@hydranium/cli 1.0.0-next.10
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 +21 -0
- package/README.md +240 -0
- package/heap-analysis/analyze-heap.mjs +798 -0
- package/heap-analysis/heap/core/aggregate.mjs +152 -0
- package/heap-analysis/heap/core/bucket-label.mjs +23 -0
- package/heap-analysis/heap/core/cutpoints.mjs +51 -0
- package/heap-analysis/heap/core/diff.mjs +56 -0
- package/heap-analysis/heap/core/format.mjs +47 -0
- package/heap-analysis/heap/core/holders.mjs +80 -0
- package/heap-analysis/heap/core/load.mjs +46 -0
- package/heap-analysis/heap/core/report.mjs +68 -0
- package/heap-analysis/heap/core/strings.mjs +80 -0
- package/heap-analysis/heap/langium/concepts.mjs +230 -0
- package/heap-analysis/heap/langium/glsp.classifier.mjs +80 -0
- package/heap-analysis/heap/langium/langium.classifier.mjs +203 -0
- package/heap-analysis/heap/renderer/renderer.mjs +122 -0
- package/lib/cli-version.d.ts +21 -0
- package/lib/cli-version.d.ts.map +1 -0
- package/lib/cli-version.js +30 -0
- package/lib/cli-version.js.map +1 -0
- package/lib/cli.d.ts +11 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +135 -0
- package/lib/cli.js.map +1 -0
- package/lib/commands/analyze-heap-args.d.ts +46 -0
- package/lib/commands/analyze-heap-args.d.ts.map +1 -0
- package/lib/commands/analyze-heap-args.js +174 -0
- package/lib/commands/analyze-heap-args.js.map +1 -0
- package/lib/commands/analyze-heap.d.ts +37 -0
- package/lib/commands/analyze-heap.d.ts.map +1 -0
- package/lib/commands/analyze-heap.js +63 -0
- package/lib/commands/analyze-heap.js.map +1 -0
- package/lib/commands/ast-ground-truth-args.d.ts +23 -0
- package/lib/commands/ast-ground-truth-args.d.ts.map +1 -0
- package/lib/commands/ast-ground-truth-args.js +47 -0
- package/lib/commands/ast-ground-truth-args.js.map +1 -0
- package/lib/commands/ast-ground-truth-driver.d.ts +10 -0
- package/lib/commands/ast-ground-truth-driver.d.ts.map +1 -0
- package/lib/commands/ast-ground-truth-driver.js +72 -0
- package/lib/commands/ast-ground-truth-driver.js.map +1 -0
- package/lib/commands/ast-ground-truth.d.ts +31 -0
- package/lib/commands/ast-ground-truth.d.ts.map +1 -0
- package/lib/commands/ast-ground-truth.js +36 -0
- package/lib/commands/ast-ground-truth.js.map +1 -0
- package/lib/commands/generate-transfer-model-args.d.ts +38 -0
- package/lib/commands/generate-transfer-model-args.d.ts.map +1 -0
- package/lib/commands/generate-transfer-model-args.js +183 -0
- package/lib/commands/generate-transfer-model-args.js.map +1 -0
- package/lib/commands/generate-transfer-model-config.d.ts +32 -0
- package/lib/commands/generate-transfer-model-config.d.ts.map +1 -0
- package/lib/commands/generate-transfer-model-config.js +122 -0
- package/lib/commands/generate-transfer-model-config.js.map +1 -0
- package/lib/commands/generate-transfer-model.d.ts +110 -0
- package/lib/commands/generate-transfer-model.d.ts.map +1 -0
- package/lib/commands/generate-transfer-model.js +587 -0
- package/lib/commands/generate-transfer-model.js.map +1 -0
- package/lib/commands/harness-args.d.ts +198 -0
- package/lib/commands/harness-args.d.ts.map +1 -0
- package/lib/commands/harness-args.js +339 -0
- package/lib/commands/harness-args.js.map +1 -0
- package/lib/commands/headless-harness.d.ts +97 -0
- package/lib/commands/headless-harness.d.ts.map +1 -0
- package/lib/commands/headless-harness.js +121 -0
- package/lib/commands/headless-harness.js.map +1 -0
- package/lib/commands/init-args.d.ts +81 -0
- package/lib/commands/init-args.d.ts.map +1 -0
- package/lib/commands/init-args.js +250 -0
- package/lib/commands/init-args.js.map +1 -0
- package/lib/commands/init-prompt.d.ts +66 -0
- package/lib/commands/init-prompt.d.ts.map +1 -0
- package/lib/commands/init-prompt.js +71 -0
- package/lib/commands/init-prompt.js.map +1 -0
- package/lib/commands/init-templates.d.ts +42 -0
- package/lib/commands/init-templates.d.ts.map +1 -0
- package/lib/commands/init-templates.js +1902 -0
- package/lib/commands/init-templates.js.map +1 -0
- package/lib/commands/init-wizard.d.ts +65 -0
- package/lib/commands/init-wizard.d.ts.map +1 -0
- package/lib/commands/init-wizard.js +302 -0
- package/lib/commands/init-wizard.js.map +1 -0
- package/lib/commands/init-workspace.d.ts +168 -0
- package/lib/commands/init-workspace.d.ts.map +1 -0
- package/lib/commands/init-workspace.js +372 -0
- package/lib/commands/init-workspace.js.map +1 -0
- package/lib/commands/init.d.ts +273 -0
- package/lib/commands/init.d.ts.map +1 -0
- package/lib/commands/init.js +303 -0
- package/lib/commands/init.js.map +1 -0
- package/lib/commands/lint-grammar-args.d.ts +23 -0
- package/lib/commands/lint-grammar-args.d.ts.map +1 -0
- package/lib/commands/lint-grammar-args.js +63 -0
- package/lib/commands/lint-grammar-args.js.map +1 -0
- package/lib/commands/lint-grammar-driver.d.ts +10 -0
- package/lib/commands/lint-grammar-driver.d.ts.map +1 -0
- package/lib/commands/lint-grammar-driver.js +72 -0
- package/lib/commands/lint-grammar-driver.js.map +1 -0
- package/lib/commands/lint-grammar-report.d.ts +24 -0
- package/lib/commands/lint-grammar-report.d.ts.map +1 -0
- package/lib/commands/lint-grammar-report.js +65 -0
- package/lib/commands/lint-grammar-report.js.map +1 -0
- package/lib/commands/lint-grammar.d.ts +33 -0
- package/lib/commands/lint-grammar.d.ts.map +1 -0
- package/lib/commands/lint-grammar.js +42 -0
- package/lib/commands/lint-grammar.js.map +1 -0
- package/lib/commands/measure-memory-args.d.ts +23 -0
- package/lib/commands/measure-memory-args.d.ts.map +1 -0
- package/lib/commands/measure-memory-args.js +106 -0
- package/lib/commands/measure-memory-args.js.map +1 -0
- package/lib/commands/measure-memory-driver.d.ts +10 -0
- package/lib/commands/measure-memory-driver.d.ts.map +1 -0
- package/lib/commands/measure-memory-driver.js +110 -0
- package/lib/commands/measure-memory-driver.js.map +1 -0
- package/lib/commands/measure-memory.d.ts +68 -0
- package/lib/commands/measure-memory.d.ts.map +1 -0
- package/lib/commands/measure-memory.js +100 -0
- package/lib/commands/measure-memory.js.map +1 -0
- package/lib/commands/model-docs-args.d.ts +23 -0
- package/lib/commands/model-docs-args.d.ts.map +1 -0
- package/lib/commands/model-docs-args.js +53 -0
- package/lib/commands/model-docs-args.js.map +1 -0
- package/lib/commands/model-docs-driver.d.ts +10 -0
- package/lib/commands/model-docs-driver.d.ts.map +1 -0
- package/lib/commands/model-docs-driver.js +61 -0
- package/lib/commands/model-docs-driver.js.map +1 -0
- package/lib/commands/model-docs-report.d.ts +18 -0
- package/lib/commands/model-docs-report.d.ts.map +1 -0
- package/lib/commands/model-docs-report.js +123 -0
- package/lib/commands/model-docs-report.js.map +1 -0
- package/lib/commands/model-docs.d.ts +30 -0
- package/lib/commands/model-docs.d.ts.map +1 -0
- package/lib/commands/model-docs.js +37 -0
- package/lib/commands/model-docs.js.map +1 -0
- package/lib/commands/projects-args.d.ts +25 -0
- package/lib/commands/projects-args.d.ts.map +1 -0
- package/lib/commands/projects-args.js +49 -0
- package/lib/commands/projects-args.js.map +1 -0
- package/lib/commands/projects.d.ts +45 -0
- package/lib/commands/projects.d.ts.map +1 -0
- package/lib/commands/projects.js +39 -0
- package/lib/commands/projects.js.map +1 -0
- package/lib/commands/query-args.d.ts +25 -0
- package/lib/commands/query-args.d.ts.map +1 -0
- package/lib/commands/query-args.js +46 -0
- package/lib/commands/query-args.js.map +1 -0
- package/lib/commands/query.d.ts +32 -0
- package/lib/commands/query.d.ts.map +1 -0
- package/lib/commands/query.js +29 -0
- package/lib/commands/query.js.map +1 -0
- package/lib/commands/reflect-args.d.ts +23 -0
- package/lib/commands/reflect-args.d.ts.map +1 -0
- package/lib/commands/reflect-args.js +59 -0
- package/lib/commands/reflect-args.js.map +1 -0
- package/lib/commands/reflect-driver.d.ts +10 -0
- package/lib/commands/reflect-driver.d.ts.map +1 -0
- package/lib/commands/reflect-driver.js +66 -0
- package/lib/commands/reflect-driver.js.map +1 -0
- package/lib/commands/reflect-report.d.ts +20 -0
- package/lib/commands/reflect-report.d.ts.map +1 -0
- package/lib/commands/reflect-report.js +127 -0
- package/lib/commands/reflect-report.js.map +1 -0
- package/lib/commands/reflect.d.ts +30 -0
- package/lib/commands/reflect.d.ts.map +1 -0
- package/lib/commands/reflect.js +38 -0
- package/lib/commands/reflect.js.map +1 -0
- package/lib/commands/save-args.d.ts +26 -0
- package/lib/commands/save-args.d.ts.map +1 -0
- package/lib/commands/save-args.js +59 -0
- package/lib/commands/save-args.js.map +1 -0
- package/lib/commands/save.d.ts +38 -0
- package/lib/commands/save.d.ts.map +1 -0
- package/lib/commands/save.js +48 -0
- package/lib/commands/save.js.map +1 -0
- package/lib/commands/validate-args.d.ts +23 -0
- package/lib/commands/validate-args.d.ts.map +1 -0
- package/lib/commands/validate-args.js +60 -0
- package/lib/commands/validate-args.js.map +1 -0
- package/lib/commands/validate-driver.d.ts +10 -0
- package/lib/commands/validate-driver.d.ts.map +1 -0
- package/lib/commands/validate-driver.js +72 -0
- package/lib/commands/validate-driver.js.map +1 -0
- package/lib/commands/validate-report.d.ts +30 -0
- package/lib/commands/validate-report.d.ts.map +1 -0
- package/lib/commands/validate-report.js +87 -0
- package/lib/commands/validate-report.js.map +1 -0
- package/lib/commands/validate.d.ts +34 -0
- package/lib/commands/validate.d.ts.map +1 -0
- package/lib/commands/validate.js +41 -0
- package/lib/commands/validate.js.map +1 -0
- package/lib/commands/watch-args.d.ts +26 -0
- package/lib/commands/watch-args.d.ts.map +1 -0
- package/lib/commands/watch-args.js +59 -0
- package/lib/commands/watch-args.js.map +1 -0
- package/lib/commands/watch.d.ts +75 -0
- package/lib/commands/watch.d.ts.map +1 -0
- package/lib/commands/watch.js +112 -0
- package/lib/commands/watch.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +16 -0
- package/lib/index.js.map +1 -0
- package/lib/log-level.d.ts +39 -0
- package/lib/log-level.d.ts.map +1 -0
- package/lib/log-level.js +47 -0
- package/lib/log-level.js.map +1 -0
- package/lib/package-name.d.ts +33 -0
- package/lib/package-name.d.ts.map +1 -0
- package/lib/package-name.js +37 -0
- package/lib/package-name.js.map +1 -0
- package/lib/spawn-data-server.d.ts +102 -0
- package/lib/spawn-data-server.d.ts.map +1 -0
- package/lib/spawn-data-server.js +154 -0
- package/lib/spawn-data-server.js.map +1 -0
- package/lib/testing/echo-server.d.ts +11 -0
- package/lib/testing/echo-server.d.ts.map +1 -0
- package/lib/testing/echo-server.js +79 -0
- package/lib/testing/echo-server.js.map +1 -0
- package/package.json +105 -0
- package/src/cli-version.ts +32 -0
- package/src/cli.ts +139 -0
- package/src/commands/analyze-heap-args.ts +184 -0
- package/src/commands/analyze-heap.ts +76 -0
- package/src/commands/ast-ground-truth-args.ts +63 -0
- package/src/commands/ast-ground-truth-driver.ts +81 -0
- package/src/commands/ast-ground-truth.ts +49 -0
- package/src/commands/generate-transfer-model-args.ts +203 -0
- package/src/commands/generate-transfer-model-config.ts +128 -0
- package/src/commands/generate-transfer-model.ts +716 -0
- package/src/commands/harness-args.ts +429 -0
- package/src/commands/headless-harness.ts +165 -0
- package/src/commands/init-args.ts +273 -0
- package/src/commands/init-prompt.ts +149 -0
- package/src/commands/init-templates.ts +2037 -0
- package/src/commands/init-wizard.ts +378 -0
- package/src/commands/init-workspace.ts +442 -0
- package/src/commands/init.ts +554 -0
- package/src/commands/lint-grammar-args.ts +79 -0
- package/src/commands/lint-grammar-driver.ts +83 -0
- package/src/commands/lint-grammar-report.ts +74 -0
- package/src/commands/lint-grammar.ts +57 -0
- package/src/commands/measure-memory-args.ts +123 -0
- package/src/commands/measure-memory-driver.ts +128 -0
- package/src/commands/measure-memory.ts +143 -0
- package/src/commands/model-docs-args.ts +69 -0
- package/src/commands/model-docs-driver.ts +68 -0
- package/src/commands/model-docs-report.ts +133 -0
- package/src/commands/model-docs.ts +48 -0
- package/src/commands/projects-args.ts +62 -0
- package/src/commands/projects.ts +76 -0
- package/src/commands/query-args.ts +61 -0
- package/src/commands/query.ts +58 -0
- package/src/commands/reflect-args.ts +75 -0
- package/src/commands/reflect-driver.ts +76 -0
- package/src/commands/reflect-report.ts +138 -0
- package/src/commands/reflect.ts +51 -0
- package/src/commands/save-args.ts +74 -0
- package/src/commands/save.ts +84 -0
- package/src/commands/validate-args.ts +76 -0
- package/src/commands/validate-driver.ts +84 -0
- package/src/commands/validate-report.ts +95 -0
- package/src/commands/validate.ts +58 -0
- package/src/commands/watch-args.ts +74 -0
- package/src/commands/watch.ts +185 -0
- package/src/index.ts +16 -0
- package/src/log-level.ts +49 -0
- package/src/package-name.ts +39 -0
- package/src/spawn-data-server.ts +247 -0
- package/src/testing/echo-server.ts +93 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import { buildInitTemplates, readFrameworkVersion, UNPUBLISHED_FRAMEWORK_VERSION } from './init-templates.js';
|
|
12
|
+
import { createNodeWorkspaceProbe, detectWorkspace } from './init-workspace.js';
|
|
13
|
+
/**
|
|
14
|
+
* The protocol heads a scaffold can start, in composition order.
|
|
15
|
+
*
|
|
16
|
+
* `lsp` is mandatory rather than optional: it owns the workspace, the build
|
|
17
|
+
* pipeline and the shared service tier every other head reads through, so a
|
|
18
|
+
* project without it has nothing for `data` or `glsp` to serve.
|
|
19
|
+
*/
|
|
20
|
+
export const INIT_HEADS = ['lsp', 'data', 'glsp'];
|
|
21
|
+
/** The heads a scaffold emits when `--heads` is not given. */
|
|
22
|
+
export const DEFAULT_INIT_HEADS = ['lsp', 'data'];
|
|
23
|
+
/** True for a string naming one of {@link INIT_HEADS}. */
|
|
24
|
+
export function isInitHead(value) {
|
|
25
|
+
return INIT_HEADS.includes(value);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A standalone, unscoped, unpublishable package — what `init` emits without the
|
|
29
|
+
* packaging flags.
|
|
30
|
+
*
|
|
31
|
+
* `private` defaults to TRUE because the manifest also declares `license:
|
|
32
|
+
* "UNLICENSED"`, and a package that grants no rights while being publishable to
|
|
33
|
+
* a public registry asserts two contradictory things about itself. npm pairs
|
|
34
|
+
* those two keys for exactly this reason. The scaffold cannot pick a licence for
|
|
35
|
+
* a stranger's project, so it withholds publication instead of granting rights
|
|
36
|
+
* nobody chose; `--public` is the opt-out for a project that has picked one.
|
|
37
|
+
*/
|
|
38
|
+
export const STANDALONE_PACKAGING = { private: true };
|
|
39
|
+
/** Kebab-case a PascalCase/camelCase name. */
|
|
40
|
+
export function kebab(name) {
|
|
41
|
+
return name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
/** True for a PascalCase identifier legal as a generated TypeScript symbol prefix. */
|
|
44
|
+
function isPascalIdentifier(value) {
|
|
45
|
+
return /^[A-Za-z][A-Za-z0-9]*$/.test(value);
|
|
46
|
+
}
|
|
47
|
+
/** Strip a leading dot and reject an extension that is empty or dotted through. */
|
|
48
|
+
function normalizeExtension(value, grammar) {
|
|
49
|
+
const extension = value.replace(/^\./, '');
|
|
50
|
+
if (extension.length === 0) {
|
|
51
|
+
throw new Error(`Invalid extension '${value}' for grammar '${grammar}': an extension cannot be empty.`);
|
|
52
|
+
}
|
|
53
|
+
return extension;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve one grammar's names.
|
|
57
|
+
*
|
|
58
|
+
* `qualify` comes from the project rather than the grammar: a lone grammar
|
|
59
|
+
* whose name matches the project keeps the bare project id, but as soon as
|
|
60
|
+
* there are several every id is qualified, so the set reads consistently
|
|
61
|
+
* instead of one member being special.
|
|
62
|
+
*/
|
|
63
|
+
function resolveGrammar(spec, projectId, qualify, diagram) {
|
|
64
|
+
if (!isPascalIdentifier(spec.name)) {
|
|
65
|
+
throw new Error(`Invalid --grammar '${spec.name}': must be a PascalCase identifier (letters and digits, starting with a letter), e.g. 'Domain'.`);
|
|
66
|
+
}
|
|
67
|
+
const grammarId = kebab(spec.name);
|
|
68
|
+
const extensions = (spec.extensions ?? [grammarId]).map(extension => normalizeExtension(extension, spec.name));
|
|
69
|
+
if (extensions.length === 0) {
|
|
70
|
+
throw new Error(`Invalid --extensions for grammar '${spec.name}': at least one extension is required.`);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
grammar: spec.name,
|
|
74
|
+
grammarId,
|
|
75
|
+
languageId: spec.languageId ?? (qualify || grammarId !== projectId ? `${projectId}-${grammarId}` : projectId),
|
|
76
|
+
extensions,
|
|
77
|
+
entryRule: `${spec.name}Model`,
|
|
78
|
+
nodeRule: `${spec.name}Node`,
|
|
79
|
+
diagram
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve which grammars get a diagram.
|
|
84
|
+
*
|
|
85
|
+
* With the `glsp` head on and nothing marked, a lone grammar is unambiguous and
|
|
86
|
+
* is taken as the diagram's; with several it is a real choice, so it is required
|
|
87
|
+
* rather than guessed — binding a diagram to the wrong grammar surfaces much
|
|
88
|
+
* later as references resolving against the wrong scope.
|
|
89
|
+
*/
|
|
90
|
+
function resolveDiagrams(specs, heads) {
|
|
91
|
+
const marked = specs.map(spec => spec.diagram === true);
|
|
92
|
+
if (!heads.includes('glsp')) {
|
|
93
|
+
const named = specs.filter(spec => spec.diagram === true).map(spec => spec.name);
|
|
94
|
+
if (named.length > 0) {
|
|
95
|
+
throw new Error(`--diagram was given for ${named.join(', ')} but the head set is '${heads.join(',')}'. ` +
|
|
96
|
+
"Add 'glsp' to --heads, since the emitted dependencies follow the head set.");
|
|
97
|
+
}
|
|
98
|
+
return marked;
|
|
99
|
+
}
|
|
100
|
+
if (marked.some(Boolean)) {
|
|
101
|
+
return marked;
|
|
102
|
+
}
|
|
103
|
+
if (specs.length === 1) {
|
|
104
|
+
return [true];
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`--heads includes 'glsp' but no grammar carries --diagram. Mark the one the diagram edits: ` +
|
|
107
|
+
`${specs.map(spec => spec.name).join(', ')}.`);
|
|
108
|
+
}
|
|
109
|
+
/** Validate the head set: known names only, and `lsp` present. */
|
|
110
|
+
function resolveHeads(heads) {
|
|
111
|
+
const resolved = heads === undefined || heads.length === 0 ? DEFAULT_INIT_HEADS : heads;
|
|
112
|
+
const unknown = resolved.filter(head => !isInitHead(head));
|
|
113
|
+
if (unknown.length > 0) {
|
|
114
|
+
throw new Error(`Unknown head(s) '${unknown.join(', ')}': expected one of ${INIT_HEADS.join(', ')}.`);
|
|
115
|
+
}
|
|
116
|
+
if (!resolved.includes('lsp')) {
|
|
117
|
+
throw new Error("--heads must include 'lsp': it owns the workspace, the build pipeline and the shared service tier the other heads read through.");
|
|
118
|
+
}
|
|
119
|
+
// De-duplicated and put back in composition order, so the order the heads
|
|
120
|
+
// were named in does not change the emitted project.
|
|
121
|
+
return INIT_HEADS.filter(head => resolved.includes(head));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Reject the collisions that would otherwise surface as a confusing generator
|
|
125
|
+
* or runtime failure rather than as a bad invocation.
|
|
126
|
+
*
|
|
127
|
+
* The extension check is the one worth having: Langium routes documents to a
|
|
128
|
+
* language BY extension, so two grammars claiming `.foo` is not a name clash
|
|
129
|
+
* but a silent mis-route of every `.foo` file to whichever language registered
|
|
130
|
+
* first.
|
|
131
|
+
*/
|
|
132
|
+
function assertNoCollisions(grammars) {
|
|
133
|
+
const byGrammarId = new Map();
|
|
134
|
+
const byLanguageId = new Map();
|
|
135
|
+
const byExtension = new Map();
|
|
136
|
+
for (const grammar of grammars) {
|
|
137
|
+
const clashingName = byGrammarId.get(grammar.grammarId);
|
|
138
|
+
if (clashingName !== undefined) {
|
|
139
|
+
throw new Error(`Duplicate grammar '${grammar.grammar}': it resolves to the same file as '${clashingName}'.`);
|
|
140
|
+
}
|
|
141
|
+
byGrammarId.set(grammar.grammarId, grammar.grammar);
|
|
142
|
+
const clashingLanguage = byLanguageId.get(grammar.languageId);
|
|
143
|
+
if (clashingLanguage !== undefined) {
|
|
144
|
+
throw new Error(`Duplicate language id '${grammar.languageId}': claimed by both '${clashingLanguage}' and '${grammar.grammar}'.`);
|
|
145
|
+
}
|
|
146
|
+
byLanguageId.set(grammar.languageId, grammar.grammar);
|
|
147
|
+
for (const extension of grammar.extensions) {
|
|
148
|
+
const clashingExtension = byExtension.get(extension);
|
|
149
|
+
if (clashingExtension !== undefined) {
|
|
150
|
+
throw new Error(`File extension '.${extension}' is claimed by both '${clashingExtension}' and '${grammar.grammar}'. ` +
|
|
151
|
+
'Langium routes documents by extension, so each grammar needs its own.');
|
|
152
|
+
}
|
|
153
|
+
byExtension.set(extension, grammar.grammar);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Derive the whole scaffold description from `--name` plus the collected
|
|
159
|
+
* grammars. Throws on a name that is not a valid PascalCase identifier — both
|
|
160
|
+
* project and grammar names become prefixes of generated TypeScript symbols.
|
|
161
|
+
*
|
|
162
|
+
* With no grammars given, one is synthesised from the project name, which is
|
|
163
|
+
* the single-language starter shape.
|
|
164
|
+
*/
|
|
165
|
+
export function resolveInitComposition(name, grammars = [], heads, packaging = STANDALONE_PACKAGING) {
|
|
166
|
+
if (!isPascalIdentifier(name)) {
|
|
167
|
+
throw new Error(`Invalid --name '${name}': must be a PascalCase identifier (letters and digits, starting with a letter), e.g. 'Bookstore'.`);
|
|
168
|
+
}
|
|
169
|
+
const projectId = kebab(name);
|
|
170
|
+
if (packaging.scope !== undefined && !/^@[a-z0-9][a-z0-9._-]*$/.test(packaging.scope)) {
|
|
171
|
+
throw new Error(`Invalid --scope '${packaging.scope}': an npm scope starts with '@', e.g. '@acme'.`);
|
|
172
|
+
}
|
|
173
|
+
const resolvedHeads = resolveHeads(heads);
|
|
174
|
+
const specs = grammars.length > 0 ? grammars : [{ name }];
|
|
175
|
+
const diagrams = resolveDiagrams(specs, resolvedHeads);
|
|
176
|
+
const resolved = specs.map((spec, index) => resolveGrammar(spec, projectId, specs.length > 1, diagrams[index]));
|
|
177
|
+
assertNoCollisions(resolved);
|
|
178
|
+
return { name, projectId, heads: resolvedHeads, grammars: resolved, packaging, frameworkVersion: readFrameworkVersion() };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Plan the files a scaffold emits — every template rendered for this
|
|
182
|
+
* composition. Pure over its input → unit-testable without touching disk;
|
|
183
|
+
* {@link runInit} is the thin IO wrapper.
|
|
184
|
+
*/
|
|
185
|
+
export function planInitFiles(composition) {
|
|
186
|
+
return buildInitTemplates(composition);
|
|
187
|
+
}
|
|
188
|
+
/** True when `dir` exists and contains at least one entry. */
|
|
189
|
+
export function isNonEmptyDir(dir) {
|
|
190
|
+
return fs.existsSync(dir) && fs.statSync(dir).isDirectory() && fs.readdirSync(dir).length > 0;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Resolve the packaging tier for a target directory, running workspace
|
|
194
|
+
* detection when `--monorepo` asked for it.
|
|
195
|
+
*
|
|
196
|
+
* Exported because the `init`-provenance gate re-runs the reference example's
|
|
197
|
+
* recorded invocation and must reach the same composition `runInit` would: a
|
|
198
|
+
* second copy of these rules there would drift from these, and the gate exists
|
|
199
|
+
* precisely to catch drift.
|
|
200
|
+
*/
|
|
201
|
+
export function resolveInitPackaging(targetDir, options) {
|
|
202
|
+
if (options.monorepo !== true) {
|
|
203
|
+
return { scope: options.scope, private: options.public !== true };
|
|
204
|
+
}
|
|
205
|
+
const detection = detectWorkspace(targetDir, options.probe ?? createNodeWorkspaceProbe());
|
|
206
|
+
if (detection === undefined) {
|
|
207
|
+
throw new Error(`--monorepo was given but no ancestor of '${path.resolve(targetDir)}' has a package.json declaring 'workspaces'. ` +
|
|
208
|
+
'Scaffold without it for a standalone project.');
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
scope: options.scope,
|
|
212
|
+
private: options.public !== true,
|
|
213
|
+
// The scope and the publishability deliberately do NOT fall back to what
|
|
214
|
+
// detection found: the emitted package name stays a function of the argv
|
|
215
|
+
// alone, which is what lets the wizard's echoed command reproduce the
|
|
216
|
+
// scaffold anywhere. Detection only supplies the wizard's DEFAULT answer.
|
|
217
|
+
workspace: {
|
|
218
|
+
targetPath: detection.targetPath,
|
|
219
|
+
baseTsconfig: detection.baseTsconfig,
|
|
220
|
+
baseCompilerOptions: detection.baseCompilerOptions,
|
|
221
|
+
printWidth: detection.printWidth,
|
|
222
|
+
eslintConfig: detection.eslintConfig
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Scaffold a new Hydranium language project end-to-end: one starter grammar per
|
|
228
|
+
* `--grammar`, `create<Name>Services` DI wiring, a launcher for each head in
|
|
229
|
+
* `--heads`, `langium-config.json`, `package.json`, and scripts. Does NOT run `npm install`
|
|
230
|
+
* or `langium generate` — those are printed as next steps, so the command stays
|
|
231
|
+
* offline and side-effect-free beyond the files it writes. Refuses a non-empty
|
|
232
|
+
* target directory unless `force`.
|
|
233
|
+
*/
|
|
234
|
+
export function runInit(options) {
|
|
235
|
+
const write = options.write ?? ((line) => process.stdout.write(line));
|
|
236
|
+
const targetDir = path.resolve(options.targetDir);
|
|
237
|
+
const detection = options.monorepo ? detectWorkspace(targetDir, options.probe ?? createNodeWorkspaceProbe()) : undefined;
|
|
238
|
+
const composition = resolveInitComposition(options.name, options.grammars, options.heads, resolveInitPackaging(targetDir, options));
|
|
239
|
+
if (!options.force && isNonEmptyDir(targetDir)) {
|
|
240
|
+
throw new Error(`Target directory '${targetDir}' is not empty. Pass --force to scaffold into it anyway.`);
|
|
241
|
+
}
|
|
242
|
+
const files = planInitFiles(composition);
|
|
243
|
+
if (options.__writeFilesForTest) {
|
|
244
|
+
options.__writeFilesForTest(targetDir, files);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
for (const file of files) {
|
|
248
|
+
const absolute = path.join(targetDir, file.path);
|
|
249
|
+
fs.mkdirSync(path.dirname(absolute), { recursive: true });
|
|
250
|
+
fs.writeFileSync(absolute, file.content, 'utf-8');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const grammarList = composition.grammars.map(grammar => (grammar.diagram ? `${grammar.grammar} (diagram)` : grammar.grammar)).join(', ');
|
|
254
|
+
write(`Scaffolded ${composition.name} (${files.length} files, heads: ${composition.heads.join(',')}, ` +
|
|
255
|
+
`${composition.grammars.length} grammar(s): ${grammarList}) into ${targetDir}\n`);
|
|
256
|
+
if (detection !== undefined) {
|
|
257
|
+
write('\n');
|
|
258
|
+
write(`Workspace root: ${detection.rootDir}\n`);
|
|
259
|
+
if (detection.baseTsconfig !== undefined) {
|
|
260
|
+
write(` tsconfig.json extends ${detection.baseTsconfig}, minus the options it inherits unchanged.\n`);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
write(' No root tsconfig carries compilerOptions, so the emitted one stands alone.\n');
|
|
264
|
+
}
|
|
265
|
+
write(" .gitignore holds `syntaxes/` only — the workspace root's covers the rest.\n");
|
|
266
|
+
if (detection.printWidth !== undefined) {
|
|
267
|
+
write(` Sources wrapped at ${detection.printWidth} columns, from ${detection.rootDir}'s prettier config.\n`);
|
|
268
|
+
}
|
|
269
|
+
if (detection.eslintConfig !== undefined) {
|
|
270
|
+
write(` A lint script was added — ${detection.eslintConfig} says this repo lints. Adjust it if your invocation differs.\n`);
|
|
271
|
+
}
|
|
272
|
+
// Printed rather than applied: `init` writes inside the target directory
|
|
273
|
+
// and nowhere else, so a scaffold can never surprise-edit a manifest that
|
|
274
|
+
// is under review, mid-rebase, or simply not the caller's to change.
|
|
275
|
+
if (detection.coveredBy === undefined) {
|
|
276
|
+
write(` Add this to "workspaces" in ${path.join(detection.rootDir, 'package.json')}:\n`);
|
|
277
|
+
write(` "${detection.targetPath}"\n`);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
write(` Already covered by the "${detection.coveredBy}" workspaces entry — no root manifest change needed.\n`);
|
|
281
|
+
}
|
|
282
|
+
if (composition.packaging.scope === undefined && detection.scope !== undefined) {
|
|
283
|
+
write(` Sibling packages all use the "${detection.scope}" scope; pass --scope ${detection.scope} to match them.\n`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
write('\n');
|
|
287
|
+
write('Next steps:\n');
|
|
288
|
+
write(` cd ${options.targetDir}\n`);
|
|
289
|
+
// The warning is conditional on the pins this scaffold actually carries — see
|
|
290
|
+
// `UNPUBLISHED_FRAMEWORK_VERSION`.
|
|
291
|
+
write(composition.frameworkVersion === UNPUBLISHED_FRAMEWORK_VERSION
|
|
292
|
+
? ' npm install # 404s until @hydranium/* is published — see README\n'
|
|
293
|
+
: ' npm install\n');
|
|
294
|
+
write(' npm run build # langium generate + tsc\n');
|
|
295
|
+
write(' npm test # the scaffolded DI-composition test\n');
|
|
296
|
+
// `npx`, not a bare invocation: `@hydranium/cli` is a devDependency of the
|
|
297
|
+
// scaffold, so the binary is on PATH inside an npm script and nowhere else.
|
|
298
|
+
write(' npx hydranium-cli reflect --services ./lib/services.js\n');
|
|
299
|
+
write('\n');
|
|
300
|
+
write('The emitted sources carry no license header — run your own header tool if\n');
|
|
301
|
+
write('your repo gates them. See the README section on that.\n');
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAC9G,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAuC,MAAM,qBAAqB,CAAC;AAErH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAK3D,8DAA8D;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAEvE,0DAA0D;AAC1D,MAAM,UAAU,UAAU,CAAC,KAAa;IACrC,OAAQ,UAAgC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAgID;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAkB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AA2ErE,8CAA8C;AAC9C,MAAM,UAAU,KAAK,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;AACpE,CAAC;AAED,sFAAsF;AACtF,SAAS,kBAAkB,CAAC,KAAa;IACtC,OAAO,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,mFAAmF;AACnF,SAAS,kBAAkB,CAAC,KAAa,EAAE,OAAe;IACvD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,kBAAkB,OAAO,kCAAkC,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO,SAAS,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,IAAqB,EAAE,SAAiB,EAAE,OAAgB,EAAE,OAAgB;IACjG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACZ,sBAAsB,IAAI,CAAC,IAAI,iGAAiG,CAClI,CAAC;IACL,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/G,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,IAAI,wCAAwC,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO;QACJ,OAAO,EAAE,IAAI,CAAC,IAAI;QAClB,SAAS;QACT,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,IAAI,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7G,UAAU;QACV,SAAS,EAAE,GAAG,IAAI,CAAC,IAAI,OAAO;QAC9B,QAAQ,EAAE,GAAG,IAAI,CAAC,IAAI,MAAM;QAC5B,OAAO;KACT,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,KAAiC,EAAE,KAA0B;IACnF,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACZ,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;gBACrF,4EAA4E,CACjF,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC;IACjB,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CACZ,4FAA4F;QACzF,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAClD,CAAC;AACL,CAAC;AAED,kEAAkE;AAClE,SAAS,YAAY,CAAC,KAAsC;IACzD,MAAM,QAAQ,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;IACxF,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACZ,iIAAiI,CACnI,CAAC;IACL,CAAC;IACD,0EAA0E;IAC1E,qDAAqD;IACrD,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CAAC,QAAqC;IAC9D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,sBAAsB,OAAO,CAAC,OAAO,uCAAuC,YAAY,IAAI,CAAC,CAAC;QACjH,CAAC;QACD,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAEpD,MAAM,gBAAgB,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC9D,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,CAAC,UAAU,uBAAuB,gBAAgB,UAAU,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QACrI,CAAC;QACD,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAEtD,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACrD,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CACZ,oBAAoB,SAAS,yBAAyB,iBAAiB,UAAU,OAAO,CAAC,OAAO,KAAK;oBAClG,uEAAuE,CAC5E,CAAC;YACL,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;IACJ,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACnC,IAAY,EACZ,WAAuC,EAAE,EACzC,KAA2B,EAC3B,YAA2B,oBAAoB;IAE/C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACZ,mBAAmB,IAAI,oGAAoG,CAC7H,CAAC;IACL,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,SAAS,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,oBAAoB,SAAS,CAAC,KAAK,gDAAgD,CAAC,CAAC;IACxG,CAAC;IACD,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChH,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC7B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,EAAE,CAAC;AAC7H,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,WAA4B;IACvD,OAAO,kBAAkB,CAAC,WAAW,CAAC,CAAC;AAC1C,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAAC,GAAW;IACtC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AACjG,CAAC;AAUD;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,OAA6B;IAClF,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC7B,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;IACrE,CAAC;IACD,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,IAAI,wBAAwB,EAAE,CAAC,CAAC;IAC1F,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACZ,4CAA4C,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,+CAA+C;YAC/G,+CAA+C,CACpD,CAAC;IACL,CAAC;IACD,OAAO;QACJ,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;QAChC,yEAAyE;QACzE,yEAAyE;QACzE,sEAAsE;QACtE,0EAA0E;QAC1E,SAAS,EAAE;YACR,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,mBAAmB,EAAE,SAAS,CAAC,mBAAmB;YAClD,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,YAAY,EAAE,SAAS,CAAC,YAAY;SACtC;KACH,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,OAA2B;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,IAAI,wBAAwB,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzH,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,oBAAoB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAEpI,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,qBAAqB,SAAS,0DAA0D,CAAC,CAAC;IAC7G,CAAC;IAED,MAAM,KAAK,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAC/B,OAAO,CAAC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACL,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACjD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzI,KAAK,CACF,cAAc,WAAW,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,kBAAkB,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;QAC7F,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,gBAAgB,WAAW,UAAU,SAAS,IAAI,CACrF,CAAC;IACF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,CAAC;QACZ,KAAK,CAAC,mBAAmB,SAAS,CAAC,OAAO,IAAI,CAAC,CAAC;QAChD,IAAI,SAAS,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACxC,KAAK,CAAC,2BAA2B,SAAS,CAAC,YAAY,8CAA8C,CAAC,CAAC;QAC1G,CAAC;aAAM,CAAC;YACL,KAAK,CAAC,gFAAgF,CAAC,CAAC;QAC3F,CAAC;QACD,KAAK,CAAC,+EAA+E,CAAC,CAAC;QACvF,IAAI,SAAS,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACtC,KAAK,CAAC,wBAAwB,SAAS,CAAC,UAAU,kBAAkB,SAAS,CAAC,OAAO,uBAAuB,CAAC,CAAC;QACjH,CAAC;QACD,IAAI,SAAS,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACxC,KAAK,CAAC,+BAA+B,SAAS,CAAC,YAAY,gEAAgE,CAAC,CAAC;QAChI,CAAC;QACD,yEAAyE;QACzE,0EAA0E;QAC1E,qEAAqE;QACrE,IAAI,SAAS,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACrC,KAAK,CAAC,iCAAiC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;YAC1F,KAAK,CAAC,QAAQ,SAAS,CAAC,UAAU,KAAK,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACL,KAAK,CAAC,6BAA6B,SAAS,CAAC,SAAS,wDAAwD,CAAC,CAAC;QACnH,CAAC;QACD,IAAI,WAAW,CAAC,SAAS,CAAC,KAAK,KAAK,SAAS,IAAI,SAAS,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9E,KAAK,CAAC,mCAAmC,SAAS,CAAC,KAAK,yBAAyB,SAAS,CAAC,KAAK,mBAAmB,CAAC,CAAC;QACxH,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,CAAC,eAAe,CAAC,CAAC;IACvB,KAAK,CAAC,QAAQ,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC;IACrC,8EAA8E;IAC9E,mCAAmC;IACnC,KAAK,CACF,WAAW,CAAC,gBAAgB,KAAK,6BAA6B;QAC3D,CAAC,CAAC,kFAAkF;QACpF,CAAC,CAAC,iBAAiB,CACxB,CAAC;IACF,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC/D,KAAK,CAAC,mEAAmE,CAAC,CAAC;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,KAAK,CAAC,4DAA4D,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACrF,KAAK,CAAC,yDAAyD,CAAC,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { type UsageError } from './harness-args.js';
|
|
10
|
+
import { type LintGrammarCommandOptions } from './lint-grammar.js';
|
|
11
|
+
/**
|
|
12
|
+
* Every flag `lint-grammar` accepts, derived from the sets the parser is handed
|
|
13
|
+
* so the list cannot claim a flag the parser would reject. `--services` is
|
|
14
|
+
* consumed by the shared harness parser itself, so it is in neither set.
|
|
15
|
+
*/
|
|
16
|
+
export declare const LINT_GRAMMAR_FLAGS: readonly string[];
|
|
17
|
+
/** The subset that takes a value, so `--help` in a value position reads as data. */
|
|
18
|
+
export declare const LINT_GRAMMAR_VALUE_FLAGS: readonly string[];
|
|
19
|
+
/** The `--help` text, as data, held to {@link LINT_GRAMMAR_FLAGS} by a test. */
|
|
20
|
+
export declare const LINT_GRAMMAR_HELP: readonly string[];
|
|
21
|
+
export declare function parseLintGrammarArgs(args: string[], onError?: UsageError): LintGrammarCommandOptions;
|
|
22
|
+
export declare function runLintGrammarCommand(args: string[]): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=lint-grammar-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-grammar-args.d.ts","sourceRoot":"","sources":["../../src/commands/lint-grammar-args.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EASJ,KAAK,UAAU,EACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAkB,KAAK,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAMnF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAA8E,CAAC;AAE/H,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAA+D,CAAC;AAEtH,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAkB9C,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,UAA0B,GAAG,yBAAyB,CAanH;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { exitWithUsage, helpRequested, LOG_LEVEL_FLAG, logLevelHelpLine, logLevelOption, parseHarnessArgs, printHelp, SERVICES_FLAG } from './harness-args.js';
|
|
10
|
+
import { runLintGrammar } from './lint-grammar.js';
|
|
11
|
+
const VALUE_FLAGS = [LOG_LEVEL_FLAG];
|
|
12
|
+
const BOOL_FLAGS = ['--strict', '--json'];
|
|
13
|
+
const REPEATABLE_VALUE_FLAGS = ['--name-property'];
|
|
14
|
+
/**
|
|
15
|
+
* Every flag `lint-grammar` accepts, derived from the sets the parser is handed
|
|
16
|
+
* so the list cannot claim a flag the parser would reject. `--services` is
|
|
17
|
+
* consumed by the shared harness parser itself, so it is in neither set.
|
|
18
|
+
*/
|
|
19
|
+
export const LINT_GRAMMAR_FLAGS = [SERVICES_FLAG, ...REPEATABLE_VALUE_FLAGS, ...VALUE_FLAGS, ...BOOL_FLAGS];
|
|
20
|
+
/** The subset that takes a value, so `--help` in a value position reads as data. */
|
|
21
|
+
export const LINT_GRAMMAR_VALUE_FLAGS = [SERVICES_FLAG, ...REPEATABLE_VALUE_FLAGS, ...VALUE_FLAGS];
|
|
22
|
+
/** The `--help` text, as data, held to {@link LINT_GRAMMAR_FLAGS} by a test. */
|
|
23
|
+
export const LINT_GRAMMAR_HELP = [
|
|
24
|
+
'Usage: hydranium-cli lint-grammar --services <module> [--name-property <p>]... [--strict] [--json] [--log-level <lvl>]',
|
|
25
|
+
'',
|
|
26
|
+
"Check a head's grammar against the framework's conventions — a CI gate: the",
|
|
27
|
+
'process exits non-zero when a violation is found. Read-only: no workspace is',
|
|
28
|
+
'built (the grammar is static once the head registers its language), so',
|
|
29
|
+
'`lint-grammar` takes no `<workspace>`. Checks that every concrete cross-reference',
|
|
30
|
+
'target carries a name property (else references cannot resolve) and that each',
|
|
31
|
+
'language declares an entry rule. `<module>` is an ESM module exporting a',
|
|
32
|
+
'zero-arg `createServices(): { shared }` thunk. Needs @hydranium/core.',
|
|
33
|
+
'',
|
|
34
|
+
'Options:',
|
|
35
|
+
' --services <module> ESM module exporting `createServices(): { shared }` (required).',
|
|
36
|
+
' --name-property <p> Property that satisfies the nameability convention',
|
|
37
|
+
' (repeatable). Default: name.',
|
|
38
|
+
' --strict Also fail (non-zero exit) on warnings, not only errors.',
|
|
39
|
+
' --json Emit the raw JSON result instead of the human report.',
|
|
40
|
+
logLevelHelpLine(23)
|
|
41
|
+
];
|
|
42
|
+
export function parseLintGrammarArgs(args, onError = exitWithUsage) {
|
|
43
|
+
const { servicesModule, options, values } = parseHarnessArgs(args, 'lint-grammar', VALUE_FLAGS, BOOL_FLAGS, {
|
|
44
|
+
requireWorkspace: false,
|
|
45
|
+
repeatableValueFlags: REPEATABLE_VALUE_FLAGS,
|
|
46
|
+
onError
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
servicesModule,
|
|
50
|
+
nameProperties: values['--name-property'],
|
|
51
|
+
strict: options['--strict'] === 'true',
|
|
52
|
+
json: options['--json'] === 'true',
|
|
53
|
+
logLevel: logLevelOption(options[LOG_LEVEL_FLAG])
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function runLintGrammarCommand(args) {
|
|
57
|
+
if (helpRequested(args, LINT_GRAMMAR_VALUE_FLAGS)) {
|
|
58
|
+
printHelp(LINT_GRAMMAR_HELP);
|
|
59
|
+
return Promise.resolve();
|
|
60
|
+
}
|
|
61
|
+
return runLintGrammar(parseLintGrammarArgs(args));
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=lint-grammar-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-grammar-args.js","sourceRoot":"","sources":["../../src/commands/lint-grammar-args.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EACJ,aAAa,EACb,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,aAAa,EAEf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAkC,MAAM,mBAAmB,CAAC;AAEnF,MAAM,WAAW,GAAG,CAAC,cAAc,CAAU,CAAC;AAC9C,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAU,CAAC;AACnD,MAAM,sBAAsB,GAAG,CAAC,iBAAiB,CAAU,CAAC;AAE5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsB,CAAC,aAAa,EAAE,GAAG,sBAAsB,EAAE,GAAG,WAAW,EAAE,GAAG,UAAU,CAAC,CAAC;AAE/H,oFAAoF;AACpF,MAAM,CAAC,MAAM,wBAAwB,GAAsB,CAAC,aAAa,EAAE,GAAG,sBAAsB,EAAE,GAAG,WAAW,CAAC,CAAC;AAEtH,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IACjD,wHAAwH;IACxH,EAAE;IACF,6EAA6E;IAC7E,8EAA8E;IAC9E,wEAAwE;IACxE,mFAAmF;IACnF,+EAA+E;IAC/E,0EAA0E;IAC1E,uEAAuE;IACvE,EAAE;IACF,UAAU;IACV,0FAA0F;IAC1F,6EAA6E;IAC7E,uDAAuD;IACvD,kFAAkF;IAClF,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,IAAc,EAAE,UAAsB,aAAa;IACrF,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE;QACzG,gBAAgB,EAAE,KAAK;QACvB,oBAAoB,EAAE,sBAAsB;QAC5C,OAAO;KACT,CAAC,CAAC;IACH,OAAO;QACJ,cAAc;QACd,cAAc,EAAE,MAAM,CAAC,iBAAiB,CAAC;QACzC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,MAAM;QACtC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,MAAM;QAClC,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;KACnD,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAc;IACjD,IAAI,aAAa,CAAC,IAAI,EAAE,wBAAwB,CAAC,EAAE,CAAC;QACjD,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO,cAAc,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=lint-grammar-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-grammar-driver.d.ts","sourceRoot":"","sources":["../../src/commands/lint-grammar-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
/*
|
|
10
|
+
* Spawned child of the `lint-grammar` subcommand. Launched by the parent with
|
|
11
|
+
* `node <this> --services <module> [--name-property <p>]... [--json] [--strict]`.
|
|
12
|
+
* It dynamic-imports the head's services module, runs the framework's
|
|
13
|
+
* `lintGrammar`, prints the report (human or `--json`) and exits with the gate
|
|
14
|
+
* code (non-zero on errors; `--strict` also fails on warnings). Never imported —
|
|
15
|
+
* only spawned.
|
|
16
|
+
*/
|
|
17
|
+
import { loadHeadlessContext } from './headless-harness.js';
|
|
18
|
+
import { formatLintReport, lintExitCode } from './lint-grammar-report.js';
|
|
19
|
+
function parseArgs(argv) {
|
|
20
|
+
const parsed = { nameProperties: [], json: false, strict: false };
|
|
21
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
22
|
+
const flag = argv[index];
|
|
23
|
+
const next = () => {
|
|
24
|
+
const value = argv[index + 1];
|
|
25
|
+
if (value === undefined) {
|
|
26
|
+
console.error(`Missing value for ${flag}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
index += 1;
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
switch (flag) {
|
|
33
|
+
case '--services':
|
|
34
|
+
parsed.servicesModule = next();
|
|
35
|
+
break;
|
|
36
|
+
case '--name-property':
|
|
37
|
+
parsed.nameProperties.push(next());
|
|
38
|
+
break;
|
|
39
|
+
case '--json':
|
|
40
|
+
parsed.json = true;
|
|
41
|
+
break;
|
|
42
|
+
case '--strict':
|
|
43
|
+
parsed.strict = true;
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
console.error(`Unknown option: ${flag}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return parsed;
|
|
51
|
+
}
|
|
52
|
+
async function main(argv) {
|
|
53
|
+
const args = parseArgs(argv);
|
|
54
|
+
if (!args.servicesModule) {
|
|
55
|
+
console.error('lint-grammar-driver: --services <module> is required.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const { createServices, coreNode } = await loadHeadlessContext(args.servicesModule);
|
|
59
|
+
const result = coreNode.lintGrammar({
|
|
60
|
+
createServices,
|
|
61
|
+
nameProperties: args.nameProperties.length ? args.nameProperties : undefined
|
|
62
|
+
});
|
|
63
|
+
console.log(formatLintReport(result, { json: args.json }));
|
|
64
|
+
return lintExitCode(result, args.strict);
|
|
65
|
+
}
|
|
66
|
+
main(process.argv.slice(2))
|
|
67
|
+
.then(code => process.exit(code))
|
|
68
|
+
.catch((error) => {
|
|
69
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=lint-grammar-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-grammar-driver.js","sourceRoot":"","sources":["../../src/commands/lint-grammar-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import type { GrammarLintResult } from '@hydranium/core/node';
|
|
10
|
+
/**
|
|
11
|
+
* The exit code for a lint run: non-zero blocks the CI gate. Errors always fail;
|
|
12
|
+
* `strict` additionally fails on warnings.
|
|
13
|
+
*/
|
|
14
|
+
export declare function lintExitCode(result: GrammarLintResult, strict?: boolean): number;
|
|
15
|
+
/**
|
|
16
|
+
* Render a grammar-convention lint result for the terminal. `json` emits the raw
|
|
17
|
+
* {@link GrammarLintResult} (the machine-readable CI contract); the default is a
|
|
18
|
+
* human report — one `severity [rule] message` line per finding — closing with
|
|
19
|
+
* the {@link summaryLine} tally.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatLintReport(result: GrammarLintResult, options?: {
|
|
22
|
+
json?: boolean;
|
|
23
|
+
}): string;
|
|
24
|
+
//# sourceMappingURL=lint-grammar-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-grammar-report.d.ts","sourceRoot":"","sources":["../../src/commands/lint-grammar-report.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAO9D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,UAAQ,GAAG,MAAM,CAQ9E;AAwBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAapG"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
/** `s` when `count !== 1`, else empty. */
|
|
10
|
+
function plural(count) {
|
|
11
|
+
return count === 1 ? '' : 's';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The exit code for a lint run: non-zero blocks the CI gate. Errors always fail;
|
|
15
|
+
* `strict` additionally fails on warnings.
|
|
16
|
+
*/
|
|
17
|
+
export function lintExitCode(result, strict = false) {
|
|
18
|
+
if (result.counts.error > 0) {
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
if (strict && result.counts.warning > 0) {
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
/** One-line severity tally, or the clean-grammar message. */
|
|
27
|
+
function summaryLine(result) {
|
|
28
|
+
const { error, warning } = result.counts;
|
|
29
|
+
if (error + warning === 0) {
|
|
30
|
+
// "target type", not "target": the tally counts distinct TYPES reachable
|
|
31
|
+
// as a cross-reference target, not cross-reference properties. Several
|
|
32
|
+
// references can share one target type, so the bare word reads as though
|
|
33
|
+
// the lint had missed the rest.
|
|
34
|
+
return `No grammar-convention problems found (${result.checkedReferenceTargets} reference target type${plural(result.checkedReferenceTargets)} checked).`;
|
|
35
|
+
}
|
|
36
|
+
const parts = [];
|
|
37
|
+
if (error) {
|
|
38
|
+
parts.push(`${error} error${plural(error)}`);
|
|
39
|
+
}
|
|
40
|
+
if (warning) {
|
|
41
|
+
parts.push(`${warning} warning${plural(warning)}`);
|
|
42
|
+
}
|
|
43
|
+
return `${parts.join(', ')}.`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Render a grammar-convention lint result for the terminal. `json` emits the raw
|
|
47
|
+
* {@link GrammarLintResult} (the machine-readable CI contract); the default is a
|
|
48
|
+
* human report — one `severity [rule] message` line per finding — closing with
|
|
49
|
+
* the {@link summaryLine} tally.
|
|
50
|
+
*/
|
|
51
|
+
export function formatLintReport(result, options = {}) {
|
|
52
|
+
if (options.json) {
|
|
53
|
+
return JSON.stringify(result, undefined, 2);
|
|
54
|
+
}
|
|
55
|
+
const lines = [];
|
|
56
|
+
for (const finding of result.findings) {
|
|
57
|
+
lines.push(` ${finding.severity.padEnd(7)} [${finding.rule}] ${finding.message}`);
|
|
58
|
+
}
|
|
59
|
+
if (result.findings.length > 0) {
|
|
60
|
+
lines.push('');
|
|
61
|
+
}
|
|
62
|
+
lines.push(summaryLine(result));
|
|
63
|
+
return lines.join('\n');
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=lint-grammar-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-grammar-report.js","sourceRoot":"","sources":["../../src/commands/lint-grammar-report.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAMlF,0CAA0C;AAC1C,SAAS,MAAM,CAAC,KAAa;IAC1B,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAyB,EAAE,MAAM,GAAG,KAAK;IACnE,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,CAAC;IACZ,CAAC;IACD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,CAAC;IACZ,CAAC;IACD,OAAO,CAAC,CAAC;AACZ,CAAC;AAED,6DAA6D;AAC7D,SAAS,WAAW,CAAC,MAAyB;IAC3C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,IAAI,KAAK,GAAG,OAAO,KAAK,CAAC,EAAE,CAAC;QACzB,yEAAyE;QACzE,uEAAuE;QACvE,yEAAyE;QACzE,gCAAgC;QAChC,OAAO,yCAAyC,MAAM,CAAC,uBAAuB,yBAAyB,MAAM,CAC1G,MAAM,CAAC,uBAAuB,CAChC,YAAY,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,EAAE,CAAC;QACT,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACX,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,WAAW,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAyB,EAAE,UAA8B,EAAE;IACzF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAChC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { type DriverSpawnOptions } from './headless-harness.js';
|
|
10
|
+
/** Options for the {@link runLintGrammar} subcommand. */
|
|
11
|
+
export interface LintGrammarCommandOptions extends DriverSpawnOptions {
|
|
12
|
+
/** ESM module exporting a zero-arg `createServices(): { shared }` thunk. */
|
|
13
|
+
readonly servicesModule: string;
|
|
14
|
+
/** Property names that satisfy the nameability convention. Empty → the framework default `name`. */
|
|
15
|
+
readonly nameProperties?: readonly string[];
|
|
16
|
+
/** Emit the raw JSON result instead of the human report. */
|
|
17
|
+
readonly json?: boolean;
|
|
18
|
+
/** Also fail (non-zero exit) on warnings, not only errors. */
|
|
19
|
+
readonly strict?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Build the argv the driver child parses. Pure → unit-testable. */
|
|
22
|
+
export declare function buildLintGrammarDriverArgs(options: LintGrammarCommandOptions): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Headless grammar-convention lint — a CI gate that checks a head's grammar against
|
|
25
|
+
* the framework's expectations (nameable cross-reference targets, an entry rule) and
|
|
26
|
+
* exits non-zero when a violation is found (`--strict` also fails on warnings).
|
|
27
|
+
* Read-only: no workspace is built (the reflection is static once the head registers
|
|
28
|
+
* its language), so this subcommand takes only `--services` and the name-property
|
|
29
|
+
* overrides. The work runs in a spawned child that dynamic-imports the head's
|
|
30
|
+
* `createServices` module, keeping the binary language-agnostic.
|
|
31
|
+
*/
|
|
32
|
+
export declare function runLintGrammar(options: LintGrammarCommandOptions): Promise<void>;
|
|
33
|
+
//# sourceMappingURL=lint-grammar.d.ts.map
|