@mnemonik/shared 6.50.0 → 7.2.2
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/dist/ast/astChunker.d.ts +124 -0
- package/dist/ast/astChunker.d.ts.map +1 -0
- package/dist/ast/astChunker.js +559 -0
- package/dist/ast/astChunker.js.map +1 -0
- package/dist/ast/grammars.d.ts +170 -0
- package/dist/ast/grammars.d.ts.map +1 -0
- package/dist/ast/grammars.js +411 -0
- package/dist/ast/grammars.js.map +1 -0
- package/dist/codeScanner.d.ts +59 -0
- package/dist/codeScanner.d.ts.map +1 -1
- package/dist/codeScanner.js +259 -2
- package/dist/codeScanner.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/queries/bash.tags.scm +7 -0
- package/queries/groovy.tags.scm +15 -0
- package/queries/powershell.tags.scm +14 -0
- package/scripts/vendor-grammars.ts +317 -0
- package/src/ast/astChunker.ts +661 -0
- package/src/ast/grammars.ts +490 -0
- package/src/codeScanner.ts +273 -3
- package/src/index.ts +22 -0
- package/wasm/bash.tags.scm +7 -0
- package/wasm/bash.wasm +0 -0
- package/wasm/c-sharp.tags.scm +23 -0
- package/wasm/c-sharp.wasm +0 -0
- package/wasm/c.tags.scm +9 -0
- package/wasm/c.wasm +0 -0
- package/wasm/cpp.tags.scm +15 -0
- package/wasm/cpp.wasm +0 -0
- package/wasm/elixir.tags.scm +54 -0
- package/wasm/elixir.wasm +0 -0
- package/wasm/go.tags.scm +42 -0
- package/wasm/go.wasm +0 -0
- package/wasm/groovy.tags.scm +15 -0
- package/wasm/groovy.wasm +0 -0
- package/wasm/java.tags.scm +20 -0
- package/wasm/java.wasm +0 -0
- package/wasm/javascript.tags.scm +99 -0
- package/wasm/javascript.wasm +0 -0
- package/wasm/php.tags.scm +40 -0
- package/wasm/php.wasm +0 -0
- package/wasm/powershell.tags.scm +14 -0
- package/wasm/powershell.wasm +0 -0
- package/wasm/python.tags.scm +14 -0
- package/wasm/python.wasm +0 -0
- package/wasm/ruby.tags.scm +64 -0
- package/wasm/ruby.wasm +0 -0
- package/wasm/rust.tags.scm +60 -0
- package/wasm/rust.wasm +0 -0
- package/wasm/scala.tags.scm +66 -0
- package/wasm/scala.wasm +0 -0
- package/wasm/solidity.tags.scm +43 -0
- package/wasm/solidity.wasm +0 -0
- package/wasm/tsx.wasm +0 -0
- package/wasm/typescript.tags.scm +23 -0
- package/wasm/typescript.wasm +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GAKnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,YAAY,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,YAAY,EACZ,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mnemonik/shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.2.2",
|
|
4
4
|
"description": "Shared constants and utilities for Mnemonik packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"author": "Anthony",
|
|
29
29
|
"license": "UNLICENSED",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"ignore": "^7.0.6"
|
|
31
|
+
"ignore": "^7.0.6",
|
|
32
|
+
"web-tree-sitter": "0.26.11"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@types/node": "^20.19.43",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
; Hand-written: tree-sitter-bash ships no queries/tags.scm.
|
|
2
|
+
;
|
|
3
|
+
; Node names verified by parsing a sample with the vendored bash.wasm rather than
|
|
4
|
+
; taken from documentation — `function_definition` carries its name in a `name`
|
|
5
|
+
; field typed `word`, covering both `foo() { }` and `function foo { }`.
|
|
6
|
+
(function_definition
|
|
7
|
+
name: (word) @name) @definition.function
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
; Hand-written: tree-sitter-groovy ships no queries/tags.scm.
|
|
2
|
+
;
|
|
3
|
+
; Node names verified against the vendored groovy.wasm. Groovy distinguishes a
|
|
4
|
+
; top-level `function_definition` from a `method_declaration` inside a
|
|
5
|
+
; `class_body`, and both name via an `identifier` field — so methods get
|
|
6
|
+
; definition.method and keep their own name, which is the defect this plan
|
|
7
|
+
; exists to fix for every language.
|
|
8
|
+
(class_declaration
|
|
9
|
+
name: (identifier) @name) @definition.class
|
|
10
|
+
|
|
11
|
+
(method_declaration
|
|
12
|
+
name: (identifier) @name) @definition.method
|
|
13
|
+
|
|
14
|
+
(function_definition
|
|
15
|
+
name: (identifier) @name) @definition.function
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
; Hand-written: tree-sitter-powershell ships no queries/tags.scm.
|
|
2
|
+
;
|
|
3
|
+
; Node names verified against the vendored powershell.wasm. PowerShell names
|
|
4
|
+
; differ from every other grammar here: a function's name node is
|
|
5
|
+
; `function_name` (not `identifier`), a class's is `simple_name`, and methods are
|
|
6
|
+
; `class_method_definition`. Guessing these from another language's convention
|
|
7
|
+
; would have produced a query that compiles and matches nothing.
|
|
8
|
+
(function_statement
|
|
9
|
+
(function_name) @name) @definition.function
|
|
10
|
+
|
|
11
|
+
(class_statement
|
|
12
|
+
(simple_name) @name) @definition.class
|
|
13
|
+
|
|
14
|
+
(class_method_definition) @definition.method
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendor tree-sitter grammar artifacts into packages/shared/wasm/.
|
|
3
|
+
*
|
|
4
|
+
* WHY `npm pack` AND NOT devDependencies. The first attempt added the grammar
|
|
5
|
+
* packages to this workspace's devDependencies and npm refused the tree:
|
|
6
|
+
* tree-sitter-groovy declares a `peerOptional` on the NATIVE tree-sitter
|
|
7
|
+
* (^0.21.1), which this design deliberately never installs. Rather than force
|
|
8
|
+
* the resolution, note that these packages have no business in the dependency
|
|
9
|
+
* graph at all — we want two files out of each of them, at build time, on our
|
|
10
|
+
* machine. `npm pack` fetches a tarball and performs NO dependency resolution,
|
|
11
|
+
* so there is no peer graph to satisfy, `npm ci` stays fast for every developer
|
|
12
|
+
* and every CI run, and nobody downloads ~283 MB of grammars to build the repo.
|
|
13
|
+
*
|
|
14
|
+
* What ships to a user: the extracted `.wasm` and `.tags.scm` files, committed
|
|
15
|
+
* here and published inside @mnemonik/shared. A user's install therefore pulls
|
|
16
|
+
* no grammar package, runs no postinstall, needs no compiler, and fetches
|
|
17
|
+
* nothing at runtime — which is the whole reason this plan chose WebAssembly
|
|
18
|
+
* over the native bindings.
|
|
19
|
+
*
|
|
20
|
+
* Run: npx tsx packages/shared/scripts/vendor-grammars.ts [--check]
|
|
21
|
+
* --check verify every manifest entry is present and non-empty; write nothing.
|
|
22
|
+
* This is what CI should run to catch a grammar that silently stopped
|
|
23
|
+
* shipping an artifact.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { execFileSync } from 'node:child_process';
|
|
27
|
+
import {
|
|
28
|
+
copyFileSync,
|
|
29
|
+
existsSync,
|
|
30
|
+
mkdirSync,
|
|
31
|
+
mkdtempSync,
|
|
32
|
+
readFileSync,
|
|
33
|
+
readdirSync,
|
|
34
|
+
rmSync,
|
|
35
|
+
statSync,
|
|
36
|
+
} from 'node:fs';
|
|
37
|
+
import { tmpdir } from 'node:os';
|
|
38
|
+
import { basename, join } from 'node:path';
|
|
39
|
+
import { fileURLToPath } from 'node:url';
|
|
40
|
+
import { Language, Parser, Query } from 'web-tree-sitter';
|
|
41
|
+
import { AST_LANGUAGE_IDS, QUERY_CHAIN, grammarArtifactBasename } from '../src/ast/grammars.js';
|
|
42
|
+
|
|
43
|
+
const WASM_DIR = fileURLToPath(new URL('../wasm/', import.meta.url));
|
|
44
|
+
/** Queries we author ourselves, for grammars whose upstream ships none. */
|
|
45
|
+
const OURS_DIR = fileURLToPath(new URL('../queries/', import.meta.url));
|
|
46
|
+
|
|
47
|
+
interface GrammarSpec {
|
|
48
|
+
/** Vendored artifact basename, and the id the registry keys on. */
|
|
49
|
+
id: string;
|
|
50
|
+
/** npm package to fetch. */
|
|
51
|
+
pkg: string;
|
|
52
|
+
/**
|
|
53
|
+
* `.wasm` basename inside the tarball when it differs from the package's own
|
|
54
|
+
* name — tree-sitter-typescript ships two, and tree-sitter-c-sharp names its
|
|
55
|
+
* file with an underscore.
|
|
56
|
+
*/
|
|
57
|
+
wasmFile?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Where the tag query comes from. 'upstream' copies queries/tags.scm out of
|
|
60
|
+
* the tarball; 'ours' copies packages/shared/queries/<id>.tags.scm, which we
|
|
61
|
+
* maintain because the grammar ships no tags.scm at all.
|
|
62
|
+
*/
|
|
63
|
+
tags: 'upstream' | 'ours' | 'inherited';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The vendored set. Deliberately explicit rather than globbed: a glob would
|
|
68
|
+
* quietly produce a smaller language set when a package changes its layout,
|
|
69
|
+
* and losing a language is exactly the silent degradation this plan exists to
|
|
70
|
+
* remove.
|
|
71
|
+
*
|
|
72
|
+
* Absent on purpose:
|
|
73
|
+
* julia, objc, haskell — the three largest grammars that ALSO ship no tag
|
|
74
|
+
* query, so each costs both its size (6.1/5.2/3.7 MB) and a hand-written
|
|
75
|
+
* query. Dropped to keep the payload under 40 MB; still indexed via the
|
|
76
|
+
* allowlist, still chunked heuristically.
|
|
77
|
+
* dart — its bundled .wasm (package v1.0.0, 2023) fails Language.load under
|
|
78
|
+
* web-tree-sitter 0.26.11 with a dylink-metadata error: the artifact
|
|
79
|
+
* predates the current wasm ABI. Presence is not loadability, which is why
|
|
80
|
+
* --check verifies both. Flutter matters, so this is worth revisiting by
|
|
81
|
+
* compiling from source with tree-sitter-cli.
|
|
82
|
+
* kotlin, swift, lua, perl, zig — bundle no .wasm, so they need a build step
|
|
83
|
+
* with tree-sitter-cli. Deferred until the grammars above are proven; they
|
|
84
|
+
* keep the heuristic chunker meanwhile.
|
|
85
|
+
* markdown — keeps chunkMarkdown. Headers already are a document's semantic
|
|
86
|
+
* unit; an AST would not improve on them.
|
|
87
|
+
*/
|
|
88
|
+
const GRAMMARS: GrammarSpec[] = [
|
|
89
|
+
{
|
|
90
|
+
id: 'typescript',
|
|
91
|
+
pkg: 'tree-sitter-typescript',
|
|
92
|
+
wasmFile: 'tree-sitter-typescript.wasm',
|
|
93
|
+
tags: 'upstream',
|
|
94
|
+
},
|
|
95
|
+
{ id: 'tsx', pkg: 'tree-sitter-typescript', wasmFile: 'tree-sitter-tsx.wasm', tags: 'inherited' },
|
|
96
|
+
{ id: 'javascript', pkg: 'tree-sitter-javascript', tags: 'upstream' },
|
|
97
|
+
{ id: 'python', pkg: 'tree-sitter-python', tags: 'upstream' },
|
|
98
|
+
{ id: 'go', pkg: 'tree-sitter-go', tags: 'upstream' },
|
|
99
|
+
{ id: 'java', pkg: 'tree-sitter-java', tags: 'upstream' },
|
|
100
|
+
{ id: 'c', pkg: 'tree-sitter-c', tags: 'upstream' },
|
|
101
|
+
{ id: 'cpp', pkg: 'tree-sitter-cpp', tags: 'upstream' },
|
|
102
|
+
{
|
|
103
|
+
id: 'c-sharp',
|
|
104
|
+
pkg: 'tree-sitter-c-sharp',
|
|
105
|
+
wasmFile: 'tree-sitter-c_sharp.wasm',
|
|
106
|
+
tags: 'upstream',
|
|
107
|
+
},
|
|
108
|
+
{ id: 'ruby', pkg: 'tree-sitter-ruby', tags: 'upstream' },
|
|
109
|
+
{ id: 'php', pkg: 'tree-sitter-php', wasmFile: 'tree-sitter-php.wasm', tags: 'upstream' },
|
|
110
|
+
{ id: 'rust', pkg: 'tree-sitter-rust', tags: 'upstream' },
|
|
111
|
+
{ id: 'scala', pkg: 'tree-sitter-scala', tags: 'upstream' },
|
|
112
|
+
{ id: 'elixir', pkg: 'tree-sitter-elixir', tags: 'upstream' },
|
|
113
|
+
{ id: 'solidity', pkg: 'tree-sitter-solidity', tags: 'upstream' },
|
|
114
|
+
{ id: 'bash', pkg: 'tree-sitter-bash', tags: 'ours' },
|
|
115
|
+
{ id: 'groovy', pkg: 'tree-sitter-groovy', tags: 'ours' },
|
|
116
|
+
{ id: 'powershell', pkg: 'tree-sitter-powershell', tags: 'ours' },
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Ordered tag-query files composing each grammar's EFFECTIVE query, keyed by
|
|
121
|
+
* VENDORED ARTIFACT BASENAME (`c-sharp`, not `csharp`) because that is what this
|
|
122
|
+
* script names files with.
|
|
123
|
+
*
|
|
124
|
+
* Derived, not declared: the chains themselves live in the runtime registry
|
|
125
|
+
* (`src/ast/grammars.ts`), which is the module that has to compose them for real
|
|
126
|
+
* work. A second hand-maintained copy here could drift from the one the scanner
|
|
127
|
+
* uses, and a drifted chain does not fail — it silently under-matches, which is
|
|
128
|
+
* the exact failure this vendoring step exists to catch. See that module for why
|
|
129
|
+
* tag queries are deltas and what composing them is worth (948 TypeScript
|
|
130
|
+
* definitions against 6,471).
|
|
131
|
+
*/
|
|
132
|
+
const CHAIN_BY_ARTIFACT: Record<string, string[]> = Object.fromEntries(
|
|
133
|
+
AST_LANGUAGE_IDS.map((id) => [
|
|
134
|
+
grammarArtifactBasename(id),
|
|
135
|
+
QUERY_CHAIN[id].map((part) => grammarArtifactBasename(part)),
|
|
136
|
+
])
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
interface Problem {
|
|
140
|
+
id: string;
|
|
141
|
+
detail: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Verify each manifest entry is present, LOADS, and compiles its composed query.
|
|
146
|
+
*
|
|
147
|
+
* Presence alone is not enough, proven here: tree-sitter-dart's bundled .wasm
|
|
148
|
+
* exists and is 741 KB, and `Language.load` rejects it under web-tree-sitter
|
|
149
|
+
* 0.26.11 because the artifact predates the current wasm ABI. A check that only
|
|
150
|
+
* stats the file would have called that grammar vendored and shipped a language
|
|
151
|
+
* that silently never parses.
|
|
152
|
+
*/
|
|
153
|
+
async function checkOnly(): Promise<Problem[]> {
|
|
154
|
+
const problems: Problem[] = [];
|
|
155
|
+
await Parser.init();
|
|
156
|
+
|
|
157
|
+
for (const spec of GRAMMARS) {
|
|
158
|
+
const wasm = join(WASM_DIR, `${spec.id}.wasm`);
|
|
159
|
+
if (!existsSync(wasm) || statSync(wasm).size === 0) {
|
|
160
|
+
problems.push({ id: spec.id, detail: `missing or empty ${spec.id}.wasm` });
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let language: Language;
|
|
165
|
+
try {
|
|
166
|
+
language = await Language.load(wasm);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
problems.push({
|
|
169
|
+
id: spec.id,
|
|
170
|
+
detail: `${spec.id}.wasm exists but Language.load rejected it (ABI mismatch?): ${
|
|
171
|
+
err instanceof Error ? err.message || err.constructor.name : String(err)
|
|
172
|
+
}`,
|
|
173
|
+
});
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const chain = CHAIN_BY_ARTIFACT[spec.id];
|
|
178
|
+
if (!chain) {
|
|
179
|
+
problems.push({
|
|
180
|
+
id: spec.id,
|
|
181
|
+
detail: `no QUERY_CHAIN entry in src/ast/grammars.ts — the grammar would load and match nothing`,
|
|
182
|
+
});
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let source = '';
|
|
187
|
+
for (const part of chain) {
|
|
188
|
+
const file = join(WASM_DIR, `${part}.tags.scm`);
|
|
189
|
+
if (!existsSync(file) || statSync(file).size === 0) {
|
|
190
|
+
problems.push({ id: spec.id, detail: `chain part missing or empty: ${part}.tags.scm` });
|
|
191
|
+
source = '';
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
source += readFileSync(file, 'utf8') + '\n';
|
|
195
|
+
}
|
|
196
|
+
if (!source) continue;
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const query = new Query(language, source);
|
|
200
|
+
const captures = query.captureNames;
|
|
201
|
+
if (!captures.some((c) => c.startsWith('definition.'))) {
|
|
202
|
+
problems.push({
|
|
203
|
+
id: spec.id,
|
|
204
|
+
detail: `composed query compiles but captures no definition.* — it would name nothing`,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} catch (err) {
|
|
208
|
+
problems.push({
|
|
209
|
+
id: spec.id,
|
|
210
|
+
detail: `composed query failed to compile: ${
|
|
211
|
+
err instanceof Error ? err.message.slice(0, 140) : String(err)
|
|
212
|
+
}`,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return problems;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function vendor(): Problem[] {
|
|
220
|
+
mkdirSync(WASM_DIR, { recursive: true });
|
|
221
|
+
const work = mkdtempSync(join(tmpdir(), 'ts-grammars-'));
|
|
222
|
+
const problems: Problem[] = [];
|
|
223
|
+
// One tarball may serve several ids (typescript + tsx), so fetch each package
|
|
224
|
+
// once and extract from the shared checkout.
|
|
225
|
+
const extracted = new Map<string, string>();
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
for (const spec of GRAMMARS) {
|
|
229
|
+
let dir = extracted.get(spec.pkg);
|
|
230
|
+
if (!dir) {
|
|
231
|
+
try {
|
|
232
|
+
const out = execFileSync(
|
|
233
|
+
'npm',
|
|
234
|
+
['pack', spec.pkg, '--silent', '--pack-destination', work],
|
|
235
|
+
{
|
|
236
|
+
cwd: work,
|
|
237
|
+
encoding: 'utf8',
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
const tarball = out.trim().split('\n').pop() ?? '';
|
|
241
|
+
dir = join(work, spec.pkg.replace(/[^a-z0-9-]/gi, '_'));
|
|
242
|
+
mkdirSync(dir, { recursive: true });
|
|
243
|
+
execFileSync('tar', [
|
|
244
|
+
'xzf',
|
|
245
|
+
join(work, basename(tarball)),
|
|
246
|
+
'-C',
|
|
247
|
+
dir,
|
|
248
|
+
'--strip-components=1',
|
|
249
|
+
]);
|
|
250
|
+
extracted.set(spec.pkg, dir);
|
|
251
|
+
} catch (err) {
|
|
252
|
+
problems.push({
|
|
253
|
+
id: spec.id,
|
|
254
|
+
detail: `npm pack/extract failed for ${spec.pkg}: ${err instanceof Error ? err.message.slice(0, 160) : err}`,
|
|
255
|
+
});
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const wasmName =
|
|
261
|
+
spec.wasmFile ?? readdirSync(dir).find((f) => f.endsWith('.wasm')) ?? `${spec.pkg}.wasm`;
|
|
262
|
+
const wasmSrc = join(dir, wasmName);
|
|
263
|
+
if (!existsSync(wasmSrc)) {
|
|
264
|
+
problems.push({ id: spec.id, detail: `${spec.pkg} ships no ${wasmName}` });
|
|
265
|
+
} else {
|
|
266
|
+
copyFileSync(wasmSrc, join(WASM_DIR, `${spec.id}.wasm`));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (spec.tags === 'upstream') {
|
|
270
|
+
const tagsSrc = join(dir, 'queries', 'tags.scm');
|
|
271
|
+
if (!existsSync(tagsSrc)) {
|
|
272
|
+
problems.push({
|
|
273
|
+
id: spec.id,
|
|
274
|
+
detail: `${spec.pkg} ships no queries/tags.scm — reclassify this entry as 'ours' and author one`,
|
|
275
|
+
});
|
|
276
|
+
} else {
|
|
277
|
+
copyFileSync(tagsSrc, join(WASM_DIR, `${spec.id}.tags.scm`));
|
|
278
|
+
}
|
|
279
|
+
} else if (spec.tags === 'ours') {
|
|
280
|
+
const ourSrc = join(OURS_DIR, `${spec.id}.tags.scm`);
|
|
281
|
+
if (!existsSync(ourSrc)) {
|
|
282
|
+
problems.push({
|
|
283
|
+
id: spec.id,
|
|
284
|
+
detail: `no hand-written query at packages/shared/queries/${spec.id}.tags.scm`,
|
|
285
|
+
});
|
|
286
|
+
} else {
|
|
287
|
+
copyFileSync(ourSrc, join(WASM_DIR, `${spec.id}.tags.scm`));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} finally {
|
|
292
|
+
rmSync(work, { recursive: true, force: true });
|
|
293
|
+
}
|
|
294
|
+
return problems;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const problems = process.argv.includes('--check') ? await checkOnly() : vendor();
|
|
298
|
+
|
|
299
|
+
if (problems.length > 0) {
|
|
300
|
+
// Non-zero and loud: a grammar that stops shipping an artifact must break the
|
|
301
|
+
// build, never silently remove a language from the product.
|
|
302
|
+
console.error('VENDOR_GRAMMARS_FAILED');
|
|
303
|
+
for (const p of problems) console.error(` ${p.id}: ${p.detail}`);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const sizes = GRAMMARS.map((g) => statSync(join(WASM_DIR, `${g.id}.wasm`)).size);
|
|
308
|
+
const totalMB = +(sizes.reduce((a, b) => a + b, 0) / 1048576).toFixed(1);
|
|
309
|
+
console.log(
|
|
310
|
+
`VENDOR_GRAMMARS_OK ${JSON.stringify({ grammars: GRAMMARS.length, totalWasmMB: totalMB })}`
|
|
311
|
+
);
|
|
312
|
+
// The plan's ceiling. Install size is a cost every user pays, so it fails the
|
|
313
|
+
// build rather than drifting upward one grammar at a time.
|
|
314
|
+
if (totalMB > 40) {
|
|
315
|
+
console.error(`VENDOR_GRAMMARS_TOO_LARGE ${totalMB}MB exceeds the 40MB ceiling`);
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|