@typemf/generator 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typemf/generator",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -30,9 +30,9 @@
30
30
  "provenance": true
31
31
  },
32
32
  "dependencies": {
33
- "@typemf/core": "0.7.0",
34
- "@typemf/node": "0.7.0",
35
- "@typemf/xmi": "0.7.0",
33
+ "@typemf/core": "0.8.0",
34
+ "@typemf/node": "0.8.0",
35
+ "@typemf/xmi": "0.8.0",
36
36
  "nunjucks": "^3.2.4",
37
37
  "prettier": "^3.9.8"
38
38
  },
@@ -43,7 +43,7 @@ export interface {{ eClass.getName() }} extends {{ superClass.getName() if super
43
43
  {% else %}
44
44
  {% set _ = useImport("EObjectImpl", "impl", {foundational: true}) %}
45
45
  {% endif %}
46
- {% set _ = useImport("BasicEList", "impl", {foundational: true}) %}
46
+ {% if options['generate-ecore'] or hasStoredManyValuedFeature(ownFeatures) %}{% set _ = useImport("BasicEList", "impl", {foundational: true}) %}{% endif %}
47
47
  {% for feature in ownFeatures %}
48
48
  {% if feature.isMany() %}
49
49
  {% set _ = useImport("EList", "types", {foundational: true}) %}
@@ -115,72 +115,54 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
115
115
  {% endif %}
116
116
  {% endfor %}
117
117
 
118
- {% if eClass.getName() == "EClassifier" %}
119
- {#- classifierID is real, internal dispatch bookkeeping (matching
120
- @typemf/core's own hand-written EClassifierImpl), not a modeled
121
- Ecore feature - so it's declared here, once, on EClassifier itself
122
- (inherited by every descendant: EClass, EDataType, EEnum, ...)
123
- rather than emitted by the ordinary feature-driven generation
124
- above, which has no feature to generate it from. Confirmed
125
- necessary by actually running self-hosted bootstrap code (which
126
- constructs real EClassifier-derived metaclass shells and needs to
127
- set their classifierID), not assumed - see NOTES.md. #}
118
+ {% if options['generate-ecore'] and eClass.getName() == "EClassifier" %}
119
+ {#- Ecore only: the classifier ID is bookkeeping, not a modeled feature, inherited by every
120
+ classifier. #}
128
121
  private classifierId = -1;
129
122
 
130
123
  getClassifierID(): number {
131
124
  return this.classifierId;
132
125
  }
133
126
 
127
+ /** Sets the classifier's ID; called by generated packages. */
134
128
  setClassifierID(id: number): void {
135
129
  this.classifierId = id;
136
130
  }
137
131
  {% endif %}
138
- {% if eClass.getName() == "EStructuralFeature" %}
139
- {#- featureID: the exact same real gap as classifierID above, one level
140
- down the hierarchy - internal dispatch bookkeeping (matching
141
- @typemf/core's own hand-written EStructuralFeatureImpl), not a
142
- modeled Ecore feature, declared once here on EStructuralFeature
143
- itself (inherited by EAttribute, EReference, ...). Found the same
144
- way: running self-hosted bootstrap code, which constructs real
145
- EStructuralFeature-derived metaclass shells (EAttributeImpl,
146
- EReferenceImpl) and needs to set their featureID - see NOTES.md. #}
132
+ {% if options['generate-ecore'] and eClass.getName() == "EStructuralFeature" %}
133
+ {#- Ecore only: the feature ID (bookkeeping) and the container class (getter modeled as an
134
+ operation, setter only on the implementation, used during bootstrap). #}
147
135
  private featureId = -1;
148
136
 
149
137
  getFeatureID(): number {
150
138
  return this.featureId;
151
139
  }
152
140
 
141
+ /** Sets the feature's ID; called by generated packages. */
153
142
  setFeatureID(id: number): void {
154
143
  this.featureId = id;
155
144
  }
156
- {#- containerClass: real EMF's own asymmetric design (see EStructuralFeature.getContainerClass()'s
157
- doc comment in @typemf/core) - PUBLIC getter (a real, modeled, reflectively-callable operation),
158
- IMPL-ONLY setter (never on the interface, set once during bootstrap - see epackage.njk). Not
159
- internal bookkeeping like featureID (it IS a real declared operation), but shares the same
160
- "special-cased field the normal per-operation loop must skip" shape, so isBookkeepingOperation
161
- treats it the same way (see typescript-filters.ts). #}
145
+
162
146
  private containerClass: {{ useImport("TypeScriptClass", "types", {foundational: true}) }}<unknown> | undefined;
163
147
 
164
148
  getContainerClass(): {{ useImport("TypeScriptClass", "types", {foundational: true}) }}<unknown> | undefined {
165
149
  return this.containerClass;
166
150
  }
167
151
 
152
+ /** Sets the implementation class of the declaring class; called by generated packages. */
168
153
  setContainerClass(cls: {{ useImport("TypeScriptClass", "types", {foundational: true}) }}<unknown> | undefined): void {
169
154
  this.containerClass = cls;
170
155
  }
171
156
  {% endif %}
172
- {% if eClass.getName() == "EOperation" %}
173
- {#- operationID: the exact same real gap as classifierID/featureID above - internal dispatch
174
- bookkeeping (matching @typemf/core's own hand-written EOperationImpl), not a modeled Ecore
175
- feature, declared once here on EOperation itself. Same discovery path: self-hosted bootstrap
176
- code constructs real EOperationImpl instances and needs to set their operationID - see NOTES.md
177
- (point 4). #}
157
+ {% if options['generate-ecore'] and eClass.getName() == "EOperation" %}
158
+ {#- Ecore only: the operation ID is bookkeeping, not a modeled feature. #}
178
159
  private operationId = -1;
179
160
 
180
161
  getOperationID(): number {
181
162
  return this.operationId;
182
163
  }
183
164
 
165
+ /** Sets the operation's ID; called by generated packages. */
184
166
  setOperationID(id: number): void {
185
167
  this.operationId = id;
186
168
  }
@@ -196,11 +178,12 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
196
178
  {% if feature.isMany() %}
197
179
  {% if getter %}
198
180
  {% set _featureImports = registerBodyImports(feature) %}
181
+ {#- Computed: the cached list is read-only, since changing it would never reach the model. #}
199
182
  get{{ ucfirst(feature.getName()) }}(): EList<{{ tsScalarType(feature) }}> {
200
183
  if (this._{{ feature.getName() }}CacheGeneration !== EObjectImpl.getModelGeneration()) {
201
- this._{{ feature.getName() }}Cache = (() => {
184
+ this._{{ feature.getName() }}Cache = new {{ useImport("UnmodifiableEList", "impl", {foundational: true}) }}((() => {
202
185
  {{ getter | indent(8) }}
203
- })();
186
+ })());
204
187
  this._{{ feature.getName() }}CacheGeneration = EObjectImpl.getModelGeneration();
205
188
  }
206
189
  return this._{{ feature.getName() }}Cache!;
@@ -447,18 +430,9 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
447
430
  }
448
431
  }
449
432
 
450
- {#- The many-valued analog of eBasicSetValue, for the identical reason:
451
- bootstrap code needs to add to a list (eStructuralFeatures,
452
- eAnnotations, eSuperTypes, ...) before the feature's own metaclass
453
- exists to back the ordinary getter's lazy construction. Constructs
454
- the cache with no feature reference when called this way - a real,
455
- narrow, deliberate limitation: containment/opposite maintenance on
456
- a list built this way is unavailable, since there's no feature to
457
- derive it from. Acceptable specifically because only the metamodel's
458
- own self-describing bootstrap instances (EClassImpl, EAttributeImpl,
459
- etc., as constructed by {Pkg}PackageImpl) ever take this path -
460
- ordinary domain instances always go through the normal, fully-
461
- wired getter instead, never this one. #}
433
+ {% if options['generate-ecore'] %}
434
+ {#- Ecore only: the bootstrap adds to lists before the metaclasses their getters need exist. #}
435
+ /** @internal The list of the many-valued feature `featureId`, for bootstrapping the package. */
462
436
  eBootstrapList(featureId: number): BasicEList<unknown> {
463
437
  switch (featureId) {
464
438
  {% for feature in ownFeatures %}
@@ -476,6 +450,7 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
476
450
  {% endif %}
477
451
  }
478
452
  }
453
+ {% endif %}
479
454
 
480
455
  eIsSet(feature: EStructuralFeature): boolean {
481
456
  this.requireOwnFeature(feature);
@@ -26,10 +26,10 @@ export interface {{ factoryClassName(package) }} extends {{ useImport("EFactory"
26
26
  double-import the old, pre-refactor version of this template had to
27
27
  guard against explicitly. #}
28
28
  export class {{ factoryClassName(package) }}Impl extends {{ useImport("EFactoryImpl", "impl", {foundational: true}) }} implements {{ useImport(factoryClassName(package), "root", {foundational: false}) }} {
29
- /** The one canonical factory instance - real EMF's own `{{ factoryClassName(package) }}.eINSTANCE`, which this project
30
- * ports onto the Impl class rather than the interface (TypeScript interfaces have no statics).
31
- * Reading this also constructs the package singleton on first use (CORE-01), via the same
32
- * lazy initializer {{ pkgClass }}Impl.eINSTANCE itself goes through. */
29
+ /**
30
+ * The factory instance, as EMF's `{{ factoryClassName(package) }}.eINSTANCE` (on the class, since
31
+ * TypeScript interfaces have no statics). Reading it constructs the package if necessary.
32
+ */
33
33
  static get eINSTANCE(): {{ factoryClassName(package) }} {
34
34
  return {{ useImport("get" + pkgClass + "Ref", "impl", {file: pkgClass + "Ref", foundational: false}) }}().getEFactoryInstance() as {{ factoryClassName(package) }};
35
35
  }
@@ -4,13 +4,7 @@
4
4
  {% set _ = useImport(name, "types", {foundational: true}) %}
5
5
  {% endfor %}
6
6
 
7
- /**
8
- * Classifier/feature IDs, as pure numeric literals - safe to import from
9
- * anywhere (Factory, Switch) with zero risk of the circular-import hazard
10
- * that made a lazy, explicit init() necessary for the singleton itself
11
- * (see {{ pkgClass }}Impl.ts) - these are just numbers, never require
12
- * constructing anything.
13
- */
7
+ /** The classifier, feature and operation IDs; plain numbers, safe to import from anywhere. */
14
8
  export const Ids = {
15
9
  {% for classifier in package.getEClassifiers() %}
16
10
  {{ classifier.getName() }}: { self: {{ classifier.getClassifierID() }}{% if isEClass(classifier) %}{% for feature in classifier.getEStructuralFeatures() %}, {{ feature.getName() }}: {{ feature.getFeatureID() }}{% endfor %}{% for op in classifier.getEOperations() %}, op{{ loop.index0 }}: {{ op.getOperationID() }}{% endfor %}{% endif %} },
@@ -60,27 +54,27 @@ export interface {{ pkgClass }} extends {{ useImport("EPackage", "types", {found
60
54
  {% set needsEnum = false %}
61
55
  {% set needsEnumLiteral = false %}
62
56
  {% set needsAnnotation = false %}
63
- {% if package.getEAnnotations().size() > 0 %}{% set needsAnnotation = true %}{% endif %}
57
+ {% if runtimeAnnotations(package).length > 0 %}{% set needsAnnotation = true %}{% endif %}
64
58
  {% for classifier in package.getEClassifiers() %}
65
- {% if classifier.getEAnnotations().size() > 0 %}{% set needsAnnotation = true %}{% endif %}
59
+ {% if runtimeAnnotations(classifier).length > 0 %}{% set needsAnnotation = true %}{% endif %}
66
60
  {% if isEClass(classifier) %}
67
61
  {% for feature in classifier.getEStructuralFeatures() %}
68
62
  {% if isEReference(feature) %}{% set needsReference = true %}{% else %}{% set needsAttribute = true %}{% endif %}
69
- {% if feature.getEAnnotations().size() > 0 %}{% set needsAnnotation = true %}{% endif %}
63
+ {% if runtimeAnnotations(feature).length > 0 %}{% set needsAnnotation = true %}{% endif %}
70
64
  {% endfor %}
71
65
  {% for op in classifier.getEOperations() %}
72
66
  {% set needsOperation = true %}
73
- {% if op.getEAnnotations().size() > 0 %}{% set needsAnnotation = true %}{% endif %}
67
+ {% if runtimeAnnotations(op).length > 0 %}{% set needsAnnotation = true %}{% endif %}
74
68
  {% if op.getEParameters().size() > 0 %}{% set needsParameter = true %}{% endif %}
75
69
  {% for param in op.getEParameters() %}
76
- {% if param.getEAnnotations().size() > 0 %}{% set needsAnnotation = true %}{% endif %}
70
+ {% if runtimeAnnotations(param).length > 0 %}{% set needsAnnotation = true %}{% endif %}
77
71
  {% endfor %}
78
72
  {% endfor %}
79
73
  {% elif isEEnum(classifier) %}
80
74
  {% set needsEnum = true %}
81
75
  {% for literal in classifier.getELiterals() %}
82
76
  {% set needsEnumLiteral = true %}
83
- {% if literal.getEAnnotations().size() > 0 %}{% set needsAnnotation = true %}{% endif %}
77
+ {% if runtimeAnnotations(literal).length > 0 %}{% set needsAnnotation = true %}{% endif %}
84
78
  {% endfor %}
85
79
  {% else %}
86
80
  {% set needsDataType = true %}
@@ -107,8 +101,9 @@ export interface {{ pkgClass }} extends {{ useImport("EPackage", "types", {found
107
101
  {% set _ = useImport("register" + pkgClass + "Initializer", "impl", {file: pkgClass + "Ref", foundational: false}) %}
108
102
 
109
103
  {#-
110
- Emits code reconstructing `element`'s real EAnnotations (source +
111
- details) onto the runtime object built at `targetExpr`. Scoped to
104
+ Emits code reconstructing `element`'s EAnnotations (source + details) onto
105
+ the runtime object built at `targetExpr`, except the generator-only ones
106
+ (see runtimeAnnotations). Scoped to
112
107
  package/classifier/feature/enum-literal only - EOperations have no
113
108
  runtime representation in the converted metamodel yet, so there's
114
109
  nowhere for an operation-level annotation to attach (see NOTES.md).
@@ -156,7 +151,7 @@ export interface {{ pkgClass }} extends {{ useImport("EPackage", "types", {found
156
151
  everywhere else in this file (the metaclass for EStringToStringMapEntry doesn't exist yet at the
157
152
  point this code runs during self-construction); the ordinary branch has no such ordering problem and
158
153
  uses the real, public API (setDetailValue) directly. #}
159
- {% for annotation in element.getEAnnotations() %}
154
+ {% for annotation in runtimeAnnotations(element) %}
160
155
  {
161
156
  const annotation = new EAnnotationImpl();
162
157
  {% if annotation.getSource() %}
@@ -208,14 +203,9 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
208
203
  private static _instance: {{ pkgClass }}Impl | undefined;
209
204
 
210
205
  /**
211
- * The one explicit entry point that constructs the singleton - call it
212
- * yourself, with your own factory, before anything else in your program
213
- * touches {{ pkgClass }}Impl.eINSTANCE, to use a custom factory (e.g. one
214
- * overriding createX() to return your own derived classes). Whichever
215
- * caller gets here FIRST wins; a later call with a *different* factory
216
- * is logged and otherwise ignored, rather than silently replacing an
217
- * already-in-use singleton or throwing on a caller who didn't cause the
218
- * conflict.
206
+ * Constructs the package, if that hasn't happened yet, and returns it. To use your own factory
207
+ * (e.g. one returning subclasses), call this with it before anything reads `eINSTANCE`; a
208
+ * factory passed after construction is ignored with a warning.
219
209
  */
220
210
  static init(factory?: {{ factoryClassName(package) }}): {{ pkgClass }}Impl {
221
211
  if (!{{ pkgClass }}Impl._instance) {
@@ -236,10 +226,7 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
236
226
 
237
227
  private constructor() {
238
228
  super();
239
- // Set immediately, before Pass 1 constructs any classifier (each of
240
- // which may need this reference - see {{ pkgClass }}Ref.ts's own doc
241
- // comment for why this is a late-bound reference rather than a
242
- // direct import of {{ pkgClass }}Impl.
229
+ // Set first: constructing the classifiers below already needs the package reference.
243
230
  set{{ pkgClass }}Ref(this);
244
231
 
245
232
  // Pass 1: create every classifier (empty shell - no features/supertypes
@@ -267,10 +254,7 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
267
254
  {{ bootstrapSet("literal", "setLiteral", "Ids.EEnumLiteral.literal", jsString(literal.getLiteral())) }}
268
255
  {{ emitAnnotations("literal", literal) }}
269
256
  {% if options['generate-ecore'] %}
270
- // No addLiteral() here - this generated EEnumImpl doesn't have that
271
- // hand-written convenience method (it's not a reflective feature),
272
- // so the list-add and the eEnum backpointer (a real, modeled,
273
- // non-changeable opposite - see NOTES.md) are wired manually.
257
+ // eEnum is not changeable, so both ends of the opposite are set directly.
274
258
  this._{{ classifier.getName() }}.eBootstrapList(Ids.EEnum.eLiterals).add(literal);
275
259
  literal.eBasicSetValue(Ids.EEnumLiteral.eEnum, this._{{ classifier.getName() }});
276
260
  {% else %}
@@ -326,6 +310,9 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
326
310
  {{ bootstrapSet(fieldExpr, "setChangeable", "Ids.EStructuralFeature.changeable", feature.isChangeable()) }}
327
311
  {{ bootstrapSet(fieldExpr, "setOrdered", "Ids.ETypedElement.ordered", feature.isOrdered()) }}
328
312
  {{ bootstrapSet(fieldExpr, "setUnique", "Ids.ETypedElement.unique", feature.isUnique()) }}
313
+ {% if feature.getDefaultValueLiteral() !== undefined %}
314
+ {{ bootstrapSet(fieldExpr, "setDefaultValueLiteral", "Ids.EStructuralFeature.defaultValueLiteral", jsString(feature.getDefaultValueLiteral())) }}
315
+ {% endif %}
329
316
  {{ fieldExpr }}.setFeatureID(Ids.{{ classifier.getName() }}.{{ feature.getName() }});
330
317
  {#- containerClass: the concrete implementation class the feature is declared on - the closest
331
318
  TypeScript has to Java's own containerClass semantics (Class<?>, e.g. EClassifier.class in the
@@ -346,11 +333,8 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
346
333
  {% endfor %}
347
334
  {% endfor %}
348
335
 
349
- // Pass 2.5: operations and their parameters - real EOperation/EParameter objects, not just the
350
- // generated METHODS (which already existed) - eOperations used to be permanently empty at runtime;
351
- // this is what actually populates it, the same way pass 2 populates eStructuralFeatures. Kept as
352
- // its own pass, after every classifier and feature exists (an operation's return type or a
353
- // parameter's type can reference either), rather than folded into the loop above.
336
+ // Pass 2.5: operations and their parameters, after every classifier and feature exists, since
337
+ // their types can refer to any of them.
354
338
  {% for classifier in eClassesOf(package) %}
355
339
  {% for op in classifier.getEOperations() %}
356
340
  {% set opIndex = loop.index0 %}
@@ -407,21 +391,9 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
407
391
  {% endfor %}
408
392
  {% endfor %}
409
393
 
410
- // Pass 5 (recompute EAll* caches, ordinary mode only) removed - stale post-swap.
411
- // @typemf/core's own EClassImpl is now itself generated code (see NOTES.md's point 6/7
412
- // write-ups), using the same automatic, get-bodied caching (EObjectImpl.getModelGeneration(),
413
- // point 1) as self-hosted output always did - there is no recomputeAllLists() method to call
414
- // anymore, in either mode, and none is needed.
415
394
 
416
- // Pass 6: set the package's own name/nsURI/nsPrefix/annotations last,
417
- // deliberately - these go through the ordinary reflective setters
418
- // (this.setName(), etc.), which need the "name"/etc. feature's own
419
- // metaclass object to already exist (it's built above, in the passes
420
- // this follows). Calling them earlier - before those metaclasses
421
- // exist - is a genuine bootstrap-ordering bug, confirmed directly by
422
- // reproducing it: this line order isn't a style choice, the metaclass
423
- // shells and feature wiring above are a real, load-bearing
424
- // precondition for the reflective setter calls below to work at all.
395
+ // Pass 5: the package's own name, nsURI, nsPrefix and annotations, last: the setters used here
396
+ // need the features built above.
425
397
  this.setName({{ jsString(package.getName()) }});
426
398
  this.setNsURI({{ jsString(package.getNsURI()) }});
427
399
  this.setNsPrefix({{ jsString(package.getNsPrefix()) }});
@@ -478,10 +450,7 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
478
450
  {% endfor %}
479
451
  }
480
452
 
481
- // CORE-01: lets getXxxRef() construct the singleton itself, on first use, instead of only ever
482
- // throwing when nothing has touched {{ pkgClass }}Impl.eINSTANCE/.init() yet. A side effect of
483
- // this module being evaluated at all - see register{{ pkgClass }}Initializer's own doc comment
484
- // in {{ pkgClass }}Ref.ts.
453
+ // Lets get{{ pkgClass }}Ref() construct the package on first use.
485
454
  register{{ pkgClass }}Initializer(() => {
486
455
  void {{ pkgClass }}Impl.eINSTANCE;
487
456
  });
@@ -2,43 +2,14 @@
2
2
  import type { {{ packageClassName(package) }} } from '../{{ packageClassName(package) }}.js';
3
3
 
4
4
  /**
5
- * A late-bound reference to the {{ packageClassName(package) }} singleton,
6
- * set once by {{ packageClassName(package) }}Impl's own constructor after
7
- * it finishes constructing itself.
8
- *
9
- * Every generated class needs a reference to the package singleton (for
10
- * eClass(), for feature-ID lookups in field initializers/lazy getters,
11
- * etc.) - and {{ packageClassName(package) }}Impl itself constructs
12
- * (nearly) every one of those classes to build the runtime metamodel. For
13
- * an ordinary generated package that mutual reference is harmless: the
14
- * package singleton already exists in full by the time anything else is
15
- * ever constructed. But self-hosting a metamodel that describes itself
16
- * (as with real Ecore.ecore) makes this a genuine, confirmed hazard: a
17
- * real class along the package's own superclass chain, or a class that is
18
- * ALSO the superclass of something the package constructs directly (the
19
- * "EFactory unification" / "EPackage unification" cases), can end up
20
- * needing this reference while {{ packageClassName(package) }}Impl is
21
- * still in the middle of constructing itself - a genuine circular
22
- * dependency, not merely an ordering preference, confirmed directly
23
- * against a real failing bundle ("Class extends value undefined is not a
24
- * constructor or null") while building this generator, not assumed.
25
- *
26
- * This module has only a type-only import (erased at compile time, zero
27
- * runtime footprint) - so importing FROM this module can never itself
28
- * participate in a circular dependency, unlike importing
29
- * {{ packageClassName(package) }}Impl (or anything re-exporting it)
30
- * directly.
5
+ * A reference to the {{ packageClassName(package) }} singleton that every generated class of the package
6
+ * reads instead of importing {{ packageClassName(package) }}Impl, which would be a circular import: the
7
+ * package constructs those classes while it constructs itself. This module only has a type
8
+ * import, so it can be imported from anywhere.
31
9
  */
32
10
  let ref: {{ packageClassName(package) }} | undefined;
33
11
 
34
- /**
35
- * Set once, as a module-scope side effect of {{ packageClassName(package) }}Impl.ts's own module
36
- * being evaluated (see the call at the bottom of that file) - never a direct import of
37
- * {{ packageClassName(package) }}Impl here, for the exact same circularity reason the class doc
38
- * comment above explains. Lets get{{ packageClassName(package) }}Ref() (CORE-01) construct the
39
- * singleton itself, on first use, instead of only ever throwing when nothing has touched
40
- * {{ packageClassName(package) }}Impl.eINSTANCE/.init() yet.
41
- */
12
+ /** Constructs the package on first use; registered when {{ packageClassName(package) }}Impl.ts is evaluated. */
42
13
  let initializer: (() => void) | undefined;
43
14
  let initializing = false;
44
15
 
@@ -51,10 +22,7 @@ export function register{{ packageClassName(package) }}Initializer(init: () => v
51
22
  }
52
23
 
53
24
  export function get{{ packageClassName(package) }}Ref(): {{ packageClassName(package) }} {
54
- // The `!initializing` guard turns a reentrant call before the constructor reaches its own
55
- // set{{ packageClassName(package) }}Ref(this) - which should never genuinely happen; the
56
- // constructor calls that first, before anything else that could call back in here - into the
57
- // ordinary "not ready yet" error below instead of unbounded recursion.
25
+ // `initializing` turns a reentrant call during construction into the error below.
58
26
  if (!ref && initializer && !initializing) {
59
27
  initializing = true;
60
28
  try {
@@ -1,22 +1,8 @@
1
1
  {% file "util/" + typeGuardsClassName(package) + ".ts" %}
2
2
  /**
3
- * Runtime type guards, one per classifier declared in types/ - the
4
- * reflective counterpart to a hand-written structural guard like
5
- *
6
- * function isReference(feature: EStructuralFeature): feature is EReference {
7
- * return "isContainment" in feature;
8
- * }
9
- *
10
- * Structural (duck-typing) checks like that one work when a single
11
- * classifier has some genuinely distinguishing own member - but nothing
12
- * guarantees an arbitrary generated classifier has one (a subclass might
13
- * add no own features at all, inheriting everything). These guards check
14
- * the object's REAL runtime EClass against the metamodel's own
15
- * eAllSuperTypes reflectively instead (via isSuperTypeOf()), which is
16
- * correct for every classifier unconditionally, including abstract ones
17
- * (correctly true for any instance of a concrete subclass) and dynamic
18
- * instances (no dependency on the object's actual JS class/prototype at
19
- * all, unlike `instanceof`).
3
+ * Type guards for the classifiers of the package. They check an object's class with
4
+ * `isSuperTypeOf()`, so they also work for abstract classes, interfaces and dynamic objects,
5
+ * unlike `instanceof`.
20
6
  */
21
7
  function hasEClass(obj: unknown): obj is {{ useImport("EObject", "types", {foundational: true}) }} {
22
8
  return obj !== null && typeof obj === 'object' && typeof (obj as { eClass?: unknown }).eClass === 'function';