@hydranium/core 1.0.0-next.29 → 1.0.0-next.31
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/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
- package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.js +60 -22
- package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.d.ts +10 -6
- package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.js +15 -11
- package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
- package/lib/testing/fake-document.d.ts +14 -3
- package/lib/testing/fake-document.d.ts.map +1 -1
- package/lib/testing/fake-document.js +18 -3
- package/lib/testing/fake-document.js.map +1 -1
- package/package.json +5 -5
- package/src/langium/ast-extension/ast-node-builder.ts +66 -22
- package/src/langium/scope/hydranium-scope-provider.ts +15 -11
- package/src/testing/fake-document.ts +22 -4
|
@@ -68,15 +68,13 @@ export type AstNodeBuilder<TMap> = <TType extends string & keyof TMap>(typeConst
|
|
|
68
68
|
* AST-interface mapping, so call sites get full inference from the type
|
|
69
69
|
* constant alone — no explicit generic parameter at every call site.
|
|
70
70
|
*
|
|
71
|
-
* Runtime behaviour:
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* TS-augmented fields (declared via `declare module './generated/ast.js'`)
|
|
79
|
-
* are unaffected by the runtime defaulting but remain typed at call sites.
|
|
71
|
+
* Runtime behaviour: pre-fills every grammar-declared default (see
|
|
72
|
+
* {@link withTypeDefaults}) before merging the caller's `init`, so containment
|
|
73
|
+
* lists and `?=`-style boolean flags default automatically. TS-augmented fields
|
|
74
|
+
* (declared via `declare module './generated/ast.js'`) are unaffected by the
|
|
75
|
+
* runtime defaulting but remain typed at call sites.
|
|
76
|
+
*
|
|
77
|
+
* Use {@link buildAstNode} instead when the type name is only known at runtime.
|
|
80
78
|
*
|
|
81
79
|
* The init shape only relaxes array-typed fields to optional (via
|
|
82
80
|
* {@link ArrayKeys}) — there is no equivalent structural signal for "this
|
|
@@ -86,5 +84,30 @@ export type AstNodeBuilder<TMap> = <TType extends string & keyof TMap>(typeConst
|
|
|
86
84
|
* rather than a way to drop fields from the typed call site.
|
|
87
85
|
*/
|
|
88
86
|
export declare function makeAstNodeBuilder<TMap>(reflection: AstReflection): AstNodeBuilder<TMap>;
|
|
87
|
+
/**
|
|
88
|
+
* Build a node whose type is only known as a RUNTIME string.
|
|
89
|
+
*
|
|
90
|
+
* The typed {@link makeAstNodeBuilder} cannot express this: its `TMap` generic
|
|
91
|
+
* resolves the AST interface from a `$type` literal, and a type name that
|
|
92
|
+
* arrives over the wire — a protocol-layer reference request naming a node that
|
|
93
|
+
* does not exist yet — has no literal to resolve from. Callers that DO know the
|
|
94
|
+
* type at compile time want the typed builder, which checks their mandatory
|
|
95
|
+
* fields; this one checks nothing beyond the reflection lookup.
|
|
96
|
+
*
|
|
97
|
+
* Applies the same reflection-driven defaulting, so a node built here carries
|
|
98
|
+
* grammar-declared containment arrays rather than leaving them `undefined`. An
|
|
99
|
+
* unknown type name yields a node with `$type` and whatever `init` supplied,
|
|
100
|
+
* because reflection answers no metadata for it and refusing would turn a
|
|
101
|
+
* permissive lookup into a throw at a call site that can only guess.
|
|
102
|
+
*
|
|
103
|
+
* **The `type` argument is authoritative: `init` cannot rebind `$type`.** The
|
|
104
|
+
* typed builder gets this for free — `AstNodeInit` omits `$type`, so a call site
|
|
105
|
+
* cannot reach it — but here `init` is loosely typed, and the case that needs
|
|
106
|
+
* the guarantee is RETYPING: a caller spreading an existing node to produce one
|
|
107
|
+
* of a different type (`{ ...source }`) carries the SOURCE's `$type` in, which
|
|
108
|
+
* would silently win over the type actually requested and hand back a node of
|
|
109
|
+
* the wrong type with no error anywhere.
|
|
110
|
+
*/
|
|
111
|
+
export declare function buildAstNode<TAst extends AstNode = AstNode>(reflection: AstReflection, type: string, init?: Partial<AstNode> & Record<string, unknown>): TAst;
|
|
89
112
|
export {};
|
|
90
113
|
//# sourceMappingURL=ast-node-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-node-builder.d.ts","sourceRoot":"","sources":["../../../src/langium/ast-extension/ast-node-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC3D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACxB;AAED;;;;;GAKG;AACH,KAAK,SAAS,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK;CAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAEnG;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,oBAAoB,GAAG,iBAAiB,CAAC,CAAC,GAAG;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEL;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,IAAI,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,EAClE,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,EACpC,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,EAChD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;AAEnC
|
|
1
|
+
{"version":3,"file":"ast-node-builder.d.ts","sourceRoot":"","sources":["../../../src/langium/ast-extension/ast-node-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC3D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACxB;AAED;;;;;GAKG;AACH,KAAK,SAAS,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK;CAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAEnG;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,oBAAoB,GAAG,iBAAiB,CAAC,CAAC,GAAG;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEL;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,IAAI,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,EAClE,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,EACpC,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,EAChD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,CAexF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO,EACxD,UAAU,EAAE,aAAa,EACzB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjD,IAAI,CAON"}
|
|
@@ -17,15 +17,13 @@
|
|
|
17
17
|
* AST-interface mapping, so call sites get full inference from the type
|
|
18
18
|
* constant alone — no explicit generic parameter at every call site.
|
|
19
19
|
*
|
|
20
|
-
* Runtime behaviour:
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* TS-augmented fields (declared via `declare module './generated/ast.js'`)
|
|
28
|
-
* are unaffected by the runtime defaulting but remain typed at call sites.
|
|
20
|
+
* Runtime behaviour: pre-fills every grammar-declared default (see
|
|
21
|
+
* {@link withTypeDefaults}) before merging the caller's `init`, so containment
|
|
22
|
+
* lists and `?=`-style boolean flags default automatically. TS-augmented fields
|
|
23
|
+
* (declared via `declare module './generated/ast.js'`) are unaffected by the
|
|
24
|
+
* runtime defaulting but remain typed at call sites.
|
|
25
|
+
*
|
|
26
|
+
* Use {@link buildAstNode} instead when the type name is only known at runtime.
|
|
29
27
|
*
|
|
30
28
|
* The init shape only relaxes array-typed fields to optional (via
|
|
31
29
|
* {@link ArrayKeys}) — there is no equivalent structural signal for "this
|
|
@@ -36,19 +34,7 @@
|
|
|
36
34
|
*/
|
|
37
35
|
export function makeAstNodeBuilder(reflection) {
|
|
38
36
|
return function astNode(typeConstant, init, extras) {
|
|
39
|
-
const
|
|
40
|
-
const result = { $type: typeConstant.$type };
|
|
41
|
-
if (meta?.properties) {
|
|
42
|
-
for (const [propName, propInfo] of Object.entries(meta.properties)) {
|
|
43
|
-
const defaultValue = propInfo.defaultValue;
|
|
44
|
-
if (defaultValue === undefined) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
// Arrays are duplicated so each node carries its own mutable instance;
|
|
48
|
-
// scalars are immutable and safe to copy by reference.
|
|
49
|
-
result[propName] = Array.isArray(defaultValue) ? [...defaultValue] : defaultValue;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
37
|
+
const result = withTypeDefaults(reflection, typeConstant.$type);
|
|
52
38
|
Object.assign(result, init);
|
|
53
39
|
if (extras) {
|
|
54
40
|
// Extras win over init: this is the explicit escape hatch, so when a
|
|
@@ -58,4 +44,56 @@ export function makeAstNodeBuilder(reflection) {
|
|
|
58
44
|
return result;
|
|
59
45
|
};
|
|
60
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a node whose type is only known as a RUNTIME string.
|
|
49
|
+
*
|
|
50
|
+
* The typed {@link makeAstNodeBuilder} cannot express this: its `TMap` generic
|
|
51
|
+
* resolves the AST interface from a `$type` literal, and a type name that
|
|
52
|
+
* arrives over the wire — a protocol-layer reference request naming a node that
|
|
53
|
+
* does not exist yet — has no literal to resolve from. Callers that DO know the
|
|
54
|
+
* type at compile time want the typed builder, which checks their mandatory
|
|
55
|
+
* fields; this one checks nothing beyond the reflection lookup.
|
|
56
|
+
*
|
|
57
|
+
* Applies the same reflection-driven defaulting, so a node built here carries
|
|
58
|
+
* grammar-declared containment arrays rather than leaving them `undefined`. An
|
|
59
|
+
* unknown type name yields a node with `$type` and whatever `init` supplied,
|
|
60
|
+
* because reflection answers no metadata for it and refusing would turn a
|
|
61
|
+
* permissive lookup into a throw at a call site that can only guess.
|
|
62
|
+
*
|
|
63
|
+
* **The `type` argument is authoritative: `init` cannot rebind `$type`.** The
|
|
64
|
+
* typed builder gets this for free — `AstNodeInit` omits `$type`, so a call site
|
|
65
|
+
* cannot reach it — but here `init` is loosely typed, and the case that needs
|
|
66
|
+
* the guarantee is RETYPING: a caller spreading an existing node to produce one
|
|
67
|
+
* of a different type (`{ ...source }`) carries the SOURCE's `$type` in, which
|
|
68
|
+
* would silently win over the type actually requested and hand back a node of
|
|
69
|
+
* the wrong type with no error anywhere.
|
|
70
|
+
*/
|
|
71
|
+
export function buildAstNode(reflection, type, init) {
|
|
72
|
+
const result = withTypeDefaults(reflection, type);
|
|
73
|
+
if (init) {
|
|
74
|
+
Object.assign(result, init);
|
|
75
|
+
result.$type = type;
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Seed a node with `$type` plus every property the grammar declares a default
|
|
81
|
+
* for. Array defaults are materialised as a fresh `[]` per call — never shared
|
|
82
|
+
* with the metadata's own array instance, which downstream callers mutate —
|
|
83
|
+
* while scalar defaults are copied as-is since they are immutable.
|
|
84
|
+
*/
|
|
85
|
+
function withTypeDefaults(reflection, type) {
|
|
86
|
+
const result = { $type: type };
|
|
87
|
+
const meta = reflection.getTypeMetaData(type);
|
|
88
|
+
if (meta?.properties) {
|
|
89
|
+
for (const [propName, propInfo] of Object.entries(meta.properties)) {
|
|
90
|
+
const defaultValue = propInfo.defaultValue;
|
|
91
|
+
if (defaultValue === undefined) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
result[propName] = Array.isArray(defaultValue) ? [...defaultValue] : defaultValue;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
61
99
|
//# sourceMappingURL=ast-node-builder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-node-builder.js","sourceRoot":"","sources":["../../../src/langium/ast-extension/ast-node-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AA8DlF
|
|
1
|
+
{"version":3,"file":"ast-node-builder.js","sourceRoot":"","sources":["../../../src/langium/ast-extension/ast-node-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AA8DlF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,kBAAkB,CAAO,UAAyB;IAC/D,OAAO,SAAS,OAAO,CACpB,YAAoC,EACpC,IAAgD,EAChD,MAAgC;QAEhC,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC5B,IAAI,MAAM,EAAE,CAAC;YACV,qEAAqE;YACrE,+DAA+D;YAC/D,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,MAAkD,CAAC;IAC7D,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,YAAY,CACzB,UAAyB,EACzB,IAAY,EACZ,IAAiD;IAEjD,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAClD,IAAI,IAAI,EAAE,CAAC;QACR,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC5B,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;IACvB,CAAC;IACD,OAAO,MAAyB,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,UAAyB,EAAE,IAAY;IAC9D,MAAM,MAAM,GAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAClE,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;YAC3C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC9B,SAAS;YACZ,CAAC;YACD,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;QACrF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AACjB,CAAC"}
|
|
@@ -308,12 +308,13 @@ export declare class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
308
308
|
* Convert a protocol-layer {@link ReferenceContext} into a Langium
|
|
309
309
|
* {@link ReferenceInfo} the rest of the scope/linking machinery accepts.
|
|
310
310
|
*
|
|
311
|
-
* Walks `syntheticPath` by FABRICATING a
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* the
|
|
311
|
+
* Walks `syntheticPath` by FABRICATING a stub per step, so a scope can be
|
|
312
|
+
* queried for an element that does not exist yet — which is what synthetic
|
|
313
|
+
* paths are for. A stub carries the grammar's declared defaults and nothing
|
|
314
|
+
* else, so its containment lists are present but EMPTY: a caller that needs
|
|
315
|
+
* to read a populated collection off the leaf wants
|
|
316
|
+
* {@link resolveReferenceSource} instead, which walks the same path into the
|
|
317
|
+
* real tree.
|
|
317
318
|
*
|
|
318
319
|
* Throws if the context references an unresolvable source; callers
|
|
319
320
|
* that prefer a soft failure should catch and fall back to
|
|
@@ -372,6 +373,9 @@ export declare class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
372
373
|
* `createEmptyDocument`. Overriding is still open to a consumer whose
|
|
373
374
|
* "container" is an inner element rather than the parse root, or one that
|
|
374
375
|
* deliberately declines to answer for an absent document.
|
|
376
|
+
*
|
|
377
|
+
* The stub carries the grammar's declared defaults, so an extension reading a
|
|
378
|
+
* containment list off it sees an empty array rather than `undefined`.
|
|
375
379
|
*/
|
|
376
380
|
protected resolveSyntheticSource(source: SyntheticSource): AstNode | undefined;
|
|
377
381
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydranium-scope-provider.d.ts","sourceRoot":"","sources":["../../../src/langium/scope/hydranium-scope-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EACJ,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EAKtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACJ,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAEnB,oBAAoB,EAEpB,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,YAAY,EAEjB,KAAK,GAAG,EAER,cAAc,EAEhB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"hydranium-scope-provider.d.ts","sourceRoot":"","sources":["../../../src/langium/scope/hydranium-scope-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
import { isDocumentSource, isElementSource, isReferenceContext, isSyntheticSource } from '@hydranium/protocol';
|
|
10
10
|
import { AstUtils, DefaultScopeProvider, MapScope, StreamScope, UriUtils, WorkspaceCache, stream } from '@hydranium/langium';
|
|
11
|
+
import { buildAstNode } from '../ast-extension/ast-node-builder.js';
|
|
11
12
|
import { isTieredDescription } from './scoped-ast-node-description.js';
|
|
12
13
|
/**
|
|
13
14
|
* Per-language scope provider that owns the full scope chain in ONE
|
|
@@ -358,12 +359,13 @@ export class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
358
359
|
* Convert a protocol-layer {@link ReferenceContext} into a Langium
|
|
359
360
|
* {@link ReferenceInfo} the rest of the scope/linking machinery accepts.
|
|
360
361
|
*
|
|
361
|
-
* Walks `syntheticPath` by FABRICATING a
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* the
|
|
362
|
+
* Walks `syntheticPath` by FABRICATING a stub per step, so a scope can be
|
|
363
|
+
* queried for an element that does not exist yet — which is what synthetic
|
|
364
|
+
* paths are for. A stub carries the grammar's declared defaults and nothing
|
|
365
|
+
* else, so its containment lists are present but EMPTY: a caller that needs
|
|
366
|
+
* to read a populated collection off the leaf wants
|
|
367
|
+
* {@link resolveReferenceSource} instead, which walks the same path into the
|
|
368
|
+
* real tree.
|
|
367
369
|
*
|
|
368
370
|
* Throws if the context references an unresolvable source; callers
|
|
369
371
|
* that prefer a soft failure should catch and fall back to
|
|
@@ -375,16 +377,15 @@ export class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
375
377
|
throw new Error('Invalid reference source');
|
|
376
378
|
}
|
|
377
379
|
for (const step of ctx.syntheticPath ?? []) {
|
|
378
|
-
container = {
|
|
380
|
+
container = buildAstNode(this.services.shared.AstReflection, step.type, {
|
|
379
381
|
$container: container,
|
|
380
382
|
$containerProperty: step.containerProperty,
|
|
381
383
|
// Part of Langium's own container contract, so a stub that omits it
|
|
382
384
|
// is an under-specified node: anything reading position off the
|
|
383
385
|
// chain (a key provider, an adopter scope extension) sees
|
|
384
386
|
// `undefined` where the caller named a slot.
|
|
385
|
-
$containerIndex: step.index
|
|
386
|
-
|
|
387
|
-
};
|
|
387
|
+
$containerIndex: step.index
|
|
388
|
+
});
|
|
388
389
|
}
|
|
389
390
|
return {
|
|
390
391
|
reference: { $refText: '', ref: undefined },
|
|
@@ -491,12 +492,15 @@ export class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
491
492
|
* `createEmptyDocument`. Overriding is still open to a consumer whose
|
|
492
493
|
* "container" is an inner element rather than the parse root, or one that
|
|
493
494
|
* deliberately declines to answer for an absent document.
|
|
495
|
+
*
|
|
496
|
+
* The stub carries the grammar's declared defaults, so an extension reading a
|
|
497
|
+
* containment list off it sees an empty array rather than `undefined`.
|
|
494
498
|
*/
|
|
495
499
|
resolveSyntheticSource(source) {
|
|
496
500
|
const uri = UriUtils.toUri(source.uri);
|
|
497
501
|
const document = this.langiumDocuments.getDocument(uri) ??
|
|
498
502
|
this.langiumDocuments.createEmptyDocument(uri, this.services.LanguageMetaData.languageId);
|
|
499
|
-
return
|
|
503
|
+
return buildAstNode(this.services.shared.AstReflection, source.type, { $container: document.parseResult.value });
|
|
500
504
|
}
|
|
501
505
|
/**
|
|
502
506
|
* Resolve the semantic root node of the document at `uri`. Default: looks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydranium-scope-provider.js","sourceRoot":"","sources":["../../../src/langium/scope/hydranium-scope-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAMJ,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIJ,QAAQ,EACR,oBAAoB,EACpB,QAAQ,EAIR,WAAW,EAEX,QAAQ,EACR,cAAc,EACd,MAAM,EACR,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"hydranium-scope-provider.js","sourceRoot":"","sources":["../../../src/langium/scope/hydranium-scope-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
|
-
import { DocumentState, type AstNode, type LangiumDocument, type URI } from '@hydranium/langium';
|
|
9
|
+
import { DocumentState, type AstNode, type AstReflection, type LangiumDocument, type URI } from '@hydranium/langium';
|
|
10
10
|
/**
|
|
11
11
|
* Build a typed AST-node fixture for unit tests.
|
|
12
12
|
*
|
|
@@ -21,13 +21,24 @@ import { DocumentState, type AstNode, type LangiumDocument, type URI } from '@hy
|
|
|
21
21
|
* framework synthetic node, and marking it would change scope/index behaviour.
|
|
22
22
|
* A test that wants a genuine synthetic node calls `markSynthetic` explicitly.
|
|
23
23
|
*
|
|
24
|
+
* **Without a `reflection`, the fixture carries only what the test spells out**,
|
|
25
|
+
* which is a shape production never produces: a parsed or built node always has
|
|
26
|
+
* its grammar-declared containment arrays, so a fixture that omits one lets a
|
|
27
|
+
* test pass against an impossible node, and lets code that walks a list crash
|
|
28
|
+
* only under test. Pass the grammar's reflection whenever the type is a real
|
|
29
|
+
* one and the code under test reads a collection off it. Fixtures typed against
|
|
30
|
+
* ad-hoc names have no reflection to pass and keep the plain form.
|
|
31
|
+
*
|
|
24
32
|
* @param node the node shape — `$type` is required; every other property is a
|
|
25
33
|
* value the test cares about (`$container`, cross-reference values, internal
|
|
26
|
-
* `_id` fields, …).
|
|
34
|
+
* `_id` fields, …).
|
|
35
|
+
* @param reflection when given, pre-fills the grammar's declared defaults the
|
|
36
|
+
* same way {@link buildAstNode} does, and the result is a fresh object rather
|
|
37
|
+
* than `node` itself. Omitted, `node` is returned by reference.
|
|
27
38
|
*/
|
|
28
39
|
export declare function makeFakeAstNode<TAst extends AstNode = AstNode>(node: {
|
|
29
40
|
$type: string;
|
|
30
|
-
} & Record<string, unknown
|
|
41
|
+
} & Record<string, unknown>, reflection?: AstReflection): TAst;
|
|
31
42
|
/**
|
|
32
43
|
* Options for {@link makeFakeDocument}.
|
|
33
44
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-document.d.ts","sourceRoot":"","sources":["../../src/testing/fake-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAY,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"fake-document.d.ts","sourceRoot":"","sources":["../../src/testing/fake-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAY,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAG/H;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO,EAC3D,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjD,UAAU,CAAC,EAAE,aAAa,GAC1B,IAAI,CAKN;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB,CAAC,IAAI,SAAS,OAAO,EAAE,WAAW;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,kFAAkF;IAClF,WAAW,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5D;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC;CACvD;AAiBD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO,EAAE,WAAW,GAAG,OAAO,EACnF,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,mBAAmB,CAAC,IAAI,EAAE,WAAW,CAAM,GACpD,eAAe,CAAC,IAAI,CAAC,CA2BvB"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
import { DocumentState, UriUtils } from '@hydranium/langium';
|
|
10
|
+
import { buildAstNode } from '../langium/ast-extension/ast-node-builder.js';
|
|
10
11
|
/**
|
|
11
12
|
* Build a typed AST-node fixture for unit tests.
|
|
12
13
|
*
|
|
@@ -21,12 +22,26 @@ import { DocumentState, UriUtils } from '@hydranium/langium';
|
|
|
21
22
|
* framework synthetic node, and marking it would change scope/index behaviour.
|
|
22
23
|
* A test that wants a genuine synthetic node calls `markSynthetic` explicitly.
|
|
23
24
|
*
|
|
25
|
+
* **Without a `reflection`, the fixture carries only what the test spells out**,
|
|
26
|
+
* which is a shape production never produces: a parsed or built node always has
|
|
27
|
+
* its grammar-declared containment arrays, so a fixture that omits one lets a
|
|
28
|
+
* test pass against an impossible node, and lets code that walks a list crash
|
|
29
|
+
* only under test. Pass the grammar's reflection whenever the type is a real
|
|
30
|
+
* one and the code under test reads a collection off it. Fixtures typed against
|
|
31
|
+
* ad-hoc names have no reflection to pass and keep the plain form.
|
|
32
|
+
*
|
|
24
33
|
* @param node the node shape — `$type` is required; every other property is a
|
|
25
34
|
* value the test cares about (`$container`, cross-reference values, internal
|
|
26
|
-
* `_id` fields, …).
|
|
35
|
+
* `_id` fields, …).
|
|
36
|
+
* @param reflection when given, pre-fills the grammar's declared defaults the
|
|
37
|
+
* same way {@link buildAstNode} does, and the result is a fresh object rather
|
|
38
|
+
* than `node` itself. Omitted, `node` is returned by reference.
|
|
27
39
|
*/
|
|
28
|
-
export function makeFakeAstNode(node) {
|
|
29
|
-
|
|
40
|
+
export function makeFakeAstNode(node, reflection) {
|
|
41
|
+
if (!reflection) {
|
|
42
|
+
return node;
|
|
43
|
+
}
|
|
44
|
+
return buildAstNode(reflection, node.$type, node);
|
|
30
45
|
}
|
|
31
46
|
/**
|
|
32
47
|
* Serialise `root` for the fake document's default text. AST fixtures routinely
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-document.js","sourceRoot":"","sources":["../../src/testing/fake-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"fake-document.js","sourceRoot":"","sources":["../../src/testing/fake-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,aAAa,EAA0D,QAAQ,EAAY,MAAM,oBAAoB,CAAC;AAC/H,OAAO,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,eAAe,CAC5B,IAAiD,EACjD,UAA0B;IAE1B,IAAI,CAAC,UAAU,EAAE,CAAC;QACf,OAAO,IAAuB,CAAC;IAClC,CAAC;IACD,OAAO,YAAY,CAAO,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC3D,CAAC;AA+BD;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,IAAa;IACrC,IAAI,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAG,IAAwC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC7B,GAAiB,EACjB,IAAU,EACV,UAAkD,EAAE;IAEpD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG;QACd,GAAG,EAAE,MAAM;QACX,WAAW,EAAE;YACV,KAAK,EAAE,IAAI;YACX,YAAY,EAAE,EAAE;YAChB,WAAW,EAAE,EAAE;YACf,GAAG,OAAO,CAAC,WAAW;SACxB;QACD,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI;YACnC,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE;YACtB,OAAO;YACP,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI;SACrB;QACD,WAAW,EAAE,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAU;QACjD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,aAAa,CAAC,SAAS;KACb,CAAC;IACtC,0EAA0E;IAC1E,qEAAqE;IACrE,sEAAsE;IACtE,iCAAiC;IAChC,IAA8C,CAAC,SAAS,GAAG,QAAQ,CAAC;IACrE,OAAO,QAAQ,CAAC;AACnB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/core",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.31",
|
|
4
4
|
"description": "Foundational runtime of the hydranium framework: AST coordination layer (services, integrity, AST extension, serialization, multi-client documents) plus the LSP textual head at the /lsp subpath. Consumed by protocol-head packages (@hydranium/data-server, @hydranium/glsp-server).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hydranium",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"diff": "^5.2.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@hydranium/langium": "1.0.0-next.
|
|
108
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
107
|
+
"@hydranium/langium": "1.0.0-next.31",
|
|
108
|
+
"@hydranium/protocol": "1.0.0-next.31",
|
|
109
109
|
"@playwright/test": "^1.40.0",
|
|
110
110
|
"@types/diff": "^5.2.0",
|
|
111
111
|
"rimraf": "^5.0.0",
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
"vscode-languageserver-types": "^3.17.5"
|
|
118
118
|
},
|
|
119
119
|
"peerDependencies": {
|
|
120
|
-
"@hydranium/langium": "1.0.0-next.
|
|
121
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
120
|
+
"@hydranium/langium": "1.0.0-next.31",
|
|
121
|
+
"@hydranium/protocol": "1.0.0-next.31",
|
|
122
122
|
"@playwright/test": "^1.40.0",
|
|
123
123
|
"vscode-jsonrpc": "9.0.1",
|
|
124
124
|
"vscode-languageserver": "~10.0.1",
|
|
@@ -78,15 +78,13 @@ export type AstNodeBuilder<TMap> = <TType extends string & keyof TMap>(
|
|
|
78
78
|
* AST-interface mapping, so call sites get full inference from the type
|
|
79
79
|
* constant alone — no explicit generic parameter at every call site.
|
|
80
80
|
*
|
|
81
|
-
* Runtime behaviour:
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* TS-augmented fields (declared via `declare module './generated/ast.js'`)
|
|
89
|
-
* are unaffected by the runtime defaulting but remain typed at call sites.
|
|
81
|
+
* Runtime behaviour: pre-fills every grammar-declared default (see
|
|
82
|
+
* {@link withTypeDefaults}) before merging the caller's `init`, so containment
|
|
83
|
+
* lists and `?=`-style boolean flags default automatically. TS-augmented fields
|
|
84
|
+
* (declared via `declare module './generated/ast.js'`) are unaffected by the
|
|
85
|
+
* runtime defaulting but remain typed at call sites.
|
|
86
|
+
*
|
|
87
|
+
* Use {@link buildAstNode} instead when the type name is only known at runtime.
|
|
90
88
|
*
|
|
91
89
|
* The init shape only relaxes array-typed fields to optional (via
|
|
92
90
|
* {@link ArrayKeys}) — there is no equivalent structural signal for "this
|
|
@@ -101,19 +99,7 @@ export function makeAstNodeBuilder<TMap>(reflection: AstReflection): AstNodeBuil
|
|
|
101
99
|
init: AstNodeInit<Extract<TMap[TType], AstNode>>,
|
|
102
100
|
extras?: Record<string, unknown>
|
|
103
101
|
): Extract<TMap[TType], AstNode> {
|
|
104
|
-
const
|
|
105
|
-
const result: Record<string, unknown> = { $type: typeConstant.$type };
|
|
106
|
-
if (meta?.properties) {
|
|
107
|
-
for (const [propName, propInfo] of Object.entries(meta.properties)) {
|
|
108
|
-
const defaultValue = propInfo.defaultValue;
|
|
109
|
-
if (defaultValue === undefined) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
// Arrays are duplicated so each node carries its own mutable instance;
|
|
113
|
-
// scalars are immutable and safe to copy by reference.
|
|
114
|
-
result[propName] = Array.isArray(defaultValue) ? [...defaultValue] : defaultValue;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
102
|
+
const result = withTypeDefaults(reflection, typeConstant.$type);
|
|
117
103
|
Object.assign(result, init);
|
|
118
104
|
if (extras) {
|
|
119
105
|
// Extras win over init: this is the explicit escape hatch, so when a
|
|
@@ -123,3 +109,61 @@ export function makeAstNodeBuilder<TMap>(reflection: AstReflection): AstNodeBuil
|
|
|
123
109
|
return result as unknown as Extract<TMap[TType], AstNode>;
|
|
124
110
|
};
|
|
125
111
|
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Build a node whose type is only known as a RUNTIME string.
|
|
115
|
+
*
|
|
116
|
+
* The typed {@link makeAstNodeBuilder} cannot express this: its `TMap` generic
|
|
117
|
+
* resolves the AST interface from a `$type` literal, and a type name that
|
|
118
|
+
* arrives over the wire — a protocol-layer reference request naming a node that
|
|
119
|
+
* does not exist yet — has no literal to resolve from. Callers that DO know the
|
|
120
|
+
* type at compile time want the typed builder, which checks their mandatory
|
|
121
|
+
* fields; this one checks nothing beyond the reflection lookup.
|
|
122
|
+
*
|
|
123
|
+
* Applies the same reflection-driven defaulting, so a node built here carries
|
|
124
|
+
* grammar-declared containment arrays rather than leaving them `undefined`. An
|
|
125
|
+
* unknown type name yields a node with `$type` and whatever `init` supplied,
|
|
126
|
+
* because reflection answers no metadata for it and refusing would turn a
|
|
127
|
+
* permissive lookup into a throw at a call site that can only guess.
|
|
128
|
+
*
|
|
129
|
+
* **The `type` argument is authoritative: `init` cannot rebind `$type`.** The
|
|
130
|
+
* typed builder gets this for free — `AstNodeInit` omits `$type`, so a call site
|
|
131
|
+
* cannot reach it — but here `init` is loosely typed, and the case that needs
|
|
132
|
+
* the guarantee is RETYPING: a caller spreading an existing node to produce one
|
|
133
|
+
* of a different type (`{ ...source }`) carries the SOURCE's `$type` in, which
|
|
134
|
+
* would silently win over the type actually requested and hand back a node of
|
|
135
|
+
* the wrong type with no error anywhere.
|
|
136
|
+
*/
|
|
137
|
+
export function buildAstNode<TAst extends AstNode = AstNode>(
|
|
138
|
+
reflection: AstReflection,
|
|
139
|
+
type: string,
|
|
140
|
+
init?: Partial<AstNode> & Record<string, unknown>
|
|
141
|
+
): TAst {
|
|
142
|
+
const result = withTypeDefaults(reflection, type);
|
|
143
|
+
if (init) {
|
|
144
|
+
Object.assign(result, init);
|
|
145
|
+
result.$type = type;
|
|
146
|
+
}
|
|
147
|
+
return result as unknown as TAst;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Seed a node with `$type` plus every property the grammar declares a default
|
|
152
|
+
* for. Array defaults are materialised as a fresh `[]` per call — never shared
|
|
153
|
+
* with the metadata's own array instance, which downstream callers mutate —
|
|
154
|
+
* while scalar defaults are copied as-is since they are immutable.
|
|
155
|
+
*/
|
|
156
|
+
function withTypeDefaults(reflection: AstReflection, type: string): Record<string, unknown> {
|
|
157
|
+
const result: Record<string, unknown> = { $type: type };
|
|
158
|
+
const meta = reflection.getTypeMetaData(type);
|
|
159
|
+
if (meta?.properties) {
|
|
160
|
+
for (const [propName, propInfo] of Object.entries(meta.properties)) {
|
|
161
|
+
const defaultValue = propInfo.defaultValue;
|
|
162
|
+
if (defaultValue === undefined) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
result[propName] = Array.isArray(defaultValue) ? [...defaultValue] : defaultValue;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
WorkspaceCache,
|
|
35
35
|
stream
|
|
36
36
|
} from '@hydranium/langium';
|
|
37
|
+
import { buildAstNode } from '../ast-extension/ast-node-builder.js';
|
|
37
38
|
import { type LogNameOptions } from '../diagnostics/logger.js';
|
|
38
39
|
import { type HydraniumLanguageServices } from '../language-module.js';
|
|
39
40
|
import { type NameProvider } from '../naming/name-provider.js';
|
|
@@ -469,12 +470,13 @@ export class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
469
470
|
* Convert a protocol-layer {@link ReferenceContext} into a Langium
|
|
470
471
|
* {@link ReferenceInfo} the rest of the scope/linking machinery accepts.
|
|
471
472
|
*
|
|
472
|
-
* Walks `syntheticPath` by FABRICATING a
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
* the
|
|
473
|
+
* Walks `syntheticPath` by FABRICATING a stub per step, so a scope can be
|
|
474
|
+
* queried for an element that does not exist yet — which is what synthetic
|
|
475
|
+
* paths are for. A stub carries the grammar's declared defaults and nothing
|
|
476
|
+
* else, so its containment lists are present but EMPTY: a caller that needs
|
|
477
|
+
* to read a populated collection off the leaf wants
|
|
478
|
+
* {@link resolveReferenceSource} instead, which walks the same path into the
|
|
479
|
+
* real tree.
|
|
478
480
|
*
|
|
479
481
|
* Throws if the context references an unresolvable source; callers
|
|
480
482
|
* that prefer a soft failure should catch and fall back to
|
|
@@ -486,16 +488,15 @@ export class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
486
488
|
throw new Error('Invalid reference source');
|
|
487
489
|
}
|
|
488
490
|
for (const step of ctx.syntheticPath ?? []) {
|
|
489
|
-
container = {
|
|
491
|
+
container = buildAstNode(this.services.shared.AstReflection, step.type, {
|
|
490
492
|
$container: container,
|
|
491
493
|
$containerProperty: step.containerProperty,
|
|
492
494
|
// Part of Langium's own container contract, so a stub that omits it
|
|
493
495
|
// is an under-specified node: anything reading position off the
|
|
494
496
|
// chain (a key provider, an adopter scope extension) sees
|
|
495
497
|
// `undefined` where the caller named a slot.
|
|
496
|
-
$containerIndex: step.index
|
|
497
|
-
|
|
498
|
-
};
|
|
498
|
+
$containerIndex: step.index
|
|
499
|
+
});
|
|
499
500
|
}
|
|
500
501
|
return {
|
|
501
502
|
reference: { $refText: '', ref: undefined },
|
|
@@ -605,13 +606,16 @@ export class HydraniumScopeProvider extends DefaultScopeProvider {
|
|
|
605
606
|
* `createEmptyDocument`. Overriding is still open to a consumer whose
|
|
606
607
|
* "container" is an inner element rather than the parse root, or one that
|
|
607
608
|
* deliberately declines to answer for an absent document.
|
|
609
|
+
*
|
|
610
|
+
* The stub carries the grammar's declared defaults, so an extension reading a
|
|
611
|
+
* containment list off it sees an empty array rather than `undefined`.
|
|
608
612
|
*/
|
|
609
613
|
protected resolveSyntheticSource(source: SyntheticSource): AstNode | undefined {
|
|
610
614
|
const uri = UriUtils.toUri(source.uri);
|
|
611
615
|
const document =
|
|
612
616
|
this.langiumDocuments.getDocument(uri) ??
|
|
613
617
|
this.langiumDocuments.createEmptyDocument(uri, this.services.LanguageMetaData.languageId);
|
|
614
|
-
return
|
|
618
|
+
return buildAstNode(this.services.shared.AstReflection, source.type, { $container: document.parseResult.value });
|
|
615
619
|
}
|
|
616
620
|
|
|
617
621
|
/**
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
|
-
import { DocumentState, type AstNode, type LangiumDocument, UriUtils, type URI } from '@hydranium/langium';
|
|
10
|
+
import { DocumentState, type AstNode, type AstReflection, type LangiumDocument, UriUtils, type URI } from '@hydranium/langium';
|
|
11
|
+
import { buildAstNode } from '../langium/ast-extension/ast-node-builder.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Build a typed AST-node fixture for unit tests.
|
|
@@ -23,12 +24,29 @@ import { DocumentState, type AstNode, type LangiumDocument, UriUtils, type URI }
|
|
|
23
24
|
* framework synthetic node, and marking it would change scope/index behaviour.
|
|
24
25
|
* A test that wants a genuine synthetic node calls `markSynthetic` explicitly.
|
|
25
26
|
*
|
|
27
|
+
* **Without a `reflection`, the fixture carries only what the test spells out**,
|
|
28
|
+
* which is a shape production never produces: a parsed or built node always has
|
|
29
|
+
* its grammar-declared containment arrays, so a fixture that omits one lets a
|
|
30
|
+
* test pass against an impossible node, and lets code that walks a list crash
|
|
31
|
+
* only under test. Pass the grammar's reflection whenever the type is a real
|
|
32
|
+
* one and the code under test reads a collection off it. Fixtures typed against
|
|
33
|
+
* ad-hoc names have no reflection to pass and keep the plain form.
|
|
34
|
+
*
|
|
26
35
|
* @param node the node shape — `$type` is required; every other property is a
|
|
27
36
|
* value the test cares about (`$container`, cross-reference values, internal
|
|
28
|
-
* `_id` fields, …).
|
|
37
|
+
* `_id` fields, …).
|
|
38
|
+
* @param reflection when given, pre-fills the grammar's declared defaults the
|
|
39
|
+
* same way {@link buildAstNode} does, and the result is a fresh object rather
|
|
40
|
+
* than `node` itself. Omitted, `node` is returned by reference.
|
|
29
41
|
*/
|
|
30
|
-
export function makeFakeAstNode<TAst extends AstNode = AstNode>(
|
|
31
|
-
|
|
42
|
+
export function makeFakeAstNode<TAst extends AstNode = AstNode>(
|
|
43
|
+
node: { $type: string } & Record<string, unknown>,
|
|
44
|
+
reflection?: AstReflection
|
|
45
|
+
): TAst {
|
|
46
|
+
if (!reflection) {
|
|
47
|
+
return node as unknown as TAst;
|
|
48
|
+
}
|
|
49
|
+
return buildAstNode<TAst>(reflection, node.$type, node);
|
|
32
50
|
}
|
|
33
51
|
|
|
34
52
|
/**
|