@hydranium/core 1.0.0-next.289 → 1.0.0-next.298

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.
Files changed (38) hide show
  1. package/README.md +1 -0
  2. package/lib/browser/index.d.ts +10 -0
  3. package/lib/browser/index.d.ts.map +1 -0
  4. package/lib/browser/index.js +14 -0
  5. package/lib/browser/index.js.map +1 -0
  6. package/lib/browser/indexeddb-file-system-store.d.ts +82 -0
  7. package/lib/browser/indexeddb-file-system-store.d.ts.map +1 -0
  8. package/lib/browser/indexeddb-file-system-store.js +181 -0
  9. package/lib/browser/indexeddb-file-system-store.js.map +1 -0
  10. package/lib/langium/ast-extension/ast-extension-service.d.ts +39 -31
  11. package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
  12. package/lib/langium/ast-extension/ast-extension-service.js +45 -19
  13. package/lib/langium/ast-extension/ast-extension-service.js.map +1 -1
  14. package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts +8 -8
  15. package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts.map +1 -1
  16. package/lib/langium/build-phase-pass/build-phase-pass-service.js +25 -16
  17. package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
  18. package/lib/langium/build-phase-pass/build-phase-pass.d.ts +19 -7
  19. package/lib/langium/build-phase-pass/build-phase-pass.d.ts.map +1 -1
  20. package/lib/langium/build-phase-pass/build-phase-pass.js +20 -0
  21. package/lib/langium/build-phase-pass/build-phase-pass.js.map +1 -1
  22. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  23. package/lib/langium/document-builder/build-pipeline-integration.js +11 -40
  24. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  25. package/lib/langium/residency/cst-residency-service.js +1 -1
  26. package/lib/langium/workspace/persistent-file-system-provider.d.ts +8 -0
  27. package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
  28. package/lib/langium/workspace/persistent-file-system-provider.js +11 -0
  29. package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
  30. package/package.json +14 -9
  31. package/src/browser/index.ts +14 -0
  32. package/src/browser/indexeddb-file-system-store.ts +192 -0
  33. package/src/langium/ast-extension/ast-extension-service.ts +74 -41
  34. package/src/langium/build-phase-pass/build-phase-pass-service.ts +28 -18
  35. package/src/langium/build-phase-pass/build-phase-pass.ts +36 -7
  36. package/src/langium/document-builder/build-pipeline-integration.ts +11 -42
  37. package/src/langium/residency/cst-residency-service.ts +1 -1
  38. package/src/langium/workspace/persistent-file-system-provider.ts +11 -0
@@ -10,46 +10,11 @@
10
10
  import { type LangiumDocument, DocumentState } from '@hydranium/langium';
11
11
  import { type CancellationToken } from 'vscode-languageserver';
12
12
  import { IntegrityPhase } from '../integrity/integrity-rule.js';
13
- import { groupDocumentsByLanguage } from '../build-phase-pass/build-phase-pass.js';
13
+ import { AstExtensionPhase } from '../ast-extension/ast-extension-service.js';
14
+ import { BuildPassPhase, groupDocumentsByLanguage } from '../build-phase-pass/build-phase-pass.js';
14
15
  import { type ServerSharedServices } from '../module.js';
15
16
  import { labelPhaseListener } from './labeled-phase-listener.js';
16
17
 
17
- /**
18
- * AST extension wiring covers every "useful" `DocumentState` an extension can
19
- * target. `Changed` has no AST yet; `IndexedContent` carries the same
20
- * per-document information as `Parsed`. No-op fires for documents with no
21
- * extension at a given state are negligible (`notifyDocumentPhase` is a plain
22
- * listener loop), so the framework wires the full set unconditionally rather
23
- * than collecting declared states from per-language registrations.
24
- */
25
- const AST_EXTENSION_PHASES: readonly DocumentState[] = [
26
- DocumentState.Parsed,
27
- DocumentState.ComputedScopes,
28
- DocumentState.Linked,
29
- DocumentState.IndexedReferences,
30
- DocumentState.Validated
31
- ];
32
-
33
- /**
34
- * Build phases at which the `BuildPhasePassService` is driven. A pass
35
- * registered at any other state never fires (the listener is not wired), and
36
- * `runPasses` no-ops at a phase with no registered pass, so wiring the full set
37
- * unconditionally costs only an empty-bucket check per phase.
38
- *
39
- * `IndexedContent` belongs here and NOT in {@link AST_EXTENSION_PHASES}, so the
40
- * two cannot be collapsed. Per document it carries nothing `Parsed` does; per
41
- * BATCH it is the only phase meaning the global index is whole again, which
42
- * batch work keyed on a complete index has nowhere else to run.
43
- */
44
- const BUILD_PHASE_PASS_STATES: readonly DocumentState[] = [
45
- DocumentState.Parsed,
46
- DocumentState.IndexedContent,
47
- DocumentState.ComputedScopes,
48
- DocumentState.Linked,
49
- DocumentState.IndexedReferences,
50
- DocumentState.Validated
51
- ];
52
-
53
18
  /**
54
19
  * Default priority of the framework integrity passes. Integrity mutates / cleans
55
20
  * the AST that every derived-state pass reads, so it is *foundational* and must
@@ -132,17 +97,19 @@ export class DefaultBuildPipelineIntegration implements BuildPipelineIntegration
132
97
  for (const phase of IntegrityPhase.all()) {
133
98
  passes.register({
134
99
  id: `framework:integrity:${IntegrityPhase.toString(phase).toLowerCase()}`,
135
- state: phase,
100
+ phase,
136
101
  priority: integrityPriority,
137
102
  run: (documents, cancelToken) => this.callIntegrity(documents, phase, cancelToken)
138
103
  });
139
104
  }
140
105
 
141
- // One onBuildPhase listener per pass state, routed through the overridable
106
+ // One onBuildPhase listener per pass phase, routed through the overridable
142
107
  // `runBuildPhase` seam → priority-ordered, sequential, cancel-aware pass
143
108
  // dispatch. The returned promise is awaited by the build pipeline, so a
144
- // mutating pass (integrity) reparses before the build advances.
145
- for (const phase of BUILD_PHASE_PASS_STATES) {
109
+ // mutating pass (integrity) reparses before the build advances. The full
110
+ // set is wired unconditionally: `runPasses` no-ops at a phase with no
111
+ // pass, so an unused listener costs one empty-bucket check.
112
+ for (const phase of BuildPassPhase.all()) {
146
113
  builder.onBuildPhase(
147
114
  phase,
148
115
  labelPhaseListener(
@@ -164,7 +131,9 @@ export class DefaultBuildPipelineIntegration implements BuildPipelineIntegration
164
131
  // unchanged by the build-phase-pass registry, which is batch-granular. The
165
132
  // listener calls the `extendAst` seam directly (the document-phase analog of
166
133
  // `runBuildPhase`); there is no per-phase handler tier — one parameterized seam.
167
- for (const phase of AST_EXTENSION_PHASES) {
134
+ // Wired for every phase unconditionally rather than for the phases the
135
+ // per-language registrations declare: a no-op fire is a plain listener loop.
136
+ for (const phase of AstExtensionPhase.all()) {
168
137
  builder.onDocumentPhase(
169
138
  phase,
170
139
  labelPhaseListener(
@@ -282,7 +282,7 @@ export class DefaultCstResidencyService implements CstResidencyService {
282
282
  this.langiumDocs = services.workspace.LangiumDocuments;
283
283
  services.workspace.BuildPhasePassService.register({
284
284
  id: 'framework:cst-residency:shed',
285
- state: DocumentState.Validated,
285
+ phase: DocumentState.Validated,
286
286
  priority: options.priority ?? CST_RESIDENCY_PASS_PRIORITY,
287
287
  run: documents => this.onBuild(documents)
288
288
  });
@@ -150,12 +150,21 @@ export class PersistentFileSystemProvider extends InMemoryFileSystemProvider {
150
150
  * of marking it — a deletion that quietly undoes itself on the next load.
151
151
  */
152
152
  protected readonly seededPaths: ReadonlySet<string>;
153
+ /**
154
+ * The store keys restored as CONTENT, in the store's order.
155
+ *
156
+ * A deletion marker is not listed: the store holds a key for a deleted seeded
157
+ * file, so a host counting stored keys would report that deletion as a
158
+ * restored file, and only this class can tell the two apart.
159
+ */
160
+ readonly restoredPaths: readonly string[];
153
161
 
154
162
  constructor(services: ServerSharedServicesMinimal, options: PersistentFileSystemOptions) {
155
163
  super(services, options);
156
164
  this.store = options.store;
157
165
  this.storeRoot = options.rootUri === undefined ? undefined : `${this.fileKey(options.rootUri)}/`;
158
166
  this.seededPaths = new Set(Object.keys(options.seed ?? {}).map(path => this.storeKey(this.storeUri(path))));
167
+ const restoredPaths: string[] = [];
159
168
  for (const [path, content] of Object.entries(options.restored ?? {})) {
160
169
  // `super.*`, so restoring does not mirror straight back into the store
161
170
  // it just came from — a write-back on every start, and one that would
@@ -170,8 +179,10 @@ export class PersistentFileSystemProvider extends InMemoryFileSystemProvider {
170
179
  this.files.delete(this.fileKey(uri));
171
180
  } else {
172
181
  super.setFile(uri, content);
182
+ restoredPaths.push(path);
173
183
  }
174
184
  }
185
+ this.restoredPaths = restoredPaths;
175
186
  }
176
187
 
177
188
  /**