Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
efae62f
feat!: switch to antlr4 runtime package
pwrightcertinia May 7, 2025
1c08daa
feat!: convert inputstream and other modules to use antlr4 runtime types
pwrightcertinia May 7, 2025
eff9422
build: use native antlr4 tool in ts build
pwrightcertinia May 7, 2025
294f3ff
build: split grammars into base and import to split options
pwrightcertinia May 8, 2025
a436e36
build: update antlr build process to match on both sides
pwrightcertinia May 8, 2025
c3d3ce7
feat!: convert ts types to use antlr4 runtime
pwrightcertinia May 8, 2025
b1c94be
test: update ts tests with type fixes and formatting
pwrightcertinia May 8, 2025
7f94688
build: update build process to allow running everything from root
pwrightcertinia May 8, 2025
42204ee
feat!: remove re-exports of antlr4 types
pwrightcertinia May 8, 2025
e1e3d60
chore: suppress javadoc output
pwrightcertinia May 8, 2025
4a6d7c2
fix: file discovery in check() and system test running
pwrightcertinia May 8, 2025
b050a0f
fix: ci script run
pwrightcertinia May 8, 2025
1247b61
build: update to node 22 and jdk 11
pwrightcertinia May 8, 2025
2361f4a
chore: update npm package configuration and dependencies
pwrightcertinia May 9, 2025
fbafa8a
chore: update eslint config
pwrightcertinia May 9, 2025
ae99e74
chore: add husky to run ts linting
pwrightcertinia May 9, 2025
de325e0
fix: prepare npm package for linting
pwrightcertinia May 9, 2025
4040213
build: configure prettier to run for both packages
pwrightcertinia May 9, 2025
7d5dcd3
chore: run prettier over code
pwrightcertinia May 9, 2025
6650386
build: update samples test version
pwrightcertinia May 9, 2025
b502f3c
test: update system test snapshots for samples 1.3.0
pwrightcertinia May 9, 2025
8cb55b6
fix: npm private registry leak
pwrightcertinia May 9, 2025
3e42649
chore: document breaking changes
pwrightcertinia May 9, 2025
5ae5c8e
doc: add prereq section to readme
pwrightcertinia May 9, 2025
7e4fef4
doc: update build instructions
pwrightcertinia May 9, 2025
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
14 changes: 8 additions & 6 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22

- name: Set up JDK 8
- name: Set up JDK
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: 8
java-version: 11
cache: "maven"

- name: Init
run: npm run init

- name: Build & Test
run: npm run build

Expand All @@ -35,11 +38,10 @@ jobs:
submodules: recursive
repository: apex-dev-tools/apex-samples
path: apex-samples
ref: v1.2.0
ref: v1.3.0

- name: Set samples env
run: echo "SAMPLES=$GITHUB_WORKSPACE/apex-samples" >> "$GITHUB_ENV"

- name: System Test
run: npm run test-samples
working-directory: npm
run: npm run systest
6 changes: 3 additions & 3 deletions .github/workflows/PublishMaven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22

- name: Set up Maven Central Repository
uses: actions/setup-java@v4
with:
java-version: "8"
java-version: 11
distribution: "temurin"
cache: "maven"
server-id: ossrh
Expand All @@ -30,7 +30,7 @@ jobs:

- name: Publish package
run: |
npm run init-jvm
npm run init:jvm
cd jvm
mvn --batch-mode deploy
env:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/PublishNPM.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
registry-url: "https://registry.npmjs.org"

- name: Publish package
run: |
npm run build-npm
npm run init:npm
npm run build:npm
cd npm
npm publish --access public
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.metals/
.vscode/
node_modules/
1 change: 1 addition & 0 deletions .husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Override user private registry back to default
registry=https://registry.npmjs.org
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# apex-parser - Changelog

## 5.0.0

