prettier-plugin-wolfram 0.7.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/LICENSE +7 -0
- package/README.md +290 -0
- package/bin/prettier-wolfram.js +55 -0
- package/package.json +58 -0
- package/src/index.js +80 -0
- package/src/options.js +206 -0
- package/src/parser/adapter.js +690 -0
- package/src/parser/cstEqual.js +18 -0
- package/src/parser/index.js +29 -0
- package/src/parser/operators.js +35 -0
- package/src/parser/position.js +62 -0
- package/src/parser/tree-sitter-wolfram.wasm +0 -0
- package/src/range.js +98 -0
- package/src/rules/index.js +57 -0
- package/src/rules/line-width.js +129 -0
- package/src/rules/newlines-between-definitions.js +103 -0
- package/src/rules/no-bare-symbol-set.js +19 -0
- package/src/rules/no-dynamic-module-leak.js +74 -0
- package/src/rules/no-general-infix-function.js +52 -0
- package/src/rules/no-shadowed-pattern.js +71 -0
- package/src/rules/no-unused-module-var.js +84 -0
- package/src/rules/prefer-rule-delayed.js +59 -0
- package/src/rules/spacing-commas.js +64 -0
- package/src/rules/spacing-operators.js +87 -0
- package/src/translator/commentSpacing.js +51 -0
- package/src/translator/docComments.js +89 -0
- package/src/translator/index.js +98 -0
- package/src/translator/nodes/binary.js +205 -0
- package/src/translator/nodes/call.js +254 -0
- package/src/translator/nodes/compound.js +117 -0
- package/src/translator/nodes/container.js +194 -0
- package/src/translator/nodes/group.js +159 -0
- package/src/translator/nodes/infix.js +408 -0
- package/src/translator/nodes/leaf.js +605 -0
- package/src/translator/nodes/postfix.js +29 -0
- package/src/translator/nodes/prefix.js +27 -0
- package/src/translator/nodes/ternary.js +82 -0
- package/src/translator/ruleAlignment.js +133 -0
- package/src/translator/sourceLines.js +49 -0
- package/src/translator/sourcePreservation.js +22 -0
- package/src/translator/specialForms.js +665 -0
- package/src/utils/codeSpacing.js +420 -0
- package/src/utils/cstErrors.js +36 -0
- package/src/utils/offsets.js +132 -0
- package/src/utils/operatorSpacing.js +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2026 Antonis Aristeidou
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="vscode-extension/assets/icon.png" width="96" height="96" alt="@wrel/prettier-plugin-wolfram logo">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Wolfram Prettier Plugin — @wrel/prettier-plugin-wolfram</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Prettier formatting for Wolfram Language, powered by tree-sitter.</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="#install">Install</a> ·
|
|
13
|
+
<a href="#cli-usage">CLI</a> ·
|
|
14
|
+
<a href="#prettier-configuration">Configuration</a> ·
|
|
15
|
+
<a href="#vs-code-extension">VS Code</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
The plugin parses Wolfram Language through a bundled tree-sitter WebAssembly
|
|
19
|
+
grammar and prints the result with Prettier. It supports `.wl`, `.wls`, `.wlt`,
|
|
20
|
+
`.mt`, and `.m` files. No Wolfram Engine or local kernel installation is required.
|
|
21
|
+
|
|
22
|
+
Not affiliated with the original prettier extension.
|
|
23
|
+
|
|
24
|
+
## At A Glance
|
|
25
|
+
|
|
26
|
+
| Need | What this package provides |
|
|
27
|
+
| ------------------- | -------------------------------------------------------------------------------- |
|
|
28
|
+
| Prettier formatting | A Wolfram parser and printer for Prettier 3 projects. |
|
|
29
|
+
| Editor support | A bundled VS Code extension with document, range, and format-on-save workflows. |
|
|
30
|
+
| Diagnostics | Formatter-backed rule findings, line-width hints, and fixable style diffs. |
|
|
31
|
+
| Zero dependencies | Parsing via a bundled tree-sitter WASM grammar; no Wolfram Engine required. |
|
|
32
|
+
|
|
33
|
+
## Requirements
|
|
34
|
+
|
|
35
|
+
- Node.js
|
|
36
|
+
- Prettier 3.x
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
Install Prettier and the plugin in the project that contains your Wolfram
|
|
41
|
+
source:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install --save-dev prettier @wrel/prettier-plugin-wolfram
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Add the plugin to your Prettier configuration for CLI use:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"plugins": ["@wrel/prettier-plugin-wolfram"]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## CLI Usage
|
|
56
|
+
|
|
57
|
+
Format a file to stdout:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx prettier --plugin @wrel/prettier-plugin-wolfram --parser wolfram file.wl
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Write changes back:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx prettier --plugin @wrel/prettier-plugin-wolfram --parser wolfram --write file.wl
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Check whether files would change:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx prettier --plugin @wrel/prettier-plugin-wolfram --parser wolfram --check "src/**/*.wl"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Format a byte range with Prettier's standard range flags:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx prettier --plugin @wrel/prettier-plugin-wolfram --parser wolfram --range-start 0 --range-end 200 file.wl
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Range formatting expands to the top-level Wolfram expressions touched by the
|
|
82
|
+
range. This avoids formatting incomplete fragments that the parser cannot
|
|
83
|
+
parse on their own.
|
|
84
|
+
|
|
85
|
+
## Formatting Features
|
|
86
|
+
|
|
87
|
+
- Formats Wolfram calls, lists, associations, prefix, postfix, infix, binary,
|
|
88
|
+
ternary, compound, and leaf nodes produced by the tree-sitter grammar.
|
|
89
|
+
- Applies specialized layouts to configurable block-style forms such as
|
|
90
|
+
`Module`, `With`, `Block`, and `DynamicModule`.
|
|
91
|
+
- Applies condition-first layout to configurable forms such as `If` and
|
|
92
|
+
`Switch`.
|
|
93
|
+
- Applies alternating condition/body layout to configurable case forms such as
|
|
94
|
+
`Which`.
|
|
95
|
+
- Wraps long string literals and flattens nested `StringJoin[...]` calls into a
|
|
96
|
+
stable multiline `StringJoin[...]` layout when needed.
|
|
97
|
+
- Preserves leading comments, trailing comments, multiline comments, and
|
|
98
|
+
top-level comment blocks.
|
|
99
|
+
- Aligns trailing documentation comments either automatically or at a configured
|
|
100
|
+
column.
|
|
101
|
+
- Preserves ordinary blank lines up to a configured cap and controls spacing
|
|
102
|
+
between adjacent definitions, including separate `Set` and `SetDelayed`
|
|
103
|
+
definition groups.
|
|
104
|
+
- Optionally aligns `Rule` and `RuleDelayed` values in multiline argument, list,
|
|
105
|
+
and association layouts.
|
|
106
|
+
- Normalizes general infix `x ~ f ~ y` to `f[x, y]` unless the function head is
|
|
107
|
+
listed in `wolfram.preserveTildeInfixFunctions`.
|
|
108
|
+
- Leaves parse-error files and unsupported CST nodes as original source instead
|
|
109
|
+
of printing internal parser details.
|
|
110
|
+
- Produces idempotent output: a second format pass should not change the first
|
|
111
|
+
pass result.
|
|
112
|
+
|
|
113
|
+
## Prettier Configuration
|
|
114
|
+
|
|
115
|
+
Typical `.prettierrc` example:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"plugins": ["@wrel/prettier-plugin-wolfram"],
|
|
120
|
+
"printWidth": 80,
|
|
121
|
+
"tabWidth": 2,
|
|
122
|
+
"wolfram": {
|
|
123
|
+
"newlinesBetweenDefinitions": 1,
|
|
124
|
+
"newlinesBetweenSameNameDefinitions": 0,
|
|
125
|
+
"maxBlankLinesBetweenCode": 1,
|
|
126
|
+
"trailingNewline": false,
|
|
127
|
+
"spaceAfterComma": true,
|
|
128
|
+
"spaceAroundOperators": true,
|
|
129
|
+
"alignRuleValues": false,
|
|
130
|
+
"documentationCommentColumn": 0,
|
|
131
|
+
"documentationCommentPadding": 2,
|
|
132
|
+
"topLevelSpacingMode": "declarations",
|
|
133
|
+
"preserveTildeInfixFunctions": "",
|
|
134
|
+
"moduleVarsBreakThreshold": 40,
|
|
135
|
+
"conditionFirstFunctions": "If,Switch",
|
|
136
|
+
"blockStructureFunctions": "Module,With,Block,DynamicModule",
|
|
137
|
+
"caseStructureFunctions": "Which",
|
|
138
|
+
"lintRules": "{}"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Use Prettier's standard `printWidth`, `tabWidth`, `useTabs`, `endOfLine`, and
|
|
144
|
+
related options for normal Prettier behavior. The options below are specific to
|
|
145
|
+
this plugin.
|
|
146
|
+
|
|
147
|
+
| Option | Type | Default | Description |
|
|
148
|
+
| ----------------------------------------------------- | ----------- | ----------------------------------- | ----------- |
|
|
149
|
+
| `wolfram.newlinesBetweenDefinitions` | integer | `1` | Blank lines inserted between adjacent top-level definitions such as `Set`, `SetDelayed`, `TagSet`, `TagSetDelayed`, `UpSet`, and `UpSetDelayed`. |
|
|
150
|
+
| `wolfram.newlinesBetweenSetDefinitions` | integer | inherit | Blank lines inserted between adjacent `Set`-family definitions. |
|
|
151
|
+
| `wolfram.newlinesBetweenSetDelayedDefinitions` | integer | inherit | Blank lines inserted between adjacent `SetDelayed`-family definitions. |
|
|
152
|
+
| `wolfram.newlinesBetweenSetAndSetDelayedDefinitions` | integer | inherit | Blank lines inserted between mixed `Set`-family and `SetDelayed`-family definitions. |
|
|
153
|
+
| `wolfram.newlinesBetweenSameNameDefinitions` | integer | `0` | Blank lines inserted between adjacent definitions that belong to the same symbol. |
|
|
154
|
+
| `wolfram.maxBlankLinesBetweenCode` | integer | `1` | Maximum source blank lines preserved between non-definition code statements. |
|
|
155
|
+
| `wolfram.trailingNewline` | boolean | `false` | Emits one trailing newline at the end of non-empty formatted files. |
|
|
156
|
+
| `wolfram.spaceAfterComma` | boolean | `true` | Inserts a space after commas in argument lists, lists, and associations. |
|
|
157
|
+
| `wolfram.spaceAroundOperators` | boolean | `true` | Inserts spaces around most infix, binary, and ternary operators. Operators that are normally tight, such as `::`, `?`, and `;;`, stay tight. |
|
|
158
|
+
| `wolfram.alignRuleValues` | boolean | `false` | Vertically aligns `Rule` and `RuleDelayed` values in multiline argument, list, and association layouts. |
|
|
159
|
+
| `wolfram.documentationCommentColumn` | integer | `0` | Column for trailing documentation comments. `0` computes a column per contiguous block. |
|
|
160
|
+
| `wolfram.documentationCommentPadding` | integer | `2` | Minimum spaces between code and an aligned trailing documentation comment when the column is computed automatically. |
|
|
161
|
+
| `wolfram.topLevelSpacingMode` | string | `"declarations"` | Top-level blank-line policy. Allowed values are `declarations`, `all`, and `none`. |
|
|
162
|
+
| `wolfram.preserveTildeInfixFunctions` | string | `""` | Comma-separated function names that stay in `x ~ f ~ y` form instead of normalizing to `f[x, y]`. |
|
|
163
|
+
| `wolfram.moduleVarsBreakThreshold` | integer | `40` | Character count at which block-structure variable lists break across lines. |
|
|
164
|
+
| `wolfram.conditionFirstFunctions` | string | `"If,Switch"` | Comma-separated heads whose first argument stays on the same line as the head when it fits. |
|
|
165
|
+
| `wolfram.blockStructureFunctions` | string | `"Module,With,Block,DynamicModule"` | Comma-separated heads formatted with block-structure argument layout. |
|
|
166
|
+
| `wolfram.caseStructureFunctions` | string | `"Which"` | Comma-separated heads formatted with alternating condition/body indentation. |
|
|
167
|
+
| `wolfram.lintRules` | string | `"{}"` | JSON object string for rule-level overrides used by lint integrations, for example `{"prefer-rule-delayed":"error"}`. |
|
|
168
|
+
|
|
169
|
+
### Top-Level Spacing
|
|
170
|
+
|
|
171
|
+
`wolfram.topLevelSpacingMode` controls how the blank-line options are applied:
|
|
172
|
+
|
|
173
|
+
| Value | Behavior |
|
|
174
|
+
| -------------- | ----------- |
|
|
175
|
+
| `declarations` | Adjacent definitions use `wolfram.newlinesBetweenDefinitions` plus any configured `Set`/`SetDelayed` and same-name overrides; other top-level code preserves source blank lines up to `wolfram.maxBlankLinesBetweenCode`. |
|
|
176
|
+
| `all` | All top-level statements require at least one blank line when `wolfram.maxBlankLinesBetweenCode` allows it, while still preserving no more than the configured maximum. |
|
|
177
|
+
| `none` | Removes top-level blank lines. |
|
|
178
|
+
|
|
179
|
+
Set `wolfram.maxBlankLinesBetweenCode` to `0` to remove preserved ordinary code
|
|
180
|
+
gaps. Set `wolfram.newlinesBetweenDefinitions` to `0` to keep adjacent
|
|
181
|
+
definitions together.
|
|
182
|
+
|
|
183
|
+
The `Set`/`SetDelayed` override options inherit
|
|
184
|
+
`wolfram.newlinesBetweenDefinitions` when omitted. Same-name definition groups,
|
|
185
|
+
such as usage messages, options, attributes, and overloads for the same symbol,
|
|
186
|
+
use `wolfram.newlinesBetweenSameNameDefinitions`.
|
|
187
|
+
|
|
188
|
+
### Custom Form Layout
|
|
189
|
+
|
|
190
|
+
The layout categories are driven by comma-separated symbol lists:
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"wolfram": {
|
|
195
|
+
"conditionFirstFunctions": "If,Switch,MyConditionForm",
|
|
196
|
+
"blockStructureFunctions": "Module,With,Block,DynamicModule,MyBlock",
|
|
197
|
+
"caseStructureFunctions": "Which,MyCaseForm"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Direct comments inside a specialized call cause the formatter to fall back to
|
|
203
|
+
the generic call layout so comments stay attached to the original arguments.
|
|
204
|
+
|
|
205
|
+
## Lint CLI
|
|
206
|
+
|
|
207
|
+
The package also exposes a small rule runner:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
npx prettier-wolfram lint "src/**/*.wl"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
It prints diagnostics as:
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
path/to/file.wl:line:column: WARN [rule-name] message
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Override rule levels with `WOLFRAM_LINT_RULES`:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
WOLFRAM_LINT_RULES='{"no-bare-symbol-set":"off","prefer-rule-delayed":"error"}' \
|
|
223
|
+
npx prettier-wolfram lint "src/**/*.wl"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Rule levels are `off`, `warn`, and `error`.
|
|
227
|
+
|
|
228
|
+
| Rule | Default | Formatter-fixable | Description |
|
|
229
|
+
| ------------------------------ | ------- | ----------------- | ----------- |
|
|
230
|
+
| `line-width` | `warn` | yes | Reports lines exceeding `printWidth`, ignoring comment-only overflow. |
|
|
231
|
+
| `newlines-between-definitions` | `warn` | yes | Reports top-level blank-line spacing that differs from the configured policy. |
|
|
232
|
+
| `spacing-operators` | `warn` | yes | Reports operator spacing inconsistent with `wolfram.spaceAroundOperators`. |
|
|
233
|
+
| `spacing-commas` | `warn` | yes | Reports comma spacing inconsistent with `wolfram.spaceAfterComma`. |
|
|
234
|
+
| `no-general-infix-function` | `warn` | yes | Reports general infix `x ~ f ~ y` forms unless `f` is preserved. |
|
|
235
|
+
| `prefer-rule-delayed` | `warn` | no | Reports definitions where `SetDelayed` is safer because the right-hand side references pattern variables. |
|
|
236
|
+
| `no-bare-symbol-set` | `warn` | no | Reports top-level global symbol assignments such as `x = value`. |
|
|
237
|
+
| `no-dynamic-module-leak` | `warn` | no | Reports assignments inside `Module`, `Block`, or `DynamicModule` to symbols missing from the variable list. |
|
|
238
|
+
| `no-shadowed-pattern` | `error` | no | Reports pattern variables that shadow local variables from `Module`, `With`, or `Block`. |
|
|
239
|
+
| `no-unused-module-var` | `warn` | no | Reports unused variables declared in `Module`, `With`, `Block`, or `DynamicModule`. |
|
|
240
|
+
|
|
241
|
+
## Parse Runtime
|
|
242
|
+
|
|
243
|
+
The plugin uses a bundled tree-sitter WebAssembly grammar
|
|
244
|
+
(`src/parser/tree-sitter-wolfram.wasm`) to parse Wolfram Language. No Wolfram
|
|
245
|
+
Engine, Mathematica installation, or kernel process is required at runtime.
|
|
246
|
+
|
|
247
|
+
## VS Code Extension
|
|
248
|
+
|
|
249
|
+
Build the standalone `.vsix` that bundles Prettier and this plugin:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
npm run package:vscode:standalone
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
This writes `vscode-extension/wolfram-prettier-vscode-<version>.vsix`.
|
|
256
|
+
|
|
257
|
+
For Marketplace pre-release publishing, use the workspace-safe publish wrapper:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npm run publish:vscode:pre-release
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The extension README with editor setup, settings, diagnostics, and file
|
|
264
|
+
association behavior lives at `vscode-extension/README.md`.
|
|
265
|
+
|
|
266
|
+
## Publishing To Verdaccio
|
|
267
|
+
|
|
268
|
+
Log in:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
npm login --registry http://localhost:4873
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Preview package contents:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
npm pack --dry-run
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Publish:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npm publish --registry http://localhost:4873
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Verify:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
npm view @wrel/prettier-plugin-wolfram --registry http://localhost:4873
|
|
290
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/prettier-wolfram.js
|
|
3
|
+
// Usage: prettier-wolfram lint [options] <glob...>
|
|
4
|
+
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { globSync } from "fs";
|
|
7
|
+
import { WolframParser } from "../src/parser/index.js";
|
|
8
|
+
import { runRules } from "../src/rules/index.js";
|
|
9
|
+
import { buildOffsetTable, addOffsets } from "../src/utils/offsets.js";
|
|
10
|
+
|
|
11
|
+
const [, , command, ...args] = process.argv;
|
|
12
|
+
|
|
13
|
+
if (command !== "lint") {
|
|
14
|
+
console.error("Usage: prettier-wolfram lint <glob...>");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (args.length === 0) {
|
|
19
|
+
console.error("Error: provide at least one glob pattern");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let lintRules = {};
|
|
24
|
+
try {
|
|
25
|
+
lintRules = JSON.parse(process.env.WOLFRAM_LINT_RULES ?? "{}");
|
|
26
|
+
} catch {}
|
|
27
|
+
|
|
28
|
+
const parser = new WolframParser();
|
|
29
|
+
let totalDiagnostics = 0;
|
|
30
|
+
|
|
31
|
+
for (const pattern of args) {
|
|
32
|
+
const files = globSync(pattern, { absolute: true });
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
const source = readFileSync(file, "utf8");
|
|
35
|
+
try {
|
|
36
|
+
const cst = await parser.getCST(source);
|
|
37
|
+
const table = buildOffsetTable(source);
|
|
38
|
+
addOffsets(cst, table);
|
|
39
|
+
const diagnostics = await runRules(cst, lintRules);
|
|
40
|
+
|
|
41
|
+
for (const d of diagnostics) {
|
|
42
|
+
const line = d.node?.source?.[0]?.[0] ?? "?";
|
|
43
|
+
const col = d.node?.source?.[0]?.[1] ?? "?";
|
|
44
|
+
console.log(
|
|
45
|
+
`${file}:${line}:${col}: ${d.level.toUpperCase()} [${d.rule}] ${d.message}`,
|
|
46
|
+
);
|
|
47
|
+
totalDiagnostics++;
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error(`${file}: ERROR — ${err.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
process.exit(totalDiagnostics > 0 ? 1 : 0);
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "prettier-plugin-wolfram",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Prettier plugin for Wolfram Language using tree-sitter",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git://github.com/ToneAr/prettier-plugin-wolfram.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"prettier",
|
|
12
|
+
"prettier-plugin",
|
|
13
|
+
"wolfram",
|
|
14
|
+
"wolfram-language",
|
|
15
|
+
"mathematica",
|
|
16
|
+
"formatter"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "src/index.js",
|
|
20
|
+
"bin": {
|
|
21
|
+
"prettier-wolfram": "bin/prettier-wolfram.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin/",
|
|
25
|
+
"src/",
|
|
26
|
+
"src/parser/tree-sitter-wolfram.wasm",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"prettier": "^3.0.0"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"web-tree-sitter": "^0.25.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"prettier": "^3.4.0",
|
|
37
|
+
"vitest": "^2.0.0",
|
|
38
|
+
"node-gyp": "^10.0.0",
|
|
39
|
+
"tree-sitter-cli": "^0.25.0"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build:grammar": "node scripts/build-grammar.mjs",
|
|
43
|
+
"bump:version": "node scripts/bump-version.mjs",
|
|
44
|
+
"package:vscode": "node scripts/package-vscode-extension.mjs",
|
|
45
|
+
"package:vscode:standalone": "node scripts/package-vscode-extension.mjs",
|
|
46
|
+
"publish:vscode:standalone": "node scripts/package-vscode-extension.mjs --publish",
|
|
47
|
+
"package:vscode:pre-release": "node scripts/package-vscode-extension.mjs --pre-release",
|
|
48
|
+
"publish:vscode:pre-release": "node scripts/package-vscode-extension.mjs --pre-release --publish",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest"
|
|
51
|
+
},
|
|
52
|
+
"workspaces": [
|
|
53
|
+
"vscode-extension"
|
|
54
|
+
],
|
|
55
|
+
"engines": {
|
|
56
|
+
"vscode": "^1.105.0"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/index.js
|
|
2
|
+
import { normalizeWolframOptions, options } from "./options.js";
|
|
3
|
+
import { WolframParser } from "./parser/index.js";
|
|
4
|
+
import { printNode } from "./translator/index.js";
|
|
5
|
+
import { buildOffsetTable, addOffsets } from "./utils/offsets.js";
|
|
6
|
+
import {
|
|
7
|
+
containsCstErrors,
|
|
8
|
+
createUnformattableNode,
|
|
9
|
+
} from "./utils/cstErrors.js";
|
|
10
|
+
import { preprocessRange } from "./range.js";
|
|
11
|
+
|
|
12
|
+
const parser = new WolframParser();
|
|
13
|
+
|
|
14
|
+
function extractLeadingShebang(text) {
|
|
15
|
+
if (!text.startsWith("#!")) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const lineBreakMatch = /\r?\n/.exec(text);
|
|
20
|
+
const lineEnd = lineBreakMatch?.index ?? text.length;
|
|
21
|
+
const lineBreak = lineBreakMatch?.[0] ?? "";
|
|
22
|
+
const bodyStart = lineEnd + lineBreak.length;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
line: text.slice(0, lineEnd),
|
|
26
|
+
maskedText: " ".repeat(lineEnd) + lineBreak + text.slice(bodyStart),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const languages = [
|
|
31
|
+
{
|
|
32
|
+
name: "Wolfram Language",
|
|
33
|
+
parsers: ["wolfram"],
|
|
34
|
+
extensions: [".wl", ".wls", ".wlt", ".mt", ".m", ".vsnb", ".nb"],
|
|
35
|
+
vscodeLanguageIds: ["wolfram", "wolframscript", "wolfram-notebook"],
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export const parsers = {
|
|
40
|
+
wolfram: {
|
|
41
|
+
parse: async (text, parsedOptions) => {
|
|
42
|
+
const normalizedOptions = normalizeWolframOptions(parsedOptions);
|
|
43
|
+
const shebang = extractLeadingShebang(text);
|
|
44
|
+
const cstText = shebang?.maskedText ?? text;
|
|
45
|
+
const cst = await parser.getCST(cstText, normalizedOptions);
|
|
46
|
+
if (!cst || containsCstErrors(cst)) {
|
|
47
|
+
return createUnformattableNode(text);
|
|
48
|
+
}
|
|
49
|
+
const table = buildOffsetTable(
|
|
50
|
+
text,
|
|
51
|
+
normalizedOptions.tabWidth ?? 2,
|
|
52
|
+
);
|
|
53
|
+
const ast = addOffsets(cst, table);
|
|
54
|
+
if (shebang) ast.wlsShebang = shebang.line;
|
|
55
|
+
return ast;
|
|
56
|
+
},
|
|
57
|
+
preprocess: preprocessRange,
|
|
58
|
+
astFormat: "wolfram-cst",
|
|
59
|
+
locStart: (node) => node.locStart,
|
|
60
|
+
locEnd: (node) => node.locEnd,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const printers = {
|
|
65
|
+
"wolfram-cst": {
|
|
66
|
+
print: (path, printOptions, print) =>
|
|
67
|
+
printNode(path, normalizeWolframOptions(printOptions), print),
|
|
68
|
+
/** Let Prettier traverse all non-whitespace nodes when walking the AST
|
|
69
|
+
* to find nodes within the range. */
|
|
70
|
+
canAttachComment: (node) =>
|
|
71
|
+
node.type !== undefined &&
|
|
72
|
+
node.type !== "UnformattableNode" &&
|
|
73
|
+
!(
|
|
74
|
+
node.type === "LeafNode" &&
|
|
75
|
+
["Token`Whitespace", "Token`Newline"].includes(node.kind)
|
|
76
|
+
),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export { options };
|