@typemf/generator 0.6.0 → 0.7.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.6.0",
3
+ "version": "0.7.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.6.0",
34
- "@typemf/node": "0.6.0",
35
- "@typemf/xmi": "0.6.0",
33
+ "@typemf/core": "0.7.0",
34
+ "@typemf/node": "0.7.0",
35
+ "@typemf/xmi": "0.7.0",
36
36
  "nunjucks": "^3.2.4",
37
37
  "prettier": "^3.9.8"
38
38
  },
@@ -339,6 +339,7 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
339
339
  {% endfor %}
340
340
 
341
341
  eGet(feature: EStructuralFeature): unknown {
342
+ this.requireOwnFeature(feature);
342
343
  switch (feature.getFeatureID()) {
343
344
  {% for feature in ownFeatures %}
344
345
  {% if featureGetter(feature) or trivialDerivedFormula(feature) %}
@@ -363,6 +364,7 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
363
364
  }
364
365
 
365
366
  eSet(feature: EStructuralFeature, value: unknown): void {
367
+ this.requireOwnFeature(feature);
366
368
  switch (feature.getFeatureID()) {
367
369
  {% for feature in ownFeatures %}
368
370
  {% if feature.isMany() %}
@@ -476,6 +478,7 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
476
478
  }
477
479
 
478
480
  eIsSet(feature: EStructuralFeature): boolean {
481
+ this.requireOwnFeature(feature);
479
482
  switch (feature.getFeatureID()) {
480
483
  {% for feature in ownFeatures %}
481
484
  {% if feature.isMany() %}
@@ -526,6 +529,7 @@ export class {{ eClass.getName() }}Impl extends {{ (superClass.getName() + "Impl
526
529
  }
527
530
 
528
531
  eUnset(feature: EStructuralFeature): void {
532
+ this.requireOwnFeature(feature);
529
533
  switch (feature.getFeatureID()) {
530
534
  {% for feature in ownFeatures %}
531
535
  {% if feature.isMany() and not featureGetter(feature) %}
@@ -1,4 +1,5 @@
1
1
  {% set eFactoryClassifier = findEClassByName(package, "EFactory") %}
2
+ {% set pkgClass = packageClassName(package) %}
2
3
  {% file factoryClassName(package) + ".ts" %}
3
4
  export interface {{ factoryClassName(package) }} extends {{ useImport("EFactory", "types", {foundational: true}) }} {
4
5
  {% for classifier in concreteEClassesOf(package) %}
@@ -25,6 +26,14 @@ export interface {{ factoryClassName(package) }} extends {{ useImport("EFactory"
25
26
  double-import the old, pre-refactor version of this template had to
26
27
  guard against explicitly. #}
27
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. */
33
+ static get eINSTANCE(): {{ factoryClassName(package) }} {
34
+ return {{ useImport("get" + pkgClass + "Ref", "impl", {file: pkgClass + "Ref", foundational: false}) }}().getEFactoryInstance() as {{ factoryClassName(package) }};
35
+ }
36
+
28
37
  {% for classifier in concreteEClassesOf(package) %}
29
38
  create{{ classifier.getName() }}(): {{ useImport(classifier.getName(), "types", {foundational: false}) }} {
30
39
  return new {{ useImport(classifier.getName() + "Impl", "impl", {foundational: false}) }}();
@@ -104,6 +104,7 @@ export interface {{ pkgClass }} extends {{ useImport("EPackage", "types", {found
104
104
  {% set _ = useImport(factoryClassName(package), "root", {foundational: false}) %}
105
105
  {% set _ = useImport(factoryClassName(package) + "Impl", "impl", {foundational: false}) %}
106
106
  {% set _ = useImport("set" + pkgClass + "Ref", "impl", {file: pkgClass + "Ref", foundational: false}) %}
107
+ {% set _ = useImport("register" + pkgClass + "Initializer", "impl", {file: pkgClass + "Ref", foundational: false}) %}
107
108
 
108
109
  {#-
109
110
  Emits code reconstructing `element`'s real EAnnotations (source +
@@ -476,4 +477,12 @@ export class {{ pkgClass }}Impl extends EPackageImpl implements {{ pkgClass }} {
476
477
  {% endif %}
477
478
  {% endfor %}
478
479
  }
480
+
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.
485
+ register{{ pkgClass }}Initializer(() => {
486
+ void {{ pkgClass }}Impl.eINSTANCE;
487
+ });
479
488
  {% endfile %}
@@ -31,14 +31,44 @@ import type { {{ packageClassName(package) }} } from '../{{ packageClassName(pac
31
31
  */
32
32
  let ref: {{ packageClassName(package) }} | undefined;
33
33
 
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
+ */
42
+ let initializer: (() => void) | undefined;
43
+ let initializing = false;
44
+
34
45
  export function set{{ packageClassName(package) }}Ref(pkg: {{ packageClassName(package) }}): void {
35
46
  ref = pkg;
36
47
  }
37
48
 
49
+ export function register{{ packageClassName(package) }}Initializer(init: () => void): void {
50
+ initializer = init;
51
+ }
52
+
38
53
  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.
58
+ if (!ref && initializer && !initializing) {
59
+ initializing = true;
60
+ try {
61
+ initializer();
62
+ } finally {
63
+ initializing = false;
64
+ }
65
+ }
39
66
  if (!ref) {
40
67
  throw new Error(
41
- 'get{{ packageClassName(package) }}Ref() called before the {{ packageClassName(package) }} singleton finished constructing itself.'
68
+ 'get{{ packageClassName(package) }}Ref() called before the {{ packageClassName(package) }} singleton finished constructing itself, and no ' +
69
+ 'initializer was registered to construct it on demand - this means {{ packageClassName(package) }}Impl.ts\'s own module ' +
70
+ 'was never evaluated at all (an unusual bundler/tree-shaking setup). Call {{ packageClassName(package) }}Impl.eINSTANCE ' +
71
+ 'or .init() yourself first, or check that this package is marked side-effectful.'
42
72
  );
43
73
  }
44
74
  return ref;