Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- patch

permissions:
id-token: write
contents: write

jobs:
Expand All @@ -28,6 +29,8 @@ jobs:
with:
node-version: '24'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false
- name: install dependencies
run: npm ci
- name: git config
Expand Down
9 changes: 7 additions & 2 deletions .release-it.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
"commitMessage": "chore: release v${version}"
},
"github": {
"release": true
"release": true,
"assets": [
"jetstreamapp-soql-parser-js-${version}.tgz",
"dist/soql-parser-js-lwc-v${version}.zip",
"dist/lwc/soqlParserJs.js"
]
},
"hooks": {
"before:init": ["npm run build", "npm test"],
"after:bump": "npm run build",
"after:bump": ["npm run build", "npm pack"],
"after:release": "npm run copy-tc-to-docs && cd docs && npm install @jetstreamapp/soql-parser-js@${version} && git add package*.json && git add static/sample-queries-json.json && git commit -m \"Updated docs version\" && git push && npm run deploy"
}
}
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## 7.2.0

May 11, 2026

### LWC Distribution

The LWC build now produces two artifacts to support different deployment workflows:

- **Standalone JS file** at `dist/lwc/soqlParserJs.js` — a single bundled file that SFDX users can drop directly into their project's `lwc/soqlParserJs/` folder alongside their own `.js-meta.xml`. Also published to npm and attached to each GitHub Release.
- **Ready-to-deploy metadata package** at `dist/lwc-packaged/` — contains `package.xml`, `lwc/soqlParserJs/soqlParserJs.js`, and `soqlParserJs.js-meta.xml`. Deploy directly with `sf project deploy start --metadata-dir dist/lwc-packaged --target-org <alias>`, no SFDX project required.
- **Pre-zipped metadata package on GitHub Releases** — every release attaches `soql-parser-js-lwc-v<version>.zip` (the metadata package, pre-zipped) so users can grab a single archive, and deploy without cloning or running `npm install`.
- **Fixed LWC compiler compatibility** — lowered the LWC bundle's esbuild target to `es2020`, which down-levels ES2022 syntax (e.g. static class initialization blocks) that the Salesforce LWC compiler does not yet support.
- **Configurable Salesforce API version** — added the `salesforceApiVersion` field to `package.json` (currently `66.0`); the value is stamped into both `package.xml` and `.js-meta.xml` at build time, so bumping the API version is a one-line change.

### Release Pipeline

- **npm tarball attached to GitHub Releases** — every release now attaches `jetstreamapp-soql-parser-js-<version>.tgz`.
- **Version banner on all bundles** — `esm`, `cjs`, `cli`, and `lwc` bundles all start with a `/*! ... */` header listing the package name, version, repository URL, and license. Banner values are sourced from `package.json`, so they stay in sync automatically with each release.

## 7.1.1

Apr 25, 2026
Expand Down
78 changes: 51 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,52 +510,74 @@ WHERE Name LIKE 'a%'

## Using in LWC

The easiest way to utilize this library in LWC is to deploy the compiled code as a web component in your org.
The library can be used as a Lightning Web Component in your Salesforce org. The build produces two artifacts to support different workflows:

:warning: The minified version ends up with `$A` characters in the output, which causes the deployment to SFD to fail, so we have created an unminified version of the library just for Salesforce.
| Artifact | What it is | Best for |
| ------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `dist/lwc/soqlParserJs.js` | Standalone bundled JS file (no metadata) | SFDX projects — drop into your existing `lwc/soqlParserJs/` folder |
| `dist/lwc-packaged/` (and the release zip) | Full Salesforce metadata package: `package.xml` + `lwc/soqlParserJs/{js,js-meta.xml}` | Direct deployment to an org via `sf project deploy start` — no SFDX project required |

### Obtaining the build artifacts
The Salesforce API version used for the metadata package is configured via the `salesforceApiVersion` field in [package.json](package.json) and is applied to both `package.xml` and `soqlParserJs.js-meta.xml` at build time.

We don't store the built artifacts on github, so you will need to obtain from NPM or run the build command yourself.
### Option 1: SFDX project — drop in the standalone JS file

#### Download from NPM
If you already have an SFDX project, the easiest path is to grab the standalone `soqlParserJs.js` and place it in your project's `lwc/soqlParserJs/` folder alongside a `soqlParserJs.js-meta.xml` file you provide yourself.

