adaptive-extender 0.10.3 → 0.10.5

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/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.10.5 (13.06.2026)
2
+ - Bugfix at [portable](./src/core/portable.ts).
3
+
1
4
  ## 0.10.3 (05.06.2026)
2
5
  - Added `Function.empty` constant — a shared no-op function available via `Function.empty`.
3
6
  - Added [function](./src/core/function.ts) module to the core package.
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ Reflect.set(Symbol, "metadata", Reflect.get(Symbol, "metadata") ?? Symbol.for("Symbol.metadata"));
2
3
  globalThis.constructor = function (value) {
3
4
  return value.constructor;
4
5
  };
@@ -4,7 +4,9 @@ import "./string.js";
4
4
  import "./boolean.js";
5
5
  import "./array.js";
6
6
  import "./object.js";
7
+ import "./map.js";
7
8
  import "./reflect.js";
9
+ import "./error.js";
8
10
  import {} from "./global.js";
9
11
  //#endregion
10
12
  //#region Field descriptor
@@ -47,24 +49,39 @@ class DescendantDescriptor {
47
49
  //#region Portability metadata
48
50
  class PortabilityMetadata {
49
51
  static #registry = new WeakMap();
50
- #model;
51
52
  #fields = new Map();
52
53
  #descendants = [];
53
54
  #discriminator = "$type";
54
- constructor(model) {
55
- this.#model = model;
55
+ static for(metadata) {
56
+ const registry = PortabilityMetadata.#registry;
57
+ let entry = registry.get(metadata);
58
+ if (entry !== undefined)
59
+ return entry;
60
+ entry = new PortabilityMetadata();
61
+ registry.set(metadata, entry);
62
+ return entry;
56
63
  }
57
64
  static read(model) {
58
- const registry = PortabilityMetadata.#registry;
59
- let metadata = registry.get(model);
60
- if (metadata !== undefined)
61
- return metadata;
62
- metadata = new PortabilityMetadata(model);
63
- registry.set(model, metadata);
65
+ const object = ReferenceError.suppress(model[Symbol.metadata], `Required an implementation of Symbol.metadata in '${model.name}' to use portability`);
66
+ const metadata = PortabilityMetadata.for(object);
67
+ const fields = metadata.#fields;
68
+ let current = object;
69
+ while (true) {
70
+ if (current === null)
71
+ break;
72
+ for (const [key, descriptor] of PortabilityMetadata.for(current).#fields)
73
+ fields.add(key, descriptor);
74
+ current = Object.getPrototypeOf(current);
75
+ }
64
76
  return metadata;
65
77
  }
66
- get model() {
67
- return this.#model;
78
+ static descendantsOf(model) {
79
+ if (!Object.hasOwn(model, Symbol.metadata))
80
+ return [];
81
+ const object = model[Symbol.metadata];
82
+ if (object === null || object === undefined)
83
+ return [];
84
+ return PortabilityMetadata.for(object).#descendants;
68
85
  }
69
86
  get fields() {
70
87
  return this.#fields;
@@ -94,8 +111,9 @@ export class Model {
94
111
  */
95
112
  static import(source, name) {
96
113
  const model = this;
97
- const { descendants, discriminator: key } = PortabilityMetadata.read(model);
114
+ const descendants = PortabilityMetadata.descendantsOf(model);
98
115
  if (descendants.length > 0) {
116
+ const { discriminator: key } = PortabilityMetadata.read(model);
99
117
  const object = Object.import(source, name);
100
118
  const value = Reflect.get(object, key);
101
119
  if (value === undefined)
@@ -122,8 +140,9 @@ export class Model {
122
140
  */
123
141
  static export(source) {
124
142
  const model = this;
125
- const { descendants, discriminator: key } = PortabilityMetadata.read(model);
143
+ const descendants = PortabilityMetadata.descendantsOf(model);
126
144
  if (descendants.length > 0) {
145
+ const { discriminator: key } = PortabilityMetadata.read(model);
127
146
  const descriptor = descendants.find(descriptor => source instanceof descriptor.type);
128
147
  if (descriptor === undefined)
129
148
  throw new TypeError(`Invalid '${typename(source)}' type for source`);
@@ -150,18 +169,15 @@ export function Field(type, name) {
150
169
  if (typeof (key) === "symbol")
151
170
  throw new TypeError("Symbols are not supported as portable keys");
152
171
  const association = name ?? key;
153
- context.addInitializer(function () {
154
- const model = constructor(this);
155
- const { fields } = PortabilityMetadata.read(model);
156
- if (fields.has(key))
157
- return;
172
+ const { fields } = PortabilityMetadata.for(context.metadata);
173
+ if (!fields.has(key))
158
174
  fields.set(key, new FieldDescriptor(key, association, type));
159
- });
160
175
  };
161
176
  }
162
177
  export function Descendant(descendant, discriminator) {
163
- return function (model) {
164
- const { descendants } = PortabilityMetadata.read(model);
178
+ return function (model, context) {
179
+ void model;
180
+ const { descendants } = PortabilityMetadata.for(context.metadata);
165
181
  descendants.push(new DescendantDescriptor(descendant, discriminator));
166
182
  };
167
183
  }
@@ -170,9 +186,9 @@ export function Descendant(descendant, discriminator) {
170
186
  * @param key The property key to use for the discriminator.
171
187
  */
172
188
  export function DiscriminatorKey(key) {
173
- return function (model) {
174
- const metadata = PortabilityMetadata.read(model);
175
- metadata.discriminator = key;
189
+ return function (model, context) {
190
+ void model;
191
+ PortabilityMetadata.for(context.metadata).discriminator = key;
176
192
  };
177
193
  }
178
194
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adaptive-extender",
3
- "version": "0.10.3",
3
+ "version": "0.10.5",
4
4
  "description": "Adaptive library for JS/TS development environments",
5
5
  "type": "module",
6
6
  "main": "./dist/core/index.js",
@@ -57,16 +57,14 @@
57
57
  "build:web": "tsc -p ./src/web/tsconfig.json",
58
58
  "build:worker": "tsc -p ./src/worker/tsconfig.json",
59
59
  "build": "npm run build:core && npm run build:node && npm run build:web && npm run build:worker",
60
- "test": "vitest run",
60
+ "test": "npm run build & vitest run",
61
61
  "coverage": "vitest run --coverage"
62
62
  },
63
63
  "devDependencies": {
64
- "@babel/plugin-proposal-decorators": "^7.29.7",
65
- "@rolldown/plugin-babel": "^0.2.3",
66
64
  "@types/jsdom": "^21.1.7",
67
65
  "esbuild": "^0.28.0",
68
66
  "jsdom": "^27.0.0",
69
- "typescript": "^6.0.3",
70
- "vitest": "^4.1.8"
67
+ "typescript": "^5.9.3",
68
+ "vitest": "^4.0.10"
71
69
  }
72
70
  }
@@ -1,27 +1,27 @@
1
- {
2
- "compilerOptions": {
3
- /* Language & Environment */
4
- "target": "ES2022",
5
- "module": "ESNext",
6
- "useDefineForClassFields": true,
7
-
8
- /* Module Resolution / Bundler */
9
- "moduleResolution": "bundler",
10
- "moduleDetection": "force",
11
- "verbatimModuleSyntax": true,
12
-
13
- /* Interop & Compatibility */
14
- "esModuleInterop": true,
15
- "allowJs": true,
16
- "skipLibCheck": false,
17
-
18
- /* Type Checking & Linting */
19
- "strict": true,
20
- "strictPropertyInitialization": false,
21
- "noUnusedLocals": false,
22
- "noUnusedParameters": false,
23
-
24
- /* Miscellaneous */
25
- "forceConsistentCasingInFileNames": true,
26
- }
27
- }
1
+ {
2
+ "compilerOptions": {
3
+ /* Language & Environment */
4
+ "target": "ES2022",
5
+ "module": "ESNext",
6
+ "useDefineForClassFields": true,
7
+
8
+ /* Module Resolution / Bundler */
9
+ "moduleResolution": "bundler",
10
+ "moduleDetection": "force",
11
+ "verbatimModuleSyntax": true,
12
+
13
+ /* Interop & Compatibility */
14
+ "esModuleInterop": true,
15
+ "allowJs": true,
16
+ "skipLibCheck": false,
17
+
18
+ /* Type Checking & Linting */
19
+ "strict": true,
20
+ "strictPropertyInitialization": false,
21
+ "noUnusedLocals": false,
22
+ "noUnusedParameters": false,
23
+
24
+ /* Miscellaneous */
25
+ "forceConsistentCasingInFileNames": true,
26
+ }
27
+ }