- (BREAKING) Migrated from `antlr4ts` to official `antlr4` runtime package.
- Some lesser used methods are missing in the type definitions, refer to the [antlr4 Javascript code](https://github.com/antlr/antlr4/tree/dev/runtime/JavaScript/src/antlr4) if you need to cast types.
- `extends` is now required to use antlr `Listener`/`Visitor` types.
- Exception being to avoid the property initialisation syntax in the antlr generated types:

```apex
class MyListener extends ParseTreeListener implements ApexParserListener {
// with 'extends ApexParserListener' you must write this
enterMethodDeclaration = () => {}

// this requires 'extends ParseTreeListener implements ApexParserListener'
enterMethodDeclaration() {}
}
```

- (BREAKING) Updated output to `ES2020` and increased min node version to 16.
- (BREAKING) Updated to ANTLR `4.13.2` across both distributions. Same tool now generates both.
- (BREAKING) Re-exported antlr types removed, add `antlr4` package dep instead matching apex-parser version.
- Typescript `CaseInsensitiveInputStream` type now extends `CharStream` and can be constructed from `string`.
- Constructor passing in `Charstream` retained to match Java version.
- Removed `node-dir` dependency - replaced with node fs api.

## 4.4.0 - 2024-12-14

- Support `TimeLiteral` for `Time` fields, e.g. `WHERE TimeField__c = 01:00:00.000Z` for SOQL queries
Expand Down
101 changes: 59 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
# apex-parser

Parser for Salesforce Apex (including Triggers & inline SOQL/SOQL). This is based on an [ANTLR4](https://www.antlr.org/) grammar, see antlr/ApexParser.g4.
Parser for Salesforce Apex (including Triggers & inline SOQL/SOQL). This is based on an [ANTLR4](https://www.antlr.org/) grammar, see [`antlr/BaseApexParser.g4`](./antlr/BaseApexParser.g4).

There are two builds of the parser available, a NPM module for use with Node and a Maven package for use on JVMs.

These builds just contain the Parser & Lexer and provides no further support for analysing the generated parse trees beyond what is provided by ANTLR4.

As Apex & SOQL/SOQL are case-insenstive languages you need to use the provided CaseInsensitiveInputStream for the parser to function correctly. When parsing Apex, inline SOQL/SOSL is automtaically parsed, but you can also parse SOQL/SOQL directly. You can find some minimal examples in the test classes.
As Apex & SOQL/SOQL are case-insenstive languages you need to use the provided `CaseInsensitiveInputStream` for the parser to function correctly. When parsing Apex, inline SOQL/SOSL is automatically parsed, but you can also parse SOQL/SOQL directly. You can find some minimal examples in the test classes.

## Example

To parse a class file (NPM version):

```typescript
import { CharStreams } from "antlr4ts";
import { CommonTokenStream } from "antlr4";
import { ApexLexer, ApexParser, CaseInsensitiveInputStream } from "@apexdevtools/apex-parser";

const stream = CharStreams.fromString("public class Hello {}");
let lexer = new ApexLexer(new CaseInsensitiveInputStream(stream));
let tokens = new CommonTokenStream(lexer);
const lexer = new ApexLexer(new CaseInsensitiveInputStream("public class Hello {}"));
const tokens = new CommonTokenStream(lexer);

let parser = new ApexParser(tokens);
let context = parser.compilationUnit();
const parser = new ApexParser(tokens);
const context = parser.compilationUnit();
```

The 'context' is a CompilationUnitContext object which is the root of the parsed representation of the class. You can access the parse tree via functions on it.

## Unicode handling

Prior to 2.12.0 the use of ANTLRInputStream for reading data in CaseInsensitiveStream would result character positions being given for UTF-16. The switch to CharStream input in 2.12.0 for JVM and 2.14.0 for node results in character positions reflecting Unicode code points.

## antlr4ts versions

The npm module uses antlr4ts 0.5.0-alpha.4, this was updated from 0.5.0-alpha.3 in the 2.9.1 version. You should make
sure that if you are using a matching versions of this dependency if you use it directly. To avoid issues you can
import 'CommonTokenStream' & 'ParseTreeWalker' from 'apex-parser' instead of from antlr4ts.

```typescript
import { CommonTokenStream} from "apex-parser";
import { ParseTreeWalker } from "apex-parser";
```
The `context` is a `CompilationUnitContext` object which is the root of the parsed representation of the class. You can access the parse tree via functions on it.

## SOSL FIND quoting

Expand All @@ -48,51 +33,83 @@ SOSL FIND uses ' as a quoting character when embedded in Apex, in the API braces
Find {something} RETURNING Account
```

To parse the API format there is an alternative parser rule, soslLiteralAlt, that you can use instead of soslLiteral. See SOSLParserTest for some examples of how these differ.
To parse the API format there is an alternative parser rule, `soslLiteralAlt`, that you can use instead of `soslLiteral`. See `SOSLParserTest` for some examples of how these differ.

## Packages
## Installation

Maven
### Maven

```xml
<dependency>
<groupId>io.github.apex-dev-tools</groupId>
<artifactId>apex-parser</artifactId>
<version>4.4.0</version>
<version><!-- version --></version>
</dependency>
```

NPM
### NPM

```json
{
"@apexdevtools/apex-parser": "^4.4.0"
}
```sh
# install antlr4 to reference runtime types
# must match version used by parser
npm i antlr4 @apexdevtools/apex-parser
```

## Building
## Development

### Prerequisites

- JDK 11+ (for ANTLR tool)
- Maven
- NodeJS LTS

To build both distributions:
### Building

The outer package contains scripts to build both distributions:

```shell
# Run once - installs deps
npm run init

# Build & test distributions
npm run build
```

## Testing
### Testing

#### Unit Tests

Unit tests are executed during the respective package builds. The system tests require both packages to be built, as the js test also spawns the jar version. They use a collection of sample projects located in the [apex-samples](https://github.com/apex-dev-tools/apex-samples) repository. Follow the README instructions in apex-samples to checkout the submodules. To run the tests:
Options for testing:

```shell
# From root, build & test each
npm run build:npm
npm run build:jvm

# From ./npm
npm run build
npm test

# From ./jvm
mvn test
```

#### System Tests

The system tests use a collection of sample projects located in the [`apex-samples`](https://github.com/apex-dev-tools/apex-samples) repository. Follow the README instructions in `apex-samples` to checkout the submodules at the version tag used by the [build workflow](.github/workflows/Build.yml). Both packages must be built beforehand, as the js system test spawns the jar as well.

To run the tests:

```shell
# Set SAMPLES env var to samples repo location
export SAMPLES=<abs path to apex-samples>

# Exec test script
npm run test-samples
# From root dir
npm run build
npm run systest
```

System test failures relating to the snapshots may highlight regressions. Though if an error is expected or the samples have changed, instead use `npm run test-snapshot` to update the snapshots, then commit the changes.

The tag version of apex-samples used by builds is set in the [build file](.github/workflows/Build.yml).
System test failures relating to the snapshots may highlight regressions. Though if an error is expected or the samples have changed, instead use `npm run systest:update` to update the snapshots, then commit the changes.

## Source & Licenses

Expand Down
4 changes: 0 additions & 4 deletions antlr/ApexLexer.g4 → antlr/BaseApexLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@
*/
lexer grammar ApexLexer;

@lexer::members {
public void clearCache() {_interp.clearDFA();}
}

channels {
WHITESPACE_CHANNEL,
COMMENT_CHANNEL
Expand Down
5 changes: 0 additions & 5 deletions antlr/ApexParser.g4 → antlr/BaseApexParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@
* $ grun Apexcode compilationUnit *.cls
*/
parser grammar ApexParser;
options {tokenVocab=ApexLexer;}

@parser::members {
public void clearCache() {_interp.clearDFA();}
}

// entry point for Apex trigger files
triggerUnit
Expand Down
3 changes: 3 additions & 0 deletions jvm/.lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"*.java": "prettier --write"
}
3 changes: 3 additions & 0 deletions jvm/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["prettier-plugin-java"]
}
7 changes: 7 additions & 0 deletions jvm/antlr/ApexLexer.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lexer grammar ApexLexer;

@lexer::members {
public void clearCache() {_interp.clearDFA();}
}

import BaseApexLexer;
8 changes: 8 additions & 0 deletions jvm/antlr/ApexParser.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
parser grammar ApexParser;
options {tokenVocab=ApexLexer;}

@parser::members {
public void clearCache() {_interp.clearDFA();}
}

import BaseApexParser;
Loading