Download from [npm](https://www.npmjs.com/package/@jetstreamapp/soql-parser-js)
Sources for the standalone JS:

**Either:**
- **GitHub Releases** — every release attaches `soqlParserJs.js` directly to the [Releases page](https://github.com/jetstreamapp/soql-parser-js/releases).
- **npm** — `npm install @jetstreamapp/soql-parser-js`, then copy from `node_modules/@jetstreamapp/soql-parser-js/dist/lwc/soqlParserJs.js`.
- **Local build** — clone the repo, run `npm install && npm run build:lwc`, and find the file at `dist/lwc/soqlParserJs.js`.

1. Go to the "Code Tab" on the [npm](https://www.npmjs.com/package/@jetstreamapp/soql-parser-js) listing
1. Navigate to `/dist/lwc.index.mjs`
2. Install this project in an existing node library by running `npm install @jetstreamapp/soql-parser-js`
1. then navigating to the downloaded code in this folder: `node_modules/@jetstreamapp/soql-parser-js/dist/lwc`
Your SFDX folder should look like:

#### Build the files yourself
```
force-app/main/default/lwc/soqlParserJs/
├── soqlParserJs.js <-- copied from this project
└── soqlParserJs.js-meta.xml <-- your own (example below)
```

1. Clone/download the repository from GitHub
2. Ensure you have node installed (version 22 or higher)
3. Install dependencies with `npm install`
4. Run `npm build:lwc`
5. The output will be placed in `/dist/lwc.index.mjs`
A minimal `soqlParserJs.js-meta.xml`:

### Deploying and Using in Salesforce
```xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>65.0</apiVersion>
Comment thread
paustint marked this conversation as resolved.
<isExposed>false</isExposed>
</LightningComponentBundle>
```

Copy `index.mjs` into an LWC component.
### Option 2: Direct deployment — use the pre-built metadata package

For example:
If you don't have an SFDX project, download the pre-zipped metadata package, extract, and deploy:

```bash
# Download soql-parser-js-lwc-v<version>.zip from the GitHub Releases page, then:
unzip soql-parser-js-lwc-v<version>.zip -d soql-parser-js-lwc
sf project deploy start --metadata-dir soql-parser-js-lwc --target-org <your-org-alias>
```
soqlParserJsLib
- soqlParserJsLib.js <--- copy the code here
- soqlParserJsLib.js-meta.xml

Or, if you've built locally, the equivalent directory is `dist/lwc-packaged/`:

```bash
sf project deploy start --metadata-dir dist/lwc-packaged --target-org <your-org-alias>
```

After you have deployed the LWC, you can import it just like any other LWC import.
Legacy `sfdx` CLI alternative:

```bash
sfdx force:mdapi:deploy -d <path-to-package> -w 10
```

### Using in Salesforce

The deployed component is `c/soqlParserJs`. It is intentionally a library component (`isExposed=false`), so you don't drop it on a Lightning page directly — instead, import its exports from your own LWC:

```js
import { LightningElement } from 'lwc';
import { parseQuery } from 'c/soqlParserJsLib';
import { parseQuery } from 'c/soqlParserJs';

export default class SoqlParserJs extends LightningElement {
export default class MyComponent extends LightningElement {
parsedQuery;

get parsedQueryString() {
Expand All @@ -570,12 +592,14 @@ export default class SoqlParserJs extends LightningElement {

```html
<template>
<button class="slds-button slds-button_neutral" onclick="{handleClick}">Click Me</button>
<button class="slds-button slds-button_neutral" onclick={handleClick}>Click Me</button>

<p>Parsed Query: {parsedQueryString}</p>
</template>
```

All public exports of the library (`parseQuery`, `composeQuery`, `formatQuery`, `isQueryValid`, the various utility functions, etc.) are available as named imports from `c/soqlParserJs`.

## CLI

Install globally or use `npx` to interact with the cli.
Expand Down
18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "@jetstreamapp/soql-parser-js",
"version": "7.1.1",
"salesforceApiVersion": "66.0",
"description": "Salesforce.com SOQL parser and composer",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.mjs",
Expand All @@ -15,11 +16,12 @@
"scripts": {
"clean": "rm -rf ./dist/*",
"prebuild": "npm run clean",
"build": "npm-run-all build:esm build:lwc build:cjs build:cli build:declarations",
"build:esm": "esbuild src/index.ts --bundle --outfile=dist/esm/index.mjs --minify --format=esm --target=es2022",
"build:lwc": "esbuild src/index.ts --bundle --outfile=dist/lwc/index.js --format=esm --target=es2022",
"build:cjs": "esbuild src/index.ts --bundle --outfile=dist/cjs/index.js --minify --format=cjs --target=es2022",
"build:cli": "esbuild cli/index.ts --bundle --outfile=dist/cli/index.js --minify --format=cjs --target=es2022 --platform=node",
"build": "npm-run-all build:bundles build:declarations",
"build:bundles": "node tasks/build.mjs",
"build:esm": "node tasks/build.mjs esm",
"build:lwc": "node tasks/build.mjs lwc",
"build:cjs": "node tasks/build.mjs cjs",
"build:cli": "node tasks/build.mjs cli",
"build:declarations": "tsc --project tsconfig.json",
"tsc": "tsc",
"release": "release-it",
Expand All @@ -37,7 +39,11 @@
"access": "public"
},
"files": [
"dist/**",
"dist/esm/**",
"dist/cjs/**",
"dist/cli/**",
"dist/lwc/**",
"dist/types/**",
"bin/**",
"AUTHORS.md",
"CHANGELOG.md",
Expand Down
104 changes: 104 additions & 0 deletions tasks/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { build } from 'esbuild';
import { readFileSync, writeFileSync, rmSync, mkdirSync, copyFileSync } from 'node:fs';
import { execFileSync } from 'node:child_process';

const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
const repoUrl = (pkg.repository?.url ?? '').replace(/^git\+/, '').replace(/\.git$/, '');

const banner = `/*!
* ${pkg.name} v${pkg.version}
* ${repoUrl}
* @license ${pkg.license}
*/`;

const LWC_COMPONENT_NAME = 'soqlParserJs';
const LWC_STANDALONE_DIR = 'dist/lwc';
const LWC_STANDALONE_FILE = `${LWC_STANDALONE_DIR}/${LWC_COMPONENT_NAME}.js`;
const LWC_PACKAGE_DIR = 'dist/lwc-packaged';
const LWC_PACKAGE_BUNDLE_DIR = `${LWC_PACKAGE_DIR}/lwc/${LWC_COMPONENT_NAME}`;

const targets = {
esm: {
entryPoints: ['src/index.ts'],
outfile: 'dist/esm/index.mjs',
format: 'esm',
},
lwc: {
entryPoints: ['src/index.ts'],
outfile: LWC_STANDALONE_FILE,
format: 'esm',
// LWC's compiler doesn't support certain ES2022 syntax
target: 'es2020',
},
cjs: {
entryPoints: ['src/index.ts'],
outfile: 'dist/cjs/index.js',
format: 'cjs',
},
cli: {
entryPoints: ['cli/index.ts'],
outfile: 'dist/cli/index.js',
format: 'cjs',
platform: 'node',
},
};

const requested = process.argv[2];
const names = requested ? [requested] : Object.keys(targets);

for (const name of names) {
if (!targets[name]) {
console.error(`Unknown build target: ${name}. Valid targets: ${Object.keys(targets).join(', ')}`);
process.exit(1);
}
}

await Promise.all(
names.map(async name => {
await build({
bundle: true,
target: 'es2022',
banner: { js: banner },
minify: true,
...targets[name],
});
if (name === 'lwc') {
writeLwcPackage();
}
}),
);

function writeLwcPackage() {
const apiVersion = pkg.salesforceApiVersion;
if (!apiVersion) {
throw new Error('Missing "salesforceApiVersion" in package.json — required for LWC package metadata.');
}
mkdirSync(LWC_PACKAGE_BUNDLE_DIR, { recursive: true });
copyFileSync(LWC_STANDALONE_FILE, `${LWC_PACKAGE_BUNDLE_DIR}/${LWC_COMPONENT_NAME}.js`);

const packageXml = `<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>${LWC_COMPONENT_NAME}</members>
<name>LightningComponentBundle</name>
</types>
<version>${apiVersion}</version>
</Package>
`;
const metaXml = `<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>${apiVersion}</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
`;
writeFileSync(`${LWC_PACKAGE_DIR}/package.xml`, packageXml);
writeFileSync(`${LWC_PACKAGE_BUNDLE_DIR}/${LWC_COMPONENT_NAME}.js-meta.xml`, metaXml);
writeLwcZip();
}

function writeLwcZip() {
const zipName = `soql-parser-js-lwc-v${pkg.version}.zip`;
const zipPath = `dist/${zipName}`;
rmSync(zipPath, { force: true });
execFileSync('zip', ['-r', `../${zipName}`, '.'], { cwd: LWC_PACKAGE_DIR, stdio: 'inherit' });
Comment thread
paustint marked this conversation as resolved.
}
5 changes: 5 additions & 0 deletions test/test-cases-for-is-valid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,5 +494,10 @@ WHERE
isValid: true,
},
{ testCase: 161, soql: `SELECT Name, Id FROM Contact USING SCOPE mru ORDER BY Name ASC`, isValid: true },
{ testCase: 162, soql: `SELECT Id FROM Account USING SCOPE scopingRule`, isValid: true },
{ testCase: 163, soql: `SELECT Id FROM Account USING SCOPE mine_and_my_groups`, isValid: true },
{ testCase: 164, soql: `SELECT Id FROM Account USING SCOPE my_territory`, isValid: true },
{ testCase: 165, soql: `SELECT Id FROM Account USING SCOPE my_team_territory`, isValid: true },
{ testCase: 166, soql: `SELECT Id, Name FROM Account USING SCOPE myRule`, isValid: true },
];
export default testCases;
Loading