Skip to content

feat: Replace formulon with sf-formula-parser for formula evaluation#1607

Open
paustint wants to merge 1 commit intomainfrom
feat/replace-formula-evaluator
Open

feat: Replace formulon with sf-formula-parser for formula evaluation#1607
paustint wants to merge 1 commit intomainfrom
feat/replace-formula-evaluator

Conversation

@paustint
Copy link
Contributor

Formulon had partial support and had a number of bugs and issues with Salesforce formulas We created a new open-source library with much better salesforce formula coverage

Copilot AI review requested due to automatic review settings March 23, 2026 01:58
@socket-security
Copy link

socket-security bot commented Mar 23, 2026

@socket-security
Copy link

socket-security bot commented Mar 23, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm entities is 91.0% likely obfuscated

Confidence: 0.91

Location: Package overview

From: ?npm/@docusaurus/preset-classic@3.9.2npm/@docusaurus/core@3.9.2npm/entities@4.5.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/entities@4.5.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm entities is 91.0% likely obfuscated

Confidence: 0.91

Location: Package overview

From: ?npm/@docusaurus/preset-classic@3.9.2npm/entities@6.0.1

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/entities@6.0.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates formula evaluation from the formulon library to the newer @jetstreamapp/sf-formula-parser, aiming to improve Salesforce formula coverage and reliability across the Formula Evaluator and formula editor workflows.

Changes:

  • Replace formulon parsing/evaluation with extractFields* + evaluateFormula from @jetstreamapp/sf-formula-parser.
  • Refactor formula context building to the new FormulaContext shape (record + globals) and update UI rendering accordingly.
  • Add Playwright E2E coverage for the formula evaluator (including globals and error cases) and supporting page object/fixture wiring.

Reviewed changes

Copilot reviewed 10 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
yarn.lock Adds @jetstreamapp/sf-formula-parser and removes formulon transitive lock entries.
package.json Swaps dependencies: adds @jetstreamapp/sf-formula-parser, removes formulon.
libs/shared/ui-core/src/formula-evaluator/formula-evaluator.utils.ts Reworks data collection to build FormulaContext (record + globals) for the new evaluator.
libs/shared/ui-core/src/formula-evaluator/FormulaEvaluatorResults.tsx Updates results rendering to show the new result + flattens FormulaContext for display; adds test ids.
libs/features/formula-evaluator/src/FormulaEvaluator.tsx Switches evaluator flow to sf-formula-parser and passes null/blank behavior via options.
libs/features/create-object-and-fields/src/CreateFieldsFormulaEditor.tsx Switches formula testing from formulon to sf-formula-parser with categorized fields + context.
libs/test/e2e-utils/src/lib/pageObjectModels/FormulaEvaluatorPage.model.ts New Playwright page object model for the Formula Evaluator.
libs/test/e2e-utils/src/index.ts Exports the new FormulaEvaluator page model.
apps/jetstream-e2e/src/tests/formula-evaluator/formula-evaluator.spec.ts New E2E test suite covering formula evaluation behavior and errors.
apps/jetstream-e2e/src/fixtures/fixtures.ts Adds formulaEvaluatorPage fixture wiring.
formulon.d.ts Removes custom typings for formulon (no longer used).
.dockerignore Removes formulon.d.ts exception (file deleted).
Comments suppressed due to low confidence (1)

libs/shared/ui-core/src/formula-evaluator/formula-evaluator.utils.ts:157

  • getFormulaData declares it can return { type: 'error' }, and callers branch on response.type === 'error', but the implementation always throws in the catch block and never returns the error variant. This makes the error-handling branch unreachable and shifts expected “field error” cases into the generic exception path. Either change getFormulaData to return { type: 'error', message } for expected failures (and avoid throwing), or update the return type + callers to treat it as throwing-only.
}: FormulaDataProps | FormulaDataProvidedRecordProps): Promise<
  { type: 'error'; message: string } | { type: 'success'; context: FormulaContext; warnings: { type: string; message: string }[] }
> {
  try {
    const formulaRecord: FormulaRecord = {};
    const globals: Record<string, FormulaRecord> = {};
    const warnings: { type: string; message: string }[] = [];

    const { objectFields, globals: globalFields, customMetadata, customLabels, customSettings, customPermissions } = categorizedFields;

    const userFields = globalFields['$User'] || [];
    const organizationFields = globalFields['$Organization'] || [];
    const profileFields = globalFields['$Profile'] || [];
    const userRoleFields = globalFields['$UserRole'] || [];
    const apiFields = globalFields['$Api'] || [];
    const systemFields = globalFields['$System'] || [];

    if (type === 'QUERY_RECORD' && recordId) {
      await collectBaseQueriedRecordFields({ selectedOrg, fields: objectFields, recordId, sobjectName, output: formulaRecord });
    } else {
      collectBaseRecordFields({ fields: objectFields, manualRecord: record || {}, output: formulaRecord });
    }

    collectApiFields({ selectedOrg, fields: apiFields, globals });
    await collectCustomMetadata({ selectedOrg, fields: customMetadata, globals });
    await collectCustomSettingFields({ selectedOrg, selectedUserId, fields: customSettings, globals });
    await collectCustomPermissions({ selectedOrg, selectedUserId, fields: customPermissions, globals });
    await collectLabels({ selectedOrg, fields: customLabels, globals });
    await collectOrganizationFields({ selectedOrg, fields: organizationFields, globals });
    await collectUserProfileAndRoleFields({
      selectedOrg,
      selectedUserId,
      userFields,
      profileFields,
      roleFields: userRoleFields,
      globals,
    });
    collectSystemFields({ fields: systemFields, globals });

    const context: FormulaContext = { record: formulaRecord };
    if (Object.keys(globals).length) {
      context.globals = globals;
    }

    logger.log({ context, warnings });

    return { type: 'success', context, warnings };
  } catch (ex) {
    logger.error(ex);
    throw ex;
  }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Formulon had partial support and had a number of bugs and issues with Salesforce formulas
We created a new open-source library with much better salesforce formula coverage
@paustint paustint force-pushed the feat/replace-formula-evaluator branch from 4f11cda to 8b94314 Compare March 23, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants