@atscript/typescript 0.1.59 → 0.1.60

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/dist/utils.cjs CHANGED
@@ -109,10 +109,32 @@ function throwFeatureDisabled(feature, option, annotation) {
109
109
 
110
110
  //#endregion
111
111
  //#region packages/typescript/src/runtime/flatten.ts
112
+ /**
113
+ * Flattens an annotated object type into a map of dot-separated paths to their annotated types.
114
+ *
115
+ * For an object like `{ address: { street: string, city: string } }`, the result contains:
116
+ * - `''` → the root object type
117
+ * - `'address'` → the address object type
118
+ * - `'address.street'` → string type
119
+ * - `'address.city'` → string type
120
+ *
121
+ * Arrays are recursed into (their element types are flattened with the same prefix).
122
+ * Unions/intersections/tuples are recursed into (each branch contributes to the same path,
123
+ * merging via synthetic union types when paths collide).
124
+ *
125
+ * @param type - The root annotated type (must be an object type).
126
+ * @param options - Optional hooks for domain-specific processing.
127
+ * @returns A map of dot-separated field paths to their annotated types.
128
+ */ const EMPTY_ANCESTORS = new Set();
129
+ function extendAncestors(ancestors, id) {
130
+ if (!id || ancestors.has(id)) return ancestors;
131
+ const next = new Set(ancestors);
132
+ next.add(id);
133
+ return next;
134
+ }
112
135
  function flattenAnnotatedType(type, options) {
113
136
  const flatMap = new Map();
114
137
  const skipPhantom = !!options?.excludePhantomTypes;
115
- const visitedIds = new Set();
116
138
  function addFieldToFlatMap(name, def) {
117
139
  const existing = flatMap.get(name);
118
140
  if (existing) {
@@ -125,62 +147,60 @@ else flatUnion.item(existing);
125
147
  flatMap.set(name, flatUnion.$type);
126
148
  } else flatMap.set(name, def);
127
149
  }
128
- function flattenArray(def, name) {
150
+ function flattenArray(def, name, ancestors) {
129
151
  const resolvedId = def.id;
130
- if (resolvedId) {
131
- if (visitedIds.has(resolvedId)) return;
132
- visitedIds.add(resolvedId);
133
- }
152
+ if (resolvedId && ancestors.has(resolvedId)) return;
153
+ let childAncestors = extendAncestors(ancestors, resolvedId);
134
154
  switch (def.type.kind) {
135
155
  case "object": {
136
156
  if (!resolvedId && def.id) {
137
- if (visitedIds.has(def.id)) return;
138
- visitedIds.add(def.id);
157
+ if (ancestors.has(def.id)) return;
158
+ childAncestors = extendAncestors(ancestors, def.id);
139
159
  }
140
160
  const items = Array.from(def.type.props.entries());
141
161
  for (const [key, value] of items) {
142
162
  if (skipPhantom && require_json_schema.isPhantomType(value)) continue;
143
- flattenType(value, name ? `${name}.${key}` : key, true);
163
+ flattenType(value, name ? `${name}.${key}` : key, true, childAncestors);
144
164
  }
145
165
  break;
146
166
  }
147
167
  case "union":
148
168
  case "intersection":
149
169
  case "tuple": {
150
- for (const item of def.type.items) flattenArray(item, name);
170
+ for (const item of def.type.items) flattenArray(item, name, childAncestors);
151
171
  break;
152
172
  }
153
173
  case "array": {
154
- flattenArray(def.type.of, name);
174
+ flattenArray(def.type.of, name, childAncestors);
155
175
  break;
156
176
  }
157
177
  default:
158
178
  }
159
179
  }
160
- function flattenType(def, prefix = "", inComplexTypeOrArray = false) {
180
+ function flattenType(def, prefix = "", inComplexTypeOrArray = false, ancestors = EMPTY_ANCESTORS) {
161
181
  let typeId = def.id;
162
- if (typeId && visitedIds.has(typeId)) {
182
+ if (typeId && ancestors.has(typeId)) {
163
183
  addFieldToFlatMap(prefix || "", def);
164
184
  if (prefix) options?.onField?.(prefix, def, def.metadata);
165
185
  return;
166
186
  }
167
- if (typeId) visitedIds.add(typeId);
187
+ let childAncestors = extendAncestors(ancestors, typeId);
168
188
  const kind = def.type.kind;
169
189
  if (!typeId && def.id) {
170
190
  typeId = def.id;
171
- if (visitedIds.has(typeId)) {
191
+ if (ancestors.has(typeId)) {
172
192
  addFieldToFlatMap(prefix || "", def);
173
193
  if (prefix) options?.onField?.(prefix, def, def.metadata);
174
194
  return;
175
195
  }
176
- visitedIds.add(typeId);
196
+ childAncestors = extendAncestors(ancestors, typeId);
177
197
  }
178
198
  switch (kind) {
179
199
  case "object": {
180
200
  addFieldToFlatMap(prefix || "", def);
181
201
  for (const [key, value] of def.type.props.entries()) {
182
202
  if (skipPhantom && require_json_schema.isPhantomType(value)) continue;
183
- flattenType(value, prefix ? `${prefix}.${key}` : key, inComplexTypeOrArray);
203
+ flattenType(value, prefix ? `${prefix}.${key}` : key, inComplexTypeOrArray, childAncestors);
184
204
  }
185
205
  break;
186
206
  }
@@ -192,13 +212,13 @@ else flatUnion.item(existing);
192
212
  if (options?.topLevelArrayTag) typeArray.metadata.set(options.topLevelArrayTag, true);
193
213
  }
194
214
  addFieldToFlatMap(prefix || "", typeArray);
195
- if (!require_json_schema.isAnnotatedTypeOfPrimitive(typeArray.type.of)) flattenArray(typeArray.type.of, prefix);
215
+ if (!require_json_schema.isAnnotatedTypeOfPrimitive(typeArray.type.of)) flattenArray(typeArray.type.of, prefix, childAncestors);
196
216
  break;
197
217
  }
198
218
  case "intersection":
199
219
  case "tuple":
200
220
  case "union": {
201
- for (const item of def.type.items) flattenType(item, prefix, true);
221
+ for (const item of def.type.items) flattenType(item, prefix, true, childAncestors);
202
222
  addFieldToFlatMap(prefix || "", def);
203
223
  if (def.optional) {
204
224
  const entry = flatMap.get(prefix || "");
package/dist/utils.d.ts CHANGED
@@ -456,23 +456,6 @@ interface TFlattenOptions {
456
456
  */
457
457
  excludePhantomTypes?: boolean;
458
458
  }
459
- /**
460
- * Flattens an annotated object type into a map of dot-separated paths to their annotated types.
461
- *
462
- * For an object like `{ address: { street: string, city: string } }`, the result contains:
463
- * - `''` → the root object type
464
- * - `'address'` → the address object type
465
- * - `'address.street'` → string type
466
- * - `'address.city'` → string type
467
- *
468
- * Arrays are recursed into (their element types are flattened with the same prefix).
469
- * Unions/intersections/tuples are recursed into (each branch contributes to the same path,
470
- * merging via synthetic union types when paths collide).
471
- *
472
- * @param type - The root annotated type (must be an object type).
473
- * @param options - Optional hooks for domain-specific processing.
474
- * @returns A map of dot-separated field paths to their annotated types.
475
- */
476
459
  declare function flattenAnnotatedType(type: TAtscriptAnnotatedType<TAtscriptTypeObject>, options?: TFlattenOptions): Map<string, TAtscriptAnnotatedType>;
477
460
 
478
461
  /** Runtime shape of a ref annotation argument (lazy type reference with optional chain). */
package/dist/utils.mjs CHANGED
@@ -108,10 +108,32 @@ function throwFeatureDisabled(feature, option, annotation) {
108
108
 
109
109
  //#endregion
110
110
  //#region packages/typescript/src/runtime/flatten.ts
111
+ /**
112
+ * Flattens an annotated object type into a map of dot-separated paths to their annotated types.
113
+ *
114
+ * For an object like `{ address: { street: string, city: string } }`, the result contains:
115
+ * - `''` → the root object type
116
+ * - `'address'` → the address object type
117
+ * - `'address.street'` → string type
118
+ * - `'address.city'` → string type
119
+ *
120
+ * Arrays are recursed into (their element types are flattened with the same prefix).
121
+ * Unions/intersections/tuples are recursed into (each branch contributes to the same path,
122
+ * merging via synthetic union types when paths collide).
123
+ *
124
+ * @param type - The root annotated type (must be an object type).
125
+ * @param options - Optional hooks for domain-specific processing.
126
+ * @returns A map of dot-separated field paths to their annotated types.
127
+ */ const EMPTY_ANCESTORS = new Set();
128
+ function extendAncestors(ancestors, id) {
129
+ if (!id || ancestors.has(id)) return ancestors;
130
+ const next = new Set(ancestors);
131
+ next.add(id);
132
+ return next;
133
+ }
111
134
  function flattenAnnotatedType(type, options) {
112
135
  const flatMap = new Map();
113
136
  const skipPhantom = !!options?.excludePhantomTypes;
114
- const visitedIds = new Set();
115
137
  function addFieldToFlatMap(name, def) {
116
138
  const existing = flatMap.get(name);
117
139
  if (existing) {
@@ -124,62 +146,60 @@ else flatUnion.item(existing);
124
146
  flatMap.set(name, flatUnion.$type);
125
147
  } else flatMap.set(name, def);
126
148
  }
127
- function flattenArray(def, name) {
149
+ function flattenArray(def, name, ancestors) {
128
150
  const resolvedId = def.id;
129
- if (resolvedId) {
130
- if (visitedIds.has(resolvedId)) return;
131
- visitedIds.add(resolvedId);
132
- }
151
+ if (resolvedId && ancestors.has(resolvedId)) return;
152
+ let childAncestors = extendAncestors(ancestors, resolvedId);
133
153
  switch (def.type.kind) {
134
154
  case "object": {
135
155
  if (!resolvedId && def.id) {
136
- if (visitedIds.has(def.id)) return;
137
- visitedIds.add(def.id);
156
+ if (ancestors.has(def.id)) return;
157
+ childAncestors = extendAncestors(ancestors, def.id);
138
158
  }
139
159
  const items = Array.from(def.type.props.entries());
140
160
  for (const [key, value] of items) {
141
161
  if (skipPhantom && isPhantomType(value)) continue;
142
- flattenType(value, name ? `${name}.${key}` : key, true);
162
+ flattenType(value, name ? `${name}.${key}` : key, true, childAncestors);
143
163
  }
144
164
  break;
145
165
  }
146
166
  case "union":
147
167
  case "intersection":
148
168
  case "tuple": {
149
- for (const item of def.type.items) flattenArray(item, name);
169
+ for (const item of def.type.items) flattenArray(item, name, childAncestors);
150
170
  break;
151
171
  }
152
172
  case "array": {
153
- flattenArray(def.type.of, name);
173
+ flattenArray(def.type.of, name, childAncestors);
154
174
  break;
155
175
  }
156
176
  default:
157
177
  }
158
178
  }
159
- function flattenType(def, prefix = "", inComplexTypeOrArray = false) {
179
+ function flattenType(def, prefix = "", inComplexTypeOrArray = false, ancestors = EMPTY_ANCESTORS) {
160
180
  let typeId = def.id;
161
- if (typeId && visitedIds.has(typeId)) {
181
+ if (typeId && ancestors.has(typeId)) {
162
182
  addFieldToFlatMap(prefix || "", def);
163
183
  if (prefix) options?.onField?.(prefix, def, def.metadata);
164
184
  return;
165
185
  }
166
- if (typeId) visitedIds.add(typeId);
186
+ let childAncestors = extendAncestors(ancestors, typeId);
167
187
  const kind = def.type.kind;
168
188
  if (!typeId && def.id) {
169
189
  typeId = def.id;
170
- if (visitedIds.has(typeId)) {
190
+ if (ancestors.has(typeId)) {
171
191
  addFieldToFlatMap(prefix || "", def);
172
192
  if (prefix) options?.onField?.(prefix, def, def.metadata);
173
193
  return;
174
194
  }
175
- visitedIds.add(typeId);
195
+ childAncestors = extendAncestors(ancestors, typeId);
176
196
  }
177
197
  switch (kind) {
178
198
  case "object": {
179
199
  addFieldToFlatMap(prefix || "", def);
180
200
  for (const [key, value] of def.type.props.entries()) {
181
201
  if (skipPhantom && isPhantomType(value)) continue;
182
- flattenType(value, prefix ? `${prefix}.${key}` : key, inComplexTypeOrArray);
202
+ flattenType(value, prefix ? `${prefix}.${key}` : key, inComplexTypeOrArray, childAncestors);
183
203
  }
184
204
  break;
185
205
  }
@@ -191,13 +211,13 @@ else flatUnion.item(existing);
191
211
  if (options?.topLevelArrayTag) typeArray.metadata.set(options.topLevelArrayTag, true);
192
212
  }
193
213
  addFieldToFlatMap(prefix || "", typeArray);
194
- if (!isAnnotatedTypeOfPrimitive(typeArray.type.of)) flattenArray(typeArray.type.of, prefix);
214
+ if (!isAnnotatedTypeOfPrimitive(typeArray.type.of)) flattenArray(typeArray.type.of, prefix, childAncestors);
195
215
  break;
196
216
  }
197
217
  case "intersection":
198
218
  case "tuple":
199
219
  case "union": {
200
- for (const item of def.type.items) flattenType(item, prefix, true);
220
+ for (const item of def.type.items) flattenType(item, prefix, true, childAncestors);
201
221
  addFieldToFlatMap(prefix || "", def);
202
222
  if (def.optional) {
203
223
  const entry = flatMap.get(prefix || "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/typescript",
3
- "version": "0.1.59",
3
+ "version": "0.1.60",
4
4
  "description": "Atscript: typescript-gen support.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@atscript/db": "^0.1.74",
76
- "@atscript/core": "^0.1.59"
76
+ "@atscript/core": "^0.1.60"
77
77
  },
78
78
  "peerDependenciesMeta": {
79
79
  "@atscript/db": {