agent-docs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/plans/OPTIMISE.md +379 -0
- package/.cursor/plans/VERSIONING.md +207 -0
- package/.cursor/rules/IMPORTANT.mdc +97 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +13 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/.github/dependabot.yml +38 -0
- package/.github/pull_request_template.md +10 -0
- package/.github/workflows/format.yml +35 -0
- package/CODE_OF_CONDUCT.md +64 -0
- package/CONTRIBUTING.md +52 -0
- package/LICENSE.md +20 -0
- package/PLAN.md +707 -0
- package/README.md +133 -0
- package/SECURITY.md +21 -0
- package/docs/APEXANNOTATIONS.md +472 -0
- package/docs/APEXDOC.md +198 -0
- package/docs/CML.md +877 -0
- package/docs/CODEANALYZER.md +435 -0
- package/docs/CONTEXTDEFINITIONS.md +617 -0
- package/docs/ESLINT.md +827 -0
- package/docs/ESLINTJSDOC.md +520 -0
- package/docs/FIELDSERVICE.md +4452 -0
- package/docs/GRAPHBINARY.md +208 -0
- package/docs/GRAPHENGINE.md +616 -0
- package/docs/GRAPHML.md +337 -0
- package/docs/GRAPHSON.md +302 -0
- package/docs/GREMLIN.md +490 -0
- package/docs/GRYO.md +232 -0
- package/docs/HUSKY.md +106 -0
- package/docs/JEST.md +387 -0
- package/docs/JORJE.md +537 -0
- package/docs/JSDOC.md +621 -0
- package/docs/PMD.md +910 -0
- package/docs/PNPM.md +409 -0
- package/docs/PRETTIER.md +716 -0
- package/docs/PRETTIERAPEX.md +874 -0
- package/docs/REVENUETRANSACTIONMANAGEMENT.md +887 -0
- package/docs/TINKERPOP.md +252 -0
- package/docs/VITEST.md +706 -0
- package/docs/VSCODE.md +231 -0
- package/docs/XPATH31.md +213 -0
- package/package.json +32 -0
- package/postinstall.mjs +51 -0
- package/prettier.config.js +18 -0
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
# Prettier Plugin Apex - AI Agent Reference
|
|
2
|
+
|
|
3
|
+
> **Version**: 1.0.0
|
|
4
|
+
|
|
5
|
+
> **Quick Info**: Prettier plugin for Apex using Jorje (Salesforce's parser).
|
|
6
|
+
> Correctness over configurability. **Source**:
|
|
7
|
+
> https://github.com/dangmai/prettier-plugin-apex
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Monorepo Structure
|
|
12
|
+
|
|
13
|
+
| Package | Purpose |
|
|
14
|
+
| -------------------------------------- | --------------------------- |
|
|
15
|
+
| `prettier-plugin-apex` | Main plugin |
|
|
16
|
+
| `apex-ast-serializer` | Java/Gradle Jorje wrapper |
|
|
17
|
+
| `playground` | Web testing interface |
|
|
18
|
+
| `@prettier-apex/apex-ast-serializer-*` | Platform-native executables |
|
|
19
|
+
|
|
20
|
+
## Core Files
|
|
21
|
+
|
|
22
|
+
| File | Role |
|
|
23
|
+
| ---------------- | ----------------------------------- |
|
|
24
|
+
| `parser.ts` | Source → Jorje AST → enriched AST |
|
|
25
|
+
| `printer.ts` | AST → Prettier Doc → formatted code |
|
|
26
|
+
| `comments.ts` | Comment attachment/handling |
|
|
27
|
+
| `util.ts` | Helpers, precedence, AST massage |
|
|
28
|
+
| `constants.ts` | Node types, operators |
|
|
29
|
+
| `pragma.ts` | `@format`/`@prettier` detection |
|
|
30
|
+
| `http-server.ts` | Standalone parser server |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Parser
|
|
35
|
+
|
|
36
|
+
### Exported Parsers
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
export const parsers = {
|
|
40
|
+
apex: {
|
|
41
|
+
astFormat: 'apex',
|
|
42
|
+
parse,
|
|
43
|
+
locStart,
|
|
44
|
+
locEnd,
|
|
45
|
+
hasPragma,
|
|
46
|
+
preprocess: (text) => text.trim(),
|
|
47
|
+
},
|
|
48
|
+
'apex-anonymous': {
|
|
49
|
+
astFormat: 'apex',
|
|
50
|
+
parse,
|
|
51
|
+
locStart,
|
|
52
|
+
locEnd,
|
|
53
|
+
hasPragma,
|
|
54
|
+
preprocess: (text) => text.trim(),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Parser Methods
|
|
60
|
+
|
|
61
|
+
| Method | Type | Description |
|
|
62
|
+
| ------------ | --------------------------------- | ---------------------------------------------------- |
|
|
63
|
+
| `parse` | `(text, options) => Promise<AST>` | **Required**. Source → enriched AST |
|
|
64
|
+
| `locStart` | `(node) => number` | **Required**. Node start index |
|
|
65
|
+
| `locEnd` | `(node) => number` | **Required**. Node end index |
|
|
66
|
+
| `hasPragma` | `(text) => boolean` | Optional. Detects `@format`/`@prettier` |
|
|
67
|
+
| `preprocess` | `(text, options) => string` | Optional. Transform before parse (default: `trim()`) |
|
|
68
|
+
|
|
69
|
+
### Parsing Modes
|
|
70
|
+
|
|
71
|
+
| Mode | Option Value | Speed | Notes |
|
|
72
|
+
| ----------- | ------------ | ------- | ---------------------------------- |
|
|
73
|
+
| Java CLI | `'none'` | Slowest | Most compatible, requires JRE ≥11 |
|
|
74
|
+
| Native | `'native'` | Fastest | Default. Falls back to Java |
|
|
75
|
+
| HTTP Server | `'built-in'` | Medium | Reuses JVM, needs separate process |
|
|
76
|
+
|
|
77
|
+
### Parse Flow
|
|
78
|
+
|
|
79
|
+
1. `preprocess` → `text.trim()`
|
|
80
|
+
2. External parse → Jorje (via Java/native/HTTP)
|
|
81
|
+
3. JSON deserialize → AST object
|
|
82
|
+
4. Error check → throw if `parseErrors.length > 0`
|
|
83
|
+
5. Comment extract → from `hiddenTokenMap`
|
|
84
|
+
6. Enrich locations → `nodeLocationVisitor`
|
|
85
|
+
7. Resolve line indices → `lineIndexVisitor`
|
|
86
|
+
8. Add metadata → `metadataVisitor`
|
|
87
|
+
|
|
88
|
+
### Location Functions
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// Access location
|
|
92
|
+
const loc = node.loc ?? node.location;
|
|
93
|
+
const start = loc.startIndex;
|
|
94
|
+
const end = loc.endIndex;
|
|
95
|
+
|
|
96
|
+
// Plugin exports
|
|
97
|
+
locStart: (node) => node.loc?.startIndex ?? node.location?.startIndex;
|
|
98
|
+
locEnd: (node) => node.loc?.endIndex ?? node.location?.endIndex;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### External Parse Functions
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Spawn (none/native mode)
|
|
105
|
+
parseTextWithSpawn(executable: string, text: string, anonymous: boolean): Promise<{stdout, stderr}>
|
|
106
|
+
// Args: anonymous ? ['-a'] : []
|
|
107
|
+
|
|
108
|
+
// HTTP (built-in mode)
|
|
109
|
+
parseTextWithHttp(text: string, host: string, port: number, protocol: string, anonymous: boolean): Promise<string>
|
|
110
|
+
// POST to ${protocol}://${host}:${port}/api/ast
|
|
111
|
+
// Body: { sourceCode: text, anonymous, prettyPrint: false }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### AST Enrichment Visitors
|
|
115
|
+
|
|
116
|
+
Applied via `dfsPostOrderApply(ast, [visitor1, visitor2, ...])` - post-order
|
|
117
|
+
DFS.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
type DfsVisitor<R, C> = {
|
|
121
|
+
accumulator?: (entry, accumulated) => R;
|
|
122
|
+
apply: (node, accumulatedResult, context, childrenContext) => R;
|
|
123
|
+
gatherChildrenContext?: (node, currentContext) => C;
|
|
124
|
+
};
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
| Visitor | Purpose |
|
|
128
|
+
| ------------------------------------------- | --------------------------------------------------------- |
|
|
129
|
+
| `nodeLocationVisitor(sourceCode, comments)` | Fix/validate node locations |
|
|
130
|
+
| `lineIndexVisitor(lineIndexes)` | Add `startLine`, `endLine`, `column` |
|
|
131
|
+
| `metadataVisitor(emptyLineLocations)` | Add `trailingEmptyLine`, `forcedHardline`, `ifBlockIndex` |
|
|
132
|
+
|
|
133
|
+
### Metadata Flags
|
|
134
|
+
|
|
135
|
+
| Flag | Purpose |
|
|
136
|
+
| ------------------- | ------------------------------ |
|
|
137
|
+
| `trailingEmptyLine` | Preserve empty line after node |
|
|
138
|
+
| `forcedHardline` | Force line breaks (SOQL/SOSL) |
|
|
139
|
+
| `ifBlockIndex` | Distinguish `if` vs `else if` |
|
|
140
|
+
| `insideParenthesis` | Flag for parameter nodes |
|
|
141
|
+
|
|
142
|
+
### Location Handlers
|
|
143
|
+
|
|
144
|
+
| Handler | Purpose |
|
|
145
|
+
| --------------------------------------- | --------------------------------- |
|
|
146
|
+
| `handleNodeSurroundedByCharacters` | Find actual `(` and `)` positions |
|
|
147
|
+
| `handleNodeEndedWithCharacter` | Extend to closing `}`, `)`, `;` |
|
|
148
|
+
| `handleWhereCompoundExpressionLocation` | SOQL WHERE clause |
|
|
149
|
+
| `handleLimitValueLocation` | SOQL LIMIT value |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Printer
|
|
154
|
+
|
|
155
|
+
### Exported Printer
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
export const printers = {
|
|
159
|
+
apex: {
|
|
160
|
+
print,
|
|
161
|
+
massageAstNode,
|
|
162
|
+
hasPrettierIgnore,
|
|
163
|
+
insertPragma,
|
|
164
|
+
isBlockComment,
|
|
165
|
+
canAttachComment,
|
|
166
|
+
printComment,
|
|
167
|
+
willPrintOwnComments,
|
|
168
|
+
handleComments: { ownLine, endOfLine, remaining },
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Printer Methods
|
|
174
|
+
|
|
175
|
+
| Method | Type | Description |
|
|
176
|
+
| ---------------------- | ---------------------------------------- | ---------------------------- |
|
|
177
|
+
| `print` | `(path, options, print, args?) => Doc` | **Required**. AST → Doc |
|
|
178
|
+
| `massageAstNode` | `(original, cloned, parent) => any` | Normalize for debug-check |
|
|
179
|
+
| `hasPrettierIgnore` | `(path) => boolean` | Check `prettier-ignore` |
|
|
180
|
+
| `insertPragma` | `(text) => string` | Insert `@format` pragma |
|
|
181
|
+
| `isBlockComment` | `(comment) => boolean` | Is `/* */` comment |
|
|
182
|
+
| `canAttachComment` | `(node, ancestors) => boolean` | Can attach comment to node |
|
|
183
|
+
| `printComment` | `(commentPath, options) => Doc` | Print comment node |
|
|
184
|
+
| `willPrintOwnComments` | `(path) => boolean` | Node prints own comments |
|
|
185
|
+
| `printPrettierIgnored` | `(path, options, print, args?) => Doc` | Format ignored regions |
|
|
186
|
+
| `embed` | `(path, options) => Fn\|Doc\|null` | Embedded language formatting |
|
|
187
|
+
| `preprocess` | `(ast, options) => ast` | Transform before printing |
|
|
188
|
+
| `getCommentChildNodes` | `(node, options) => nodes[]` | Comment attachment traversal |
|
|
189
|
+
| `getVisitorKeys` | `(node, nonTraversableKeys) => string[]` | AST traversal keys |
|
|
190
|
+
|
|
191
|
+
### Print Dispatch
|
|
192
|
+
|
|
193
|
+
1. Get `node['@class']`
|
|
194
|
+
2. Lookup in `nodeHandler` table
|
|
195
|
+
3. If not found → `getParentType()` for parent lookup
|
|
196
|
+
4. Call handler → `(path, print, options) => Doc`
|
|
197
|
+
5. Apply `handleTrailingEmptyLines()`
|
|
198
|
+
|
|
199
|
+
### Handler Types
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
type SingleNodeHandler = (
|
|
203
|
+
path: AstPath,
|
|
204
|
+
print: PrintFn,
|
|
205
|
+
options: ParserOptions,
|
|
206
|
+
) => Doc;
|
|
207
|
+
type ChildNodeHandler = (
|
|
208
|
+
childClass: string,
|
|
209
|
+
path: AstPath,
|
|
210
|
+
print: PrintFn,
|
|
211
|
+
options: ParserOptions,
|
|
212
|
+
) => Doc;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Handler Patterns
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// Passthrough
|
|
219
|
+
handlePassthroughCall('propertyDecl') // path.call(print, "propertyDecl")
|
|
220
|
+
|
|
221
|
+
// Inline
|
|
222
|
+
() => "break;"
|
|
223
|
+
(path, print) => ["throw", " ", path.call(print, "expr"), ";"]
|
|
224
|
+
|
|
225
|
+
// Child class lookup
|
|
226
|
+
(childClass: string) => MODIFIER[childClass]
|
|
227
|
+
|
|
228
|
+
// Complex
|
|
229
|
+
function handleBinaryishExpression(path, print): Doc { /* ... */ }
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Doc Builders
|
|
233
|
+
|
|
234
|
+
From Prettier: `group`, `indent`, `hardline`, `softline`, `line`, `join`,
|
|
235
|
+
`align`, `fill`, `ifBreak`
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Node Handlers Reference
|
|
240
|
+
|
|
241
|
+
### Statements
|
|
242
|
+
|
|
243
|
+
| Type | Handler |
|
|
244
|
+
| -------------------------------- | ----------------------------------------------- |
|
|
245
|
+
| `IF_ELSE_BLOCK` | `handleIfElseBlock` |
|
|
246
|
+
| `IF_BLOCK` | `handleIfBlock` |
|
|
247
|
+
| `ELSE_BLOCK` | `handleElseBlock` |
|
|
248
|
+
| `EXPRESSION_STATEMENT` | `handleExpressionStatement` |
|
|
249
|
+
| `RETURN_STATEMENT` | `handleReturnStatement` |
|
|
250
|
+
| `BREAK_STATEMENT` | `() => "break;"` |
|
|
251
|
+
| `CONTINUE_STATEMENT` | `() => "continue;"` |
|
|
252
|
+
| `THROW_STATEMENT` | `["throw", " ", path.call(print, "expr"), ";"]` |
|
|
253
|
+
| `BLOCK_STATEMENT` | `handleBlockStatement` |
|
|
254
|
+
| `VARIABLE_DECLARATION_STATEMENT` | `handlePassthroughCall("variableDecls")` |
|
|
255
|
+
| `STATEMENT` | `handleStatement` |
|
|
256
|
+
| `DML_MERGE_STATEMENT` | `handleDmlMergeStatement` |
|
|
257
|
+
|
|
258
|
+
### Loops
|
|
259
|
+
|
|
260
|
+
| Type | Handler |
|
|
261
|
+
| ---------------------- | -------------------------- |
|
|
262
|
+
| `WHILE_LOOP` | `handleWhileLoop` |
|
|
263
|
+
| `DO_LOOP` | `handleDoLoop` |
|
|
264
|
+
| `FOR_LOOP` | `handleForLoop` |
|
|
265
|
+
| `FOR_C_STYLE_CONTROL` | `handleForCStyleControl` |
|
|
266
|
+
| `FOR_ENHANCED_CONTROL` | `handleForEnhancedControl` |
|
|
267
|
+
| `FOR_INITS` | `handleForInits` |
|
|
268
|
+
| `FOR_INIT` | `handleForInit` |
|
|
269
|
+
|
|
270
|
+
### Try-Catch-Finally
|
|
271
|
+
|
|
272
|
+
| Type | Handler |
|
|
273
|
+
| ------------------------- | ---------------------------- |
|
|
274
|
+
| `TRY_CATCH_FINALLY_BLOCK` | `handleTryCatchFinallyBlock` |
|
|
275
|
+
| `CATCH_BLOCK` | `handleCatchBlock` |
|
|
276
|
+
| `FINALLY_BLOCK` | `handleFinallyBlock` |
|
|
277
|
+
|
|
278
|
+
### Switch
|
|
279
|
+
|
|
280
|
+
| Type | Handler |
|
|
281
|
+
| ------------------ | ------------------------------- |
|
|
282
|
+
| `SWITCH_STATEMENT` | `handleSwitchStatement` |
|
|
283
|
+
| `VALUE_WHEN` | `handleValueWhen` |
|
|
284
|
+
| `ELSE_WHEN` | `handleElseWhen` |
|
|
285
|
+
| `TYPE_WHEN` | `handleTypeWhen` |
|
|
286
|
+
| `ENUM_CASE` | `handleEnumCase` |
|
|
287
|
+
| `LITERAL_CASE` | `handlePassthroughCall("expr")` |
|
|
288
|
+
|
|
289
|
+
### Declarations
|
|
290
|
+
|
|
291
|
+
| Type | Handler |
|
|
292
|
+
| ----------------------- | ----------------------------------- |
|
|
293
|
+
| `CLASS_DECLARATION` | `handleClassDeclaration` |
|
|
294
|
+
| `INTERFACE_DECLARATION` | `handleInterfaceDeclaration` |
|
|
295
|
+
| `METHOD_DECLARATION` | `handleMethodDeclaration` |
|
|
296
|
+
| `VARIABLE_DECLARATION` | `handleVariableDeclaration` |
|
|
297
|
+
| `ENUM_DECLARATION` | `handleEnumDeclaration` |
|
|
298
|
+
| `PROPERTY_DECLATION` | `handlePropertyDeclaration` |
|
|
299
|
+
| `PROPERTY_GETTER` | `handlePropertyGetterSetter("get")` |
|
|
300
|
+
| `PROPERTY_SETTER` | `handlePropertyGetterSetter("set")` |
|
|
301
|
+
|
|
302
|
+
### Compilation Units
|
|
303
|
+
|
|
304
|
+
| Type | Handler |
|
|
305
|
+
| ---------------------------- | ------------------------------- |
|
|
306
|
+
| `TRIGGER_DECLARATION_UNIT` | `handleTriggerDeclarationUnit` |
|
|
307
|
+
| `CLASS_DECLARATION_UNIT` | `handlePassthroughCall("body")` |
|
|
308
|
+
| `ENUM_DECLARATION_UNIT` | `handlePassthroughCall("body")` |
|
|
309
|
+
| `INTERFACE_DECLARATION_UNIT` | `handlePassthroughCall("body")` |
|
|
310
|
+
| `ANONYMOUS_BLOCK_UNIT` | `handleAnonymousBlockUnit` |
|
|
311
|
+
|
|
312
|
+
### Block Members
|
|
313
|
+
|
|
314
|
+
| Type | Handler |
|
|
315
|
+
| ------------------------------- | ---------------------------------------- |
|
|
316
|
+
| `PROPERTY_MEMBER` | `handlePassthroughCall("propertyDecl")` |
|
|
317
|
+
| `FIELD_MEMBER` | `handlePassthroughCall("variableDecls")` |
|
|
318
|
+
| `STATEMENT_BLOCK_MEMBER` | `handleStatementBlockMember()` |
|
|
319
|
+
| `STATIC_STATEMENT_BLOCK_MEMBER` | `handleStatementBlockMember("static")` |
|
|
320
|
+
| `METHOD_MEMBER` | `handlePassthroughCall("methodDecl")` |
|
|
321
|
+
| `INNER_CLASS_MEMBER` | `handlePassthroughCall("body")` |
|
|
322
|
+
| `INNER_ENUM_MEMBER` | `handlePassthroughCall("body")` |
|
|
323
|
+
| `INNER_INTERFACE_MEMBER` | `handlePassthroughCall("body")` |
|
|
324
|
+
|
|
325
|
+
### Expressions
|
|
326
|
+
|
|
327
|
+
| Type | Handler |
|
|
328
|
+
| ----------------------------- | ------------------------------------------------ |
|
|
329
|
+
| `BINARY_EXPRESSION` | `handleBinaryishExpression` |
|
|
330
|
+
| `BOOLEAN_EXPRESSION` | `handleBinaryishExpression` |
|
|
331
|
+
| `ASSIGNMENT_EXPRESSION` | `handleAssignmentExpression` |
|
|
332
|
+
| `TERNARY_EXPRESSION` | `handleTernaryExpression` |
|
|
333
|
+
| `NESTED_EXPRESSION` | `handleNestedExpression` |
|
|
334
|
+
| `VARIABLE_EXPRESSION` | `handleVariableExpression` |
|
|
335
|
+
| `JAVA_VARIABLE_EXPRESSION` | `handleJavaVariableExpression` |
|
|
336
|
+
| `LITERAL_EXPRESSION` | `handleLiteralExpression` |
|
|
337
|
+
| `TRIGGER_VARIABLE_EXPRESSION` | `["Trigger", ".", path.call(print, "variable")]` |
|
|
338
|
+
| `THIS_VARIABLE_EXPRESSION` | `() => "this"` |
|
|
339
|
+
| `SUPER_VARIABLE_EXPRESSION` | `() => "super"` |
|
|
340
|
+
| `POSTFIX_EXPRESSION` | `handlePostfixExpression` |
|
|
341
|
+
| `PREFIX_EXPRESSION` | `handlePrefixExpression` |
|
|
342
|
+
| `CAST_EXPRESSION` | `handleCastExpression` |
|
|
343
|
+
| `INSTANCE_OF_EXPRESSION` | `handleInstanceOfExpression` |
|
|
344
|
+
| `PACKAGE_VERSION_EXPRESSION` | `handlePackageVersionExpression` |
|
|
345
|
+
| `ARRAY_EXPRESSION` | `handleArrayExpression` |
|
|
346
|
+
| `CLASS_REF_EXPRESSION` | `[path.call(print, "type"), ".", "class"]` |
|
|
347
|
+
| `NULL_COALESCING_EXPRESSION` | `handleNullCoalescingExpression` |
|
|
348
|
+
|
|
349
|
+
### Method Calls
|
|
350
|
+
|
|
351
|
+
| Type | Handler |
|
|
352
|
+
| ------------------------------ | --------------------------------- |
|
|
353
|
+
| `METHOD_CALL_EXPRESSION` | `handleMethodCallExpression` |
|
|
354
|
+
| `JAVA_METHOD_CALL_EXPRESSION` | `handleJavaMethodCallExpression` |
|
|
355
|
+
| `SUPER_METHOD_CALL_EXPRESSION` | `handleSuperMethodCallExpression` |
|
|
356
|
+
| `THIS_METHOD_CALL_EXPRESSION` | `handleThisMethodCallExpression` |
|
|
357
|
+
| `NEW_EXPRESSION` | `handleNewExpression` |
|
|
358
|
+
| `NEW_LIST_INIT` | `handleNewListInit` |
|
|
359
|
+
| `NEW_MAP_INIT` | `handleNewMapInit` |
|
|
360
|
+
| `NEW_SET_INIT` | `handleNewSetInit` |
|
|
361
|
+
| `NEW_LIST_LITERAL` | `handleNewListLiteral` |
|
|
362
|
+
| `NEW_MAP_LITERAL` | `handleNewMapLiteral` |
|
|
363
|
+
| `NEW_SET_LITERAL` | `handleNewSetLiteral` |
|
|
364
|
+
| `NEW_STANDARD` | `handleNewStandard` |
|
|
365
|
+
| `NEW_KEY_VALUE` | `handleNewKeyValue` |
|
|
366
|
+
| `SOQL_EXPRESSION` | `handleSoqlExpression` |
|
|
367
|
+
| `SOSL_EXPRESSION` | `handleSoslExpression` |
|
|
368
|
+
|
|
369
|
+
### Types
|
|
370
|
+
|
|
371
|
+
| Type | Handler |
|
|
372
|
+
| ---------------- | -------------------- |
|
|
373
|
+
| `TYPE_REF` | `handleTypeRef` |
|
|
374
|
+
| `ARRAY_TYPE_REF` | `handleArrayTypeRef` |
|
|
375
|
+
| `CLASS_TYPE_REF` | `handleClassTypeRef` |
|
|
376
|
+
|
|
377
|
+
### Annotations
|
|
378
|
+
|
|
379
|
+
| Type | Handler |
|
|
380
|
+
| ------------------------ | -------------------------- |
|
|
381
|
+
| `ANNOTATION` | `handleAnnotation` |
|
|
382
|
+
| `ANNOTATION_KEY_VALUE` | `handleAnnotationKeyValue` |
|
|
383
|
+
| `ANNOTATION_VALUE` | `handleAnnotationValue` |
|
|
384
|
+
| `ANNOTATION_TRUE_VALUE` | `() => "true"` |
|
|
385
|
+
| `ANNOTATION_FALSE_VALUE` | `() => "false"` |
|
|
386
|
+
|
|
387
|
+
### Modifiers
|
|
388
|
+
|
|
389
|
+
| Type | Handler |
|
|
390
|
+
| ---------- | -------------------------------------- |
|
|
391
|
+
| `MODIFIER` | `(childClass) => MODIFIER[childClass]` |
|
|
392
|
+
|
|
393
|
+
**Modifier constants:**
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
const MODIFIER = {
|
|
397
|
+
PUBLIC: 'public',
|
|
398
|
+
PRIVATE: 'private',
|
|
399
|
+
PROTECTED: 'protected',
|
|
400
|
+
ABSTRACT: 'abstract',
|
|
401
|
+
FINAL: 'final',
|
|
402
|
+
GLOBAL: 'global',
|
|
403
|
+
INHERITED_SHARING: 'inherited sharing',
|
|
404
|
+
OVERRIDE: 'override',
|
|
405
|
+
STATIC: 'static',
|
|
406
|
+
TEST_METHOD: 'testMethod',
|
|
407
|
+
TRANSIENT: 'transient',
|
|
408
|
+
VIRTUAL: 'virtual',
|
|
409
|
+
WEB_SERVICE: 'webService',
|
|
410
|
+
WITH_SHARING: 'with sharing',
|
|
411
|
+
WITHOUT_SHARING: 'without sharing',
|
|
412
|
+
};
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### DML
|
|
416
|
+
|
|
417
|
+
| Type | Handler |
|
|
418
|
+
| ------------------------ | -------------------------------- |
|
|
419
|
+
| `DML_INSERT_STATEMENT` | `handleDmlStatement("insert")` |
|
|
420
|
+
| `DML_UPDATE_STATEMENT` | `handleDmlStatement("update")` |
|
|
421
|
+
| `DML_UPSERT_STATEMENT` | `handleDmlUpsertStatement` |
|
|
422
|
+
| `DML_DELETE_STATEMENT` | `handleDmlStatement("delete")` |
|
|
423
|
+
| `DML_UNDELETE_STATEMENT` | `handleDmlStatement("undelete")` |
|
|
424
|
+
|
|
425
|
+
### SOQL
|
|
426
|
+
|
|
427
|
+
| Type | Handler |
|
|
428
|
+
| ----------------------------- | ----------------------------------------------------- |
|
|
429
|
+
| `QUERY` | `handleQuery` |
|
|
430
|
+
| `SELECT_COLUMN` | `handleSelectColumn` |
|
|
431
|
+
| `SELECT_INNER_QUERY` | `handleSelectInnerQuery` |
|
|
432
|
+
| `FIELD` | `handleField` |
|
|
433
|
+
| `FIELD_IDENTIFIER` | `handleFieldIdentifier` |
|
|
434
|
+
| `FROM_CLAUSE` | `handleFromClause` |
|
|
435
|
+
| `FROM_EXPRESSION` | `handleFromExpression` |
|
|
436
|
+
| `WHERE_CLAUSE` | `handleWhereClause` |
|
|
437
|
+
| `WHERE_INNER_EXPRESSION` | `handleWhereInnerExpression` |
|
|
438
|
+
| `WHERE_OPERATION_EXPRESSION` | `handleWhereOperationExpression` |
|
|
439
|
+
| `WHERE_OPERATION_EXPRESSIONS` | `handleWhereOperationExpressions` |
|
|
440
|
+
| `WHERE_COMPOUND_EXPRESSION` | `handleWhereCompoundExpression` |
|
|
441
|
+
| `WHERE_UNARY_EXPRESSION` | `handleWhereUnaryExpression` |
|
|
442
|
+
| `WHERE_DISTANCE_EXPRESSION` | `handleWhereDistanceExpression` |
|
|
443
|
+
| `ORDER_BY` | `handleOrderBy` |
|
|
444
|
+
| `ORDER_BY_VALUE` | `handleOrderByValue` |
|
|
445
|
+
| `GROUP_BY` | `handleGroupBy` |
|
|
446
|
+
| `GROUP_BY_VALUE` | `handleGroupByValue` |
|
|
447
|
+
| `GROUP_BY_TYPE` | `handleGroupByType` |
|
|
448
|
+
| `HAVING_CLAUSE` | `handleHavingClause` |
|
|
449
|
+
| `LIMIT_VALUE` | `handleLimitValue` |
|
|
450
|
+
| `OFFSET_VALUE` | `handleOffsetValue` |
|
|
451
|
+
| `WITH_VALUE` | `handleWithValue` |
|
|
452
|
+
| `WITH_DATA_CATEGORY` | `handleWithDataCategory` |
|
|
453
|
+
| `DATA_CATEGORY` | `handleDataCategory` |
|
|
454
|
+
| `DATA_CATEGORY_OPERATOR` | `(childClass) => DATA_CATEGORY_OPERATORS[childClass]` |
|
|
455
|
+
| `FOR_CLAUSE` | `handleForClause` |
|
|
456
|
+
| `UPDATE_STATS_CLAUSE` | `handleUpdateStatsClause` |
|
|
457
|
+
| `BIND_CLAUSE` | `handleBindClause` |
|
|
458
|
+
| `BIND_EXPRESSION` | `handleBindExpression` |
|
|
459
|
+
|
|
460
|
+
**SOQL Operators:**
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
const QUERY = {
|
|
464
|
+
AND: 'AND',
|
|
465
|
+
OR: 'OR',
|
|
466
|
+
NOT: 'NOT',
|
|
467
|
+
INCLUDES: 'INCLUDES',
|
|
468
|
+
EXCLUDES: 'EXCLUDES',
|
|
469
|
+
LIKE: 'LIKE',
|
|
470
|
+
IN: 'IN',
|
|
471
|
+
NOT_IN: 'NOT IN',
|
|
472
|
+
'=': '=',
|
|
473
|
+
'!=': '!=',
|
|
474
|
+
'<>': '<>',
|
|
475
|
+
'<': '<',
|
|
476
|
+
'>': '>',
|
|
477
|
+
'<=': '<=',
|
|
478
|
+
'>=': '>=',
|
|
479
|
+
ASC: 'ASC',
|
|
480
|
+
DESC: 'DESC',
|
|
481
|
+
NULLS_FIRST: 'NULLS FIRST',
|
|
482
|
+
NULLS_LAST: 'NULLS LAST',
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
const DATA_CATEGORY_OPERATORS = {
|
|
486
|
+
AT: 'AT',
|
|
487
|
+
ABOVE: 'ABOVE',
|
|
488
|
+
BELOW: 'BELOW',
|
|
489
|
+
ABOVE_OR_BELOW: 'ABOVE_OR_BELOW',
|
|
490
|
+
};
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### SOSL
|
|
494
|
+
|
|
495
|
+
| Type | Handler |
|
|
496
|
+
| ----------------------------- | --------------------------------- |
|
|
497
|
+
| `SEARCH` | `handleSearch` |
|
|
498
|
+
| `FIND_CLAUSE` | `handleFindClause` |
|
|
499
|
+
| `SEARCH_WITH_CLAUSE` | `handleSearchWithClause` |
|
|
500
|
+
| `SEARCH_WITH_CLAUSE_VALUE` | `handleSearchWithClauseValue` |
|
|
501
|
+
| `DIVISION_VALUE` | `handleDivisionValue` |
|
|
502
|
+
| `RETURNING_CLAUSE` | `handleReturningClause` |
|
|
503
|
+
| `RETURNING_EXPRESSION` | `handleReturningExpression` |
|
|
504
|
+
| `RETURNING_SELECT_EXPRESSION` | `handleReturningSelectExpression` |
|
|
505
|
+
| `SEARCH_USING_CLAUSE` | `handleSearchUsingClause` |
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Comments
|
|
510
|
+
|
|
511
|
+
### Comment Types
|
|
512
|
+
|
|
513
|
+
| Type | Detection |
|
|
514
|
+
| ------- | ---------------------------------------------- |
|
|
515
|
+
| Block | `node['@class'] === APEX_TYPES.BLOCK_COMMENT` |
|
|
516
|
+
| Inline | `node['@class'] === APEX_TYPES.INLINE_COMMENT` |
|
|
517
|
+
| ApexDoc | Block comment starting with `/**` |
|
|
518
|
+
|
|
519
|
+
### Comment Handlers
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
handleComments: {
|
|
523
|
+
ownLine: (comment, text, options, ast, isLast) => boolean, // Own line
|
|
524
|
+
endOfLine: (comment, text, options, ast, isLast) => boolean, // End of line
|
|
525
|
+
remaining: (comment, text, options, ast, isLast) => boolean // Between code
|
|
526
|
+
}
|
|
527
|
+
// Return true = handled; false = let Prettier handle
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Comment Properties
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
interface AnnotatedComment {
|
|
534
|
+
value: string; // Comment text
|
|
535
|
+
location: { startIndex; endIndex };
|
|
536
|
+
trailing?: boolean; // After code
|
|
537
|
+
leading?: boolean; // Before code
|
|
538
|
+
printed?: boolean; // Already printed
|
|
539
|
+
enclosingNode?: any; // Containing node
|
|
540
|
+
followingNode?: any; // Next node
|
|
541
|
+
precedingNode?: any; // Previous node
|
|
542
|
+
placement?: string; // "ownLine" | "endOfLine" | "remaining"
|
|
543
|
+
trailingEmptyLine?: boolean; // Preserve empty line after
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Prettier-Ignore
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
// Detection: exact match "prettier-ignore"
|
|
551
|
+
// Formats: // prettier-ignore OR /* prettier-ignore */
|
|
552
|
+
hasPrettierIgnore: (path) => {
|
|
553
|
+
const comment = path.getValue()?.comments?.find((c) => isPrettierIgnore(c));
|
|
554
|
+
return !!comment;
|
|
555
|
+
};
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Comment Attachment Constants
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
const ALLOW_DANGLING_COMMENTS = [BLOCK_STATEMENT, CLASS_DECLARATION, INTERFACE_DECLARATION, ENUM_DECLARATION, ...];
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Special Comment Cases
|
|
565
|
+
|
|
566
|
+
| Case | Handler | Behavior |
|
|
567
|
+
| -------------- | ---------------------------------------------------- | ---------------------------- |
|
|
568
|
+
| Dangling | `handleDanglingComment` | Empty block comments |
|
|
569
|
+
| Block leading | `handleBlockStatementLeadingComment` | Move before `{` inside |
|
|
570
|
+
| Method chain | `handleLongChainComment` | Move to trailing of previous |
|
|
571
|
+
| Binary expr | `handleBinaryishExpressionRightChildTrailingComment` | Attach to right child |
|
|
572
|
+
| Continue/Break | `handleContinueBreakDanglingComment` | Move to trailing |
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Options
|
|
577
|
+
|
|
578
|
+
### Apex-Specific Options
|
|
579
|
+
|
|
580
|
+
| Option | Type | Default | Description |
|
|
581
|
+
| ------------------------ | ------------------------------ | ------------- | ----------------- |
|
|
582
|
+
| `apexStandaloneParser` | `'none'\|'native'\|'built-in'` | `'native'` | Parser mode |
|
|
583
|
+
| `apexStandaloneHost` | `string` | `'localhost'` | HTTP server host |
|
|
584
|
+
| `apexStandalonePort` | `number` | `2117` | HTTP server port |
|
|
585
|
+
| `apexStandaloneProtocol` | `'http'\|'https'` | `'http'` | HTTP protocol |
|
|
586
|
+
| `apexInsertFinalNewline` | `boolean` | `true` | Add final newline |
|
|
587
|
+
|
|
588
|
+
### Standard Prettier Options (Apex-Relevant)
|
|
589
|
+
|
|
590
|
+
| Option | Type | Default | Description |
|
|
591
|
+
| --------------- | --------- | ------- | ----------------------- |
|
|
592
|
+
| `printWidth` | `number` | `80` | Line wrap width |
|
|
593
|
+
| `tabWidth` | `number` | `4` | Tab spaces |
|
|
594
|
+
| `useTabs` | `boolean` | `false` | Use tabs |
|
|
595
|
+
| `requirePragma` | `boolean` | `false` | Only format with pragma |
|
|
596
|
+
| `insertPragma` | `boolean` | `false` | Add pragma to output |
|
|
597
|
+
|
|
598
|
+
### Options Definition
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
export const options: SupportOptions = {
|
|
602
|
+
apexStandaloneParser: {
|
|
603
|
+
type: 'choice',
|
|
604
|
+
category: 'apex',
|
|
605
|
+
default: 'native',
|
|
606
|
+
choices: [
|
|
607
|
+
{ value: 'none', description: 'Java CLI' },
|
|
608
|
+
{ value: 'native', description: 'Native executables' },
|
|
609
|
+
{ value: 'built-in', description: 'HTTP server' },
|
|
610
|
+
],
|
|
611
|
+
description: 'Parser mode',
|
|
612
|
+
},
|
|
613
|
+
// ...
|
|
614
|
+
};
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## Constants
|
|
620
|
+
|
|
621
|
+
### APEX_TYPES
|
|
622
|
+
|
|
623
|
+
Node type constants mapping `@class` strings. Pattern: `apex.jorje.data.ast.*`
|
|
624
|
+
or `apex.jorje.parser.impl.*`
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
// Example entries
|
|
628
|
+
APEX_TYPES.CLASS_DECLARATION = 'apex.jorje.data.ast.ClassDecl';
|
|
629
|
+
APEX_TYPES.METHOD_DECLARATION = 'apex.jorje.data.ast.MethodDecl';
|
|
630
|
+
APEX_TYPES.BINARY_EXPRESSION = 'apex.jorje.data.ast.BinaryExpr';
|
|
631
|
+
// ... 140+ types
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**Parent type lookup**: Split on `$` (e.g., `Modifier$Annotation` → parent
|
|
635
|
+
`Modifier`)
|
|
636
|
+
|
|
637
|
+
### Operator Constants
|
|
638
|
+
|
|
639
|
+
```typescript
|
|
640
|
+
const BINARY = { ADDITION: '+', SUBTRACTION: '-', MULTIPLICATION: '*', DIVISION: '/', ... };
|
|
641
|
+
const BOOLEAN = { DOUBLE_EQUAL: '==', TRIPLE_EQUAL: '===', NOT_EQUAL: '!=', ... };
|
|
642
|
+
const ASSIGNMENT = { EQUALS: '=', ADDITION_EQUALS: '+=', SUBTRACTION_EQUALS: '-=', ... };
|
|
643
|
+
const PREFIX = { NEGATIVE: '-', POSITIVE: '+', NOT: '!', BITWISE_NOT: '~', INCREMENT: '++', DECREMENT: '--' };
|
|
644
|
+
const POSTFIX = { INCREMENT: '++', DECREMENT: '--' };
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Precedence (Apex-specific)
|
|
648
|
+
|
|
649
|
+
```
|
|
650
|
+
1. || (lowest)
|
|
651
|
+
2. &&
|
|
652
|
+
3. | ^ &
|
|
653
|
+
4. == === != !== <> < > <= >= (SAME tier in Apex!)
|
|
654
|
+
5. >> << >>>
|
|
655
|
+
6. + -
|
|
656
|
+
7. * / % (highest)
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Metadata Arrays
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
const ALLOW_TRAILING_EMPTY_LINE = [CLASS_DECLARATION, METHOD_DECLARATION, ...];
|
|
663
|
+
const ALLOW_DANGLING_COMMENTS = [BLOCK_STATEMENT, CLASS_DECLARATION, ...];
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
## Utilities
|
|
669
|
+
|
|
670
|
+
### Key Functions
|
|
671
|
+
|
|
672
|
+
| Function | Purpose |
|
|
673
|
+
| ----------------------------------------------- | ---------------------------- |
|
|
674
|
+
| `isBinaryish(node)` | Is binary/boolean expression |
|
|
675
|
+
| `isApexDocComment(comment)` | Is `/**` ApexDoc |
|
|
676
|
+
| `getPrecedence(op)` | Operator precedence level |
|
|
677
|
+
| `getParentType(className)` | Parent from `$` split |
|
|
678
|
+
| `findNextUncommentedCharacter(text, idx, char)` | Skip comments when searching |
|
|
679
|
+
| `shouldDottedExpressionBreak(path)` | Method chain breaking logic |
|
|
680
|
+
| `getEmptyLineLocations(src)` | Array of empty line numbers |
|
|
681
|
+
| `getLineIndexes(src)` | Array of line start indices |
|
|
682
|
+
|
|
683
|
+
### AST Massage (Debug-Check)
|
|
684
|
+
|
|
685
|
+
Normalizes AST for comparison:
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
massageAstNode(original, cloned, parent) {
|
|
689
|
+
// Remove: loc, comments, trailingEmptyLine, forcedHardline, etc.
|
|
690
|
+
// Normalize: scope → uppercase
|
|
691
|
+
// Flatten: WHERE compound expressions, dotted expression names
|
|
692
|
+
// Normalize: ApexDoc whitespace
|
|
693
|
+
}
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
## Plugin API
|
|
699
|
+
|
|
700
|
+
### Exported Interface
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
export default {
|
|
704
|
+
languages: [{ name: 'Apex', parsers: ['apex', 'apex-anonymous'], extensions: ['.cls', '.trigger'] }],
|
|
705
|
+
parsers: { apex, 'apex-anonymous' },
|
|
706
|
+
printers: { apex },
|
|
707
|
+
options: { apexStandaloneParser, ... },
|
|
708
|
+
defaultOptions: { tabWidth: 4 }
|
|
709
|
+
};
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
### Override Plugin
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
import originalPlugin from 'prettier-plugin-apex';
|
|
716
|
+
|
|
717
|
+
export default {
|
|
718
|
+
...originalPlugin,
|
|
719
|
+
parsers: {
|
|
720
|
+
...originalPlugin.parsers,
|
|
721
|
+
apex: {
|
|
722
|
+
...originalPlugin.parsers.apex,
|
|
723
|
+
parse: async (text, options) => {
|
|
724
|
+
/* custom */
|
|
725
|
+
},
|
|
726
|
+
preprocess: (text, options) => {
|
|
727
|
+
/* custom */
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
printers: {
|
|
732
|
+
...originalPlugin.printers,
|
|
733
|
+
apex: {
|
|
734
|
+
...originalPlugin.printers.apex,
|
|
735
|
+
print: (path, options, print) => {
|
|
736
|
+
/* custom */
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
};
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
---
|
|
744
|
+
|
|
745
|
+
## Override Points Summary
|
|
746
|
+
|
|
747
|
+
| Category | Point | Location |
|
|
748
|
+
| ------------- | ---------------------- | ----------------------------------------- |
|
|
749
|
+
| **Parser** | `parse` | `parsers.apex.parse` |
|
|
750
|
+
| | `locStart` | `parsers.apex.locStart` |
|
|
751
|
+
| | `locEnd` | `parsers.apex.locEnd` |
|
|
752
|
+
| | `hasPragma` | `parsers.apex.hasPragma` |
|
|
753
|
+
| | `preprocess` | `parsers.apex.preprocess` |
|
|
754
|
+
| **Printer** | `print` | `printers.apex.print` |
|
|
755
|
+
| | `massageAstNode` | `printers.apex.massageAstNode` |
|
|
756
|
+
| | `hasPrettierIgnore` | `printers.apex.hasPrettierIgnore` |
|
|
757
|
+
| | `insertPragma` | `printers.apex.insertPragma` |
|
|
758
|
+
| | `isBlockComment` | `printers.apex.isBlockComment` |
|
|
759
|
+
| | `canAttachComment` | `printers.apex.canAttachComment` |
|
|
760
|
+
| | `printComment` | `printers.apex.printComment` |
|
|
761
|
+
| | `willPrintOwnComments` | `printers.apex.willPrintOwnComments` |
|
|
762
|
+
| **Comments** | `ownLine` | `handleComments.ownLine` |
|
|
763
|
+
| | `endOfLine` | `handleComments.endOfLine` |
|
|
764
|
+
| | `remaining` | `handleComments.remaining` |
|
|
765
|
+
| **Location** | handlers | `parser.ts` - `locationGenerationHandler` |
|
|
766
|
+
| **Visitors** | `nodeLocationVisitor` | `parser.ts` |
|
|
767
|
+
| | `lineIndexVisitor` | `parser.ts` |
|
|
768
|
+
| | `metadataVisitor` | `parser.ts` |
|
|
769
|
+
| **Handlers** | `nodeHandler` | `printer.ts` |
|
|
770
|
+
| **Utils** | `getPrecedence` | `util.ts` |
|
|
771
|
+
| | `isBinaryish` | `util.ts` |
|
|
772
|
+
| | `isApexDocComment` | `util.ts` |
|
|
773
|
+
| **Options** | `options` | `index.ts` |
|
|
774
|
+
| | `defaultOptions` | `index.ts` |
|
|
775
|
+
| **Constants** | `APEX_TYPES` | `constants.ts` |
|
|
776
|
+
| | operators | `constants.ts` |
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## Binary Expression Handling
|
|
781
|
+
|
|
782
|
+
### Precedence Check
|
|
783
|
+
|
|
784
|
+
```typescript
|
|
785
|
+
function shouldFlatten(parent, node) {
|
|
786
|
+
const parentOp = parent.op?.['@class'];
|
|
787
|
+
const nodeOp = node.op?.['@class'];
|
|
788
|
+
return getPrecedence(parentOp) === getPrecedence(nodeOp);
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
### Grouping Logic
|
|
793
|
+
|
|
794
|
+
```typescript
|
|
795
|
+
// Same precedence: flatten
|
|
796
|
+
// Different precedence: group child
|
|
797
|
+
// Left/right asymmetry: special handling for readability
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
## SOQL/SOSL Formatting
|
|
803
|
+
|
|
804
|
+
- Preserves user line breaks via `forcedHardline`
|
|
805
|
+
- Complex WHERE clause: flattening + indentation
|
|
806
|
+
- Query literals: special string handling
|
|
807
|
+
- Order/Group by: consistent formatting
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
## CLI / Usage
|
|
812
|
+
|
|
813
|
+
```bash
|
|
814
|
+
# Format file
|
|
815
|
+
npx prettier --plugin prettier-plugin-apex --write MyClass.cls
|
|
816
|
+
|
|
817
|
+
# Check formatting
|
|
818
|
+
npx prettier --plugin prettier-plugin-apex --check MyClass.cls
|
|
819
|
+
|
|
820
|
+
# Debug output
|
|
821
|
+
npx prettier --plugin prettier-plugin-apex --debug-check MyClass.cls
|
|
822
|
+
|
|
823
|
+
# Start HTTP server (for built-in mode)
|
|
824
|
+
npx start-apex-server --host localhost --port 2117
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### Config (.prettierrc)
|
|
828
|
+
|
|
829
|
+
```json
|
|
830
|
+
{
|
|
831
|
+
"plugins": ["prettier-plugin-apex"],
|
|
832
|
+
"apexStandaloneParser": "native",
|
|
833
|
+
"apexInsertFinalNewline": true,
|
|
834
|
+
"printWidth": 120,
|
|
835
|
+
"tabWidth": 4
|
|
836
|
+
}
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## Best Practices
|
|
842
|
+
|
|
843
|
+
### Parser
|
|
844
|
+
|
|
845
|
+
1. Preserve AST structure
|
|
846
|
+
2. Throw descriptive errors
|
|
847
|
+
3. Ensure location accuracy
|
|
848
|
+
4. Use native executables when possible
|
|
849
|
+
5. Test with `--debug-check`
|
|
850
|
+
|
|
851
|
+
### Printer
|
|
852
|
+
|
|
853
|
+
1. Use Doc builders correctly
|
|
854
|
+
2. Handle precedence/parentheses
|
|
855
|
+
3. Preserve comments
|
|
856
|
+
4. Apply trailing empty lines
|
|
857
|
+
|
|
858
|
+
### Overrides
|
|
859
|
+
|
|
860
|
+
1. Call original functions unless replacing
|
|
861
|
+
2. Maintain TypeScript types
|
|
862
|
+
3. Preserve error handling
|
|
863
|
+
4. Test with `--debug-check`
|
|
864
|
+
5. Document changes
|
|
865
|
+
6. Consider version compatibility
|
|
866
|
+
|
|
867
|
+
---
|
|
868
|
+
|
|
869
|
+
## Related Docs
|
|
870
|
+
|
|
871
|
+
- `docs/JORJE.md` - Jorje AST details
|
|
872
|
+
- `docs/PRETTIER.md` - Prettier architecture
|
|
873
|
+
- `docs/ESLINT.md` - ESLint reference
|
|
874
|
+
- `docs/VITEST.md` - Vitest testing
|