@atscript/typescript 0.1.19 → 0.1.21

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/cli.cjs CHANGED
@@ -334,6 +334,8 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
334
334
  this.writeln(`static validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${asClass}>`);
335
335
  if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
336
336
  this.writeln("static toJsonSchema: () => any");
337
+ if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
338
+ this.writeln("static toExampleData?: () => any");
337
339
  }
338
340
  this.pop();
339
341
  }
@@ -397,6 +399,8 @@ else if ((0, __atscript_core.isPrimitive)(realDef)) typeDef = `TAtscriptTypeFina
397
399
  this.writeln(`const validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${name}>`);
398
400
  if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
399
401
  this.writeln("const toJsonSchema: () => any");
402
+ if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
403
+ this.writeln("const toExampleData: (() => any) | undefined");
400
404
  this.popln();
401
405
  }
402
406
  phantomPropType(def) {
@@ -1081,7 +1085,10 @@ var JsRenderer = class extends BaseRenderer {
1081
1085
  this.writeln("/* eslint-disable */");
1082
1086
  this.writeln("/* oxlint-disable */");
1083
1087
  const imports = ["defineAnnotatedType as $", "annotate as $a"];
1084
- if (resolveJsonSchemaMode(this.opts) === "lazy") imports.push("buildJsonSchema as $$");
1088
+ const jsonSchemaMode = resolveJsonSchemaMode(this.opts);
1089
+ if (jsonSchemaMode === "lazy") imports.push("buildJsonSchema as $$");
1090
+ if (this.opts?.exampleData) imports.push("createDataFromAnnotatedType as $e");
1091
+ if (jsonSchemaMode === false) imports.push("throwFeatureDisabled as $d");
1085
1092
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
1086
1093
  }
1087
1094
  buildAdHocMap(annotateNodes) {
@@ -1127,6 +1134,7 @@ else {
1127
1134
  this.writeln("static type = {}");
1128
1135
  this.writeln("static metadata = new Map()");
1129
1136
  this.renderJsonSchemaMethod(node);
1137
+ this.renderExampleDataMethod(node);
1130
1138
  }
1131
1139
  renderInterface(node) {
1132
1140
  this.writeln();
@@ -1182,7 +1190,14 @@ else {
1182
1190
  this.writeln("}");
1183
1191
  } else {
1184
1192
  this.writeln("static toJsonSchema() {");
1185
- this.indent().writeln("throw new Error(\"JSON Schema support is disabled. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add @emit.jsonSchema annotation to individual interfaces.\")").unindent();
1193
+ this.indent().writeln("$d(\"JSON Schema\", \"jsonSchema\", \"emit.jsonSchema\")").unindent();
1194
+ this.writeln("}");
1195
+ }
1196
+ }
1197
+ renderExampleDataMethod(_node) {
1198
+ if (this.opts?.exampleData) {
1199
+ this.writeln("static toExampleData() {");
1200
+ this.indent().writeln("return $e(this, { mode: \"example\" })").unindent();
1186
1201
  this.writeln("}");
1187
1202
  }
1188
1203
  }
package/dist/index.cjs CHANGED
@@ -331,6 +331,8 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
331
331
  this.writeln(`static validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${asClass}>`);
332
332
  if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
333
333
  this.writeln("static toJsonSchema: () => any");
334
+ if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
335
+ this.writeln("static toExampleData?: () => any");
334
336
  }
335
337
  this.pop();
336
338
  }
@@ -394,6 +396,8 @@ else if ((0, __atscript_core.isPrimitive)(realDef)) typeDef = `TAtscriptTypeFina
394
396
  this.writeln(`const validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${name}>`);
395
397
  if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
396
398
  this.writeln("const toJsonSchema: () => any");
399
+ if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
400
+ this.writeln("const toExampleData: (() => any) | undefined");
397
401
  this.popln();
398
402
  }
399
403
  phantomPropType(def) {
@@ -1078,7 +1082,10 @@ var JsRenderer = class extends BaseRenderer {
1078
1082
  this.writeln("/* eslint-disable */");
1079
1083
  this.writeln("/* oxlint-disable */");
1080
1084
  const imports = ["defineAnnotatedType as $", "annotate as $a"];
1081
- if (resolveJsonSchemaMode(this.opts) === "lazy") imports.push("buildJsonSchema as $$");
1085
+ const jsonSchemaMode = resolveJsonSchemaMode(this.opts);
1086
+ if (jsonSchemaMode === "lazy") imports.push("buildJsonSchema as $$");
1087
+ if (this.opts?.exampleData) imports.push("createDataFromAnnotatedType as $e");
1088
+ if (jsonSchemaMode === false) imports.push("throwFeatureDisabled as $d");
1082
1089
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
1083
1090
  }
1084
1091
  buildAdHocMap(annotateNodes) {
@@ -1124,6 +1131,7 @@ else {
1124
1131
  this.writeln("static type = {}");
1125
1132
  this.writeln("static metadata = new Map()");
1126
1133
  this.renderJsonSchemaMethod(node);
1134
+ this.renderExampleDataMethod(node);
1127
1135
  }
1128
1136
  renderInterface(node) {
1129
1137
  this.writeln();
@@ -1179,7 +1187,14 @@ else {
1179
1187
  this.writeln("}");
1180
1188
  } else {
1181
1189
  this.writeln("static toJsonSchema() {");
1182
- this.indent().writeln("throw new Error(\"JSON Schema support is disabled. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add @emit.jsonSchema annotation to individual interfaces.\")").unindent();
1190
+ this.indent().writeln("$d(\"JSON Schema\", \"jsonSchema\", \"emit.jsonSchema\")").unindent();
1191
+ this.writeln("}");
1192
+ }
1193
+ }
1194
+ renderExampleDataMethod(_node) {
1195
+ if (this.opts?.exampleData) {
1196
+ this.writeln("static toExampleData() {");
1197
+ this.indent().writeln("return $e(this, { mode: \"example\" })").unindent();
1183
1198
  this.writeln("}");
1184
1199
  }
1185
1200
  }
package/dist/index.d.ts CHANGED
@@ -11,6 +11,12 @@ interface TTsPluginOptions {
11
11
  * to force build-time embedding regardless of this setting.
12
12
  */
13
13
  jsonSchema?: false | 'lazy' | 'bundle';
14
+ /**
15
+ * Example data support:
16
+ * - `false` — No support. `toExampleData` is not rendered. *(default)*
17
+ * - `true` — Import `createDataFromAnnotatedType`, create example data on each call.
18
+ */
19
+ exampleData?: boolean;
14
20
  }
15
21
  declare const tsPlugin: (opts?: TTsPluginOptions) => TAtscriptPlugin;
16
22
 
package/dist/index.mjs CHANGED
@@ -307,6 +307,8 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
307
307
  this.writeln(`static validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${asClass}>`);
308
308
  if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
309
309
  this.writeln("static toJsonSchema: () => any");
310
+ if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
311
+ this.writeln("static toExampleData?: () => any");
310
312
  }
311
313
  this.pop();
312
314
  }
@@ -370,6 +372,8 @@ else if (isPrimitive(realDef)) typeDef = `TAtscriptTypeFinal<${name}>`;
370
372
  this.writeln(`const validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${name}>`);
371
373
  if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
372
374
  this.writeln("const toJsonSchema: () => any");
375
+ if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
376
+ this.writeln("const toExampleData: (() => any) | undefined");
373
377
  this.popln();
374
378
  }
375
379
  phantomPropType(def) {
@@ -1054,7 +1058,10 @@ var JsRenderer = class extends BaseRenderer {
1054
1058
  this.writeln("/* eslint-disable */");
1055
1059
  this.writeln("/* oxlint-disable */");
1056
1060
  const imports = ["defineAnnotatedType as $", "annotate as $a"];
1057
- if (resolveJsonSchemaMode(this.opts) === "lazy") imports.push("buildJsonSchema as $$");
1061
+ const jsonSchemaMode = resolveJsonSchemaMode(this.opts);
1062
+ if (jsonSchemaMode === "lazy") imports.push("buildJsonSchema as $$");
1063
+ if (this.opts?.exampleData) imports.push("createDataFromAnnotatedType as $e");
1064
+ if (jsonSchemaMode === false) imports.push("throwFeatureDisabled as $d");
1058
1065
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
1059
1066
  }
1060
1067
  buildAdHocMap(annotateNodes) {
@@ -1100,6 +1107,7 @@ else {
1100
1107
  this.writeln("static type = {}");
1101
1108
  this.writeln("static metadata = new Map()");
1102
1109
  this.renderJsonSchemaMethod(node);
1110
+ this.renderExampleDataMethod(node);
1103
1111
  }
1104
1112
  renderInterface(node) {
1105
1113
  this.writeln();
@@ -1155,7 +1163,14 @@ else {
1155
1163
  this.writeln("}");
1156
1164
  } else {
1157
1165
  this.writeln("static toJsonSchema() {");
1158
- this.indent().writeln("throw new Error(\"JSON Schema support is disabled. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add @emit.jsonSchema annotation to individual interfaces.\")").unindent();
1166
+ this.indent().writeln("$d(\"JSON Schema\", \"jsonSchema\", \"emit.jsonSchema\")").unindent();
1167
+ this.writeln("}");
1168
+ }
1169
+ }
1170
+ renderExampleDataMethod(_node) {
1171
+ if (this.opts?.exampleData) {
1172
+ this.writeln("static toExampleData() {");
1173
+ this.indent().writeln("return $e(this, { mode: \"example\" })").unindent();
1159
1174
  this.writeln("}");
1160
1175
  }
1161
1176
  }
package/dist/utils.cjs CHANGED
@@ -553,7 +553,7 @@ function isAnnotatedTypeOfPrimitive(t) {
553
553
  //#endregion
554
554
  //#region packages/typescript/src/json-schema.ts
555
555
  function buildJsonSchema(type) {
556
- const build = (def) => {
556
+ const build$1 = (def) => {
557
557
  const meta = def.metadata;
558
558
  return forAnnotatedType(def, {
559
559
  phantom() {
@@ -564,7 +564,7 @@ function buildJsonSchema(type) {
564
564
  const required = [];
565
565
  for (const [key, val] of d.type.props.entries()) {
566
566
  if (isPhantomType(val)) continue;
567
- properties[key] = build(val);
567
+ properties[key] = build$1(val);
568
568
  if (!val.optional) required.push(key);
569
569
  }
570
570
  const schema = {
@@ -577,7 +577,7 @@ function buildJsonSchema(type) {
577
577
  array(d) {
578
578
  const schema = {
579
579
  type: "array",
580
- items: build(d.type.of)
580
+ items: build$1(d.type.of)
581
581
  };
582
582
  const minLength = meta.get("expect.minLength");
583
583
  if (minLength) schema.minItems = typeof minLength === "number" ? minLength : minLength.length;
@@ -586,15 +586,15 @@ function buildJsonSchema(type) {
586
586
  return schema;
587
587
  },
588
588
  union(d) {
589
- return { anyOf: d.type.items.map(build) };
589
+ return { anyOf: d.type.items.map(build$1) };
590
590
  },
591
591
  intersection(d) {
592
- return { allOf: d.type.items.map(build) };
592
+ return { allOf: d.type.items.map(build$1) };
593
593
  },
594
594
  tuple(d) {
595
595
  return {
596
596
  type: "array",
597
- items: d.type.items.map(build),
597
+ items: d.type.items.map(build$1),
598
598
  additionalItems: false
599
599
  };
600
600
  },
@@ -625,7 +625,7 @@ else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern:
625
625
  }
626
626
  });
627
627
  };
628
- return build(type);
628
+ return build$1(type);
629
629
  }
630
630
  function fromJsonSchema(schema) {
631
631
  const convert = (s) => {
@@ -719,6 +719,92 @@ function fromJsonSchema(schema) {
719
719
  return convert(schema);
720
720
  }
721
721
 
722
+ //#endregion
723
+ //#region packages/typescript/src/default-value.ts
724
+ /**
725
+ * Attempts to resolve a value from the mode for the given annotated type.
726
+ * Returns `undefined` when no value is available (or parse/validation fails).
727
+ */ function resolveValue(prop, path, mode) {
728
+ if (!mode || mode === "empty") return undefined;
729
+ let raw;
730
+ if (typeof mode === "function") {
731
+ raw = mode(prop, path);
732
+ if (raw === undefined) return undefined;
733
+ if (prop.validator({ unknownProps: "ignore" }).validate(raw, true)) return { value: raw };
734
+ return undefined;
735
+ }
736
+ const metaKey = mode === "default" ? "meta.default" : "meta.example";
737
+ const rawStr = prop.metadata.get(metaKey);
738
+ if (rawStr === undefined) return undefined;
739
+ const parsed = parseRawValue(rawStr, prop);
740
+ if (parsed === undefined) return undefined;
741
+ if (prop.validator({ unknownProps: "ignore" }).validate(parsed, true)) return { value: parsed };
742
+ return undefined;
743
+ }
744
+ /**
745
+ * Parses a raw annotation string into a JS value.
746
+ * Strings are returned as-is for string types; everything else goes through JSON.parse.
747
+ */ function parseRawValue(raw, prop) {
748
+ if (prop.type.kind === "" && prop.type.designType === "string") return raw;
749
+ try {
750
+ return JSON.parse(raw);
751
+ } catch {
752
+ return undefined;
753
+ }
754
+ }
755
+ /** Returns the structural default for a final (primitive/literal) type. */ function finalDefault(def) {
756
+ if (def.type.value !== undefined) return def.type.value;
757
+ switch (def.type.designType) {
758
+ case "string": return "";
759
+ case "number": return 0;
760
+ case "boolean": return false;
761
+ case "undefined": return undefined;
762
+ case "null": return null;
763
+ default: return undefined;
764
+ }
765
+ }
766
+ function createDataFromAnnotatedType(type, opts) {
767
+ return build(type, "", opts?.mode);
768
+ }
769
+ function build(def, path, mode) {
770
+ const resolved = resolveValue(def, path, mode);
771
+ if (resolved !== undefined) return resolved.value;
772
+ return forAnnotatedType(def, {
773
+ phantom: () => undefined,
774
+ final: (d) => finalDefault(d),
775
+ object: (d) => {
776
+ const data = {};
777
+ for (const [key, prop] of d.type.props.entries()) {
778
+ if (isPhantomType(prop)) continue;
779
+ const childPath = path ? `${path}.${key}` : key;
780
+ if (prop.optional) {
781
+ const childResolved = resolveValue(prop, childPath, mode);
782
+ if (childResolved !== undefined) data[key] = childResolved.value;
783
+ continue;
784
+ }
785
+ data[key] = build(prop, childPath, mode);
786
+ }
787
+ return data;
788
+ },
789
+ array: () => [],
790
+ tuple: (d) => d.type.items.map((item, i) => build(item, `${path}.${i}`, mode)),
791
+ union: (d) => {
792
+ const first = d.type.items[0];
793
+ return first ? build(first, path, mode) : undefined;
794
+ },
795
+ intersection: (d) => {
796
+ const first = d.type.items[0];
797
+ return first ? build(first, path, mode) : undefined;
798
+ }
799
+ });
800
+ }
801
+
802
+ //#endregion
803
+ //#region packages/typescript/src/throw-disabled.ts
804
+ function throwFeatureDisabled(feature, option, annotation) {
805
+ throw new Error(`${feature} support is disabled. To enable, set \`${option}: 'lazy'\` or \`${option}: 'bundle'\` in tsPlugin options, or add @${annotation} annotation to individual interfaces.`);
806
+ }
807
+
722
808
  //#endregion
723
809
  //#region packages/typescript/src/flatten.ts
724
810
  function flattenAnnotatedType(type, options) {
@@ -969,6 +1055,7 @@ exports.Validator = Validator
969
1055
  exports.ValidatorError = ValidatorError
970
1056
  exports.annotate = annotate
971
1057
  exports.buildJsonSchema = buildJsonSchema
1058
+ exports.createDataFromAnnotatedType = createDataFromAnnotatedType
972
1059
  exports.defineAnnotatedType = defineAnnotatedType
973
1060
  exports.deserializeAnnotatedType = deserializeAnnotatedType
974
1061
  exports.flattenAnnotatedType = flattenAnnotatedType
@@ -977,4 +1064,5 @@ exports.fromJsonSchema = fromJsonSchema
977
1064
  exports.isAnnotatedType = isAnnotatedType
978
1065
  exports.isAnnotatedTypeOfPrimitive = isAnnotatedTypeOfPrimitive
979
1066
  exports.isPhantomType = isPhantomType
980
- exports.serializeAnnotatedType = serializeAnnotatedType
1067
+ exports.serializeAnnotatedType = serializeAnnotatedType
1068
+ exports.throwFeatureDisabled = throwFeatureDisabled
package/dist/utils.d.ts CHANGED
@@ -305,6 +305,49 @@ declare function forAnnotatedType<R>(def: TAtscriptAnnotatedType, handlers: {
305
305
  phantom?: (def: TAtscriptAnnotatedType<TAtscriptTypeFinal>) => R;
306
306
  }): R;
307
307
 
308
+ /**
309
+ * Custom resolver function for computing field values.
310
+ * Return `undefined` to fall through to structural defaults.
311
+ */
312
+ type TValueResolver = (prop: TAtscriptAnnotatedType, path: string) => unknown | undefined;
313
+ /** Options for {@link createDataFromAnnotatedType}. */
314
+ interface TCreateDataOptions {
315
+ /**
316
+ * How to resolve values:
317
+ * - `'empty'` — structural defaults only (`''`, `0`, `false`, `[]`, `{}`); optional props skipped
318
+ * - `'default'` — use `@meta.default` annotations; optional props skipped unless annotated
319
+ * - `'example'` — use `@meta.example` annotations; optional props skipped unless annotated
320
+ * - `function` — custom resolver per field; optional props skipped unless resolver returns a value
321
+ *
322
+ * @default 'empty'
323
+ */
324
+ mode?: 'empty' | 'default' | 'example' | TValueResolver;
325
+ }
326
+ /**
327
+ * Creates a data object from an ATScript annotated type definition.
328
+ *
329
+ * Supports four modes:
330
+ * - `'empty'` — structural defaults only; optional props omitted
331
+ * - `'default'` — uses `@meta.default` annotations; optional props omitted unless annotated
332
+ * - `'example'` — uses `@meta.example` annotations; optional props omitted unless annotated
333
+ * - `function` — custom resolver; optional props omitted unless resolver returns a value
334
+ *
335
+ * When a `@meta.default` / `@meta.example` value is set on a complex type (object, array)
336
+ * and passes full validation, the entire subtree is replaced — no recursion into inner props.
337
+ * If validation fails, the annotation is ignored and structural defaults are built from inner props.
338
+ *
339
+ * @param type - The ATScript annotated type to create data from.
340
+ * @param opts - Options controlling value resolution mode.
341
+ * @returns A value conforming to the type's shape.
342
+ */
343
+ declare function createDataFromAnnotatedType(type: TAtscriptAnnotatedType, opts?: TCreateDataOptions): unknown;
344
+
345
+ /**
346
+ * Throws a runtime error indicating that a feature is disabled.
347
+ * Used by generated JS files to avoid duplicating the error message string.
348
+ */
349
+ declare function throwFeatureDisabled(feature: string, option: string, annotation: string): never;
350
+
308
351
  /**
309
352
  * Options for controlling the flattening process.
310
353
  */
@@ -452,5 +495,5 @@ declare function serializeAnnotatedType(type: TAtscriptAnnotatedType, options?:
452
495
  */
453
496
  declare function deserializeAnnotatedType(data: TSerializedAnnotatedType): TAtscriptAnnotatedType;
454
497
 
455
- export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType };
456
- export type { InferDataType, TAnnotatedTypeHandle, TAtscriptAnnotatedType, TAtscriptAnnotatedTypeConstructor, TAtscriptTypeArray, TAtscriptTypeComplex, TAtscriptTypeDef, TAtscriptTypeFinal, TAtscriptTypeObject, TFlattenOptions, TMetadataMap, TProcessAnnotationContext, TSerializeOptions, TSerializedAnnotatedType, TSerializedAnnotatedTypeInner, TSerializedTypeArray, TSerializedTypeComplex, TSerializedTypeDef, TSerializedTypeFinal, TSerializedTypeObject, TValidatorOptions, TValidatorPlugin, TValidatorPluginContext };
498
+ export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, createDataFromAnnotatedType, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType, throwFeatureDisabled };
499
+ export type { InferDataType, TAnnotatedTypeHandle, TAtscriptAnnotatedType, TAtscriptAnnotatedTypeConstructor, TAtscriptTypeArray, TAtscriptTypeComplex, TAtscriptTypeDef, TAtscriptTypeFinal, TAtscriptTypeObject, TCreateDataOptions, TFlattenOptions, TMetadataMap, TProcessAnnotationContext, TSerializeOptions, TSerializedAnnotatedType, TSerializedAnnotatedTypeInner, TSerializedTypeArray, TSerializedTypeComplex, TSerializedTypeDef, TSerializedTypeFinal, TSerializedTypeObject, TValidatorOptions, TValidatorPlugin, TValidatorPluginContext, TValueResolver };
package/dist/utils.mjs CHANGED
@@ -552,7 +552,7 @@ function isAnnotatedTypeOfPrimitive(t) {
552
552
  //#endregion
553
553
  //#region packages/typescript/src/json-schema.ts
554
554
  function buildJsonSchema(type) {
555
- const build = (def) => {
555
+ const build$1 = (def) => {
556
556
  const meta = def.metadata;
557
557
  return forAnnotatedType(def, {
558
558
  phantom() {
@@ -563,7 +563,7 @@ function buildJsonSchema(type) {
563
563
  const required = [];
564
564
  for (const [key, val] of d.type.props.entries()) {
565
565
  if (isPhantomType(val)) continue;
566
- properties[key] = build(val);
566
+ properties[key] = build$1(val);
567
567
  if (!val.optional) required.push(key);
568
568
  }
569
569
  const schema = {
@@ -576,7 +576,7 @@ function buildJsonSchema(type) {
576
576
  array(d) {
577
577
  const schema = {
578
578
  type: "array",
579
- items: build(d.type.of)
579
+ items: build$1(d.type.of)
580
580
  };
581
581
  const minLength = meta.get("expect.minLength");
582
582
  if (minLength) schema.minItems = typeof minLength === "number" ? minLength : minLength.length;
@@ -585,15 +585,15 @@ function buildJsonSchema(type) {
585
585
  return schema;
586
586
  },
587
587
  union(d) {
588
- return { anyOf: d.type.items.map(build) };
588
+ return { anyOf: d.type.items.map(build$1) };
589
589
  },
590
590
  intersection(d) {
591
- return { allOf: d.type.items.map(build) };
591
+ return { allOf: d.type.items.map(build$1) };
592
592
  },
593
593
  tuple(d) {
594
594
  return {
595
595
  type: "array",
596
- items: d.type.items.map(build),
596
+ items: d.type.items.map(build$1),
597
597
  additionalItems: false
598
598
  };
599
599
  },
@@ -624,7 +624,7 @@ else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern:
624
624
  }
625
625
  });
626
626
  };
627
- return build(type);
627
+ return build$1(type);
628
628
  }
629
629
  function fromJsonSchema(schema) {
630
630
  const convert = (s) => {
@@ -718,6 +718,92 @@ function fromJsonSchema(schema) {
718
718
  return convert(schema);
719
719
  }
720
720
 
721
+ //#endregion
722
+ //#region packages/typescript/src/default-value.ts
723
+ /**
724
+ * Attempts to resolve a value from the mode for the given annotated type.
725
+ * Returns `undefined` when no value is available (or parse/validation fails).
726
+ */ function resolveValue(prop, path, mode) {
727
+ if (!mode || mode === "empty") return undefined;
728
+ let raw;
729
+ if (typeof mode === "function") {
730
+ raw = mode(prop, path);
731
+ if (raw === undefined) return undefined;
732
+ if (prop.validator({ unknownProps: "ignore" }).validate(raw, true)) return { value: raw };
733
+ return undefined;
734
+ }
735
+ const metaKey = mode === "default" ? "meta.default" : "meta.example";
736
+ const rawStr = prop.metadata.get(metaKey);
737
+ if (rawStr === undefined) return undefined;
738
+ const parsed = parseRawValue(rawStr, prop);
739
+ if (parsed === undefined) return undefined;
740
+ if (prop.validator({ unknownProps: "ignore" }).validate(parsed, true)) return { value: parsed };
741
+ return undefined;
742
+ }
743
+ /**
744
+ * Parses a raw annotation string into a JS value.
745
+ * Strings are returned as-is for string types; everything else goes through JSON.parse.
746
+ */ function parseRawValue(raw, prop) {
747
+ if (prop.type.kind === "" && prop.type.designType === "string") return raw;
748
+ try {
749
+ return JSON.parse(raw);
750
+ } catch {
751
+ return undefined;
752
+ }
753
+ }
754
+ /** Returns the structural default for a final (primitive/literal) type. */ function finalDefault(def) {
755
+ if (def.type.value !== undefined) return def.type.value;
756
+ switch (def.type.designType) {
757
+ case "string": return "";
758
+ case "number": return 0;
759
+ case "boolean": return false;
760
+ case "undefined": return undefined;
761
+ case "null": return null;
762
+ default: return undefined;
763
+ }
764
+ }
765
+ function createDataFromAnnotatedType(type, opts) {
766
+ return build(type, "", opts?.mode);
767
+ }
768
+ function build(def, path, mode) {
769
+ const resolved = resolveValue(def, path, mode);
770
+ if (resolved !== undefined) return resolved.value;
771
+ return forAnnotatedType(def, {
772
+ phantom: () => undefined,
773
+ final: (d) => finalDefault(d),
774
+ object: (d) => {
775
+ const data = {};
776
+ for (const [key, prop] of d.type.props.entries()) {
777
+ if (isPhantomType(prop)) continue;
778
+ const childPath = path ? `${path}.${key}` : key;
779
+ if (prop.optional) {
780
+ const childResolved = resolveValue(prop, childPath, mode);
781
+ if (childResolved !== undefined) data[key] = childResolved.value;
782
+ continue;
783
+ }
784
+ data[key] = build(prop, childPath, mode);
785
+ }
786
+ return data;
787
+ },
788
+ array: () => [],
789
+ tuple: (d) => d.type.items.map((item, i) => build(item, `${path}.${i}`, mode)),
790
+ union: (d) => {
791
+ const first = d.type.items[0];
792
+ return first ? build(first, path, mode) : undefined;
793
+ },
794
+ intersection: (d) => {
795
+ const first = d.type.items[0];
796
+ return first ? build(first, path, mode) : undefined;
797
+ }
798
+ });
799
+ }
800
+
801
+ //#endregion
802
+ //#region packages/typescript/src/throw-disabled.ts
803
+ function throwFeatureDisabled(feature, option, annotation) {
804
+ throw new Error(`${feature} support is disabled. To enable, set \`${option}: 'lazy'\` or \`${option}: 'bundle'\` in tsPlugin options, or add @${annotation} annotation to individual interfaces.`);
805
+ }
806
+
721
807
  //#endregion
722
808
  //#region packages/typescript/src/flatten.ts
723
809
  function flattenAnnotatedType(type, options) {
@@ -963,4 +1049,4 @@ function deserializeTypeDef(t) {
963
1049
  }
964
1050
 
965
1051
  //#endregion
966
- export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType };
1052
+ export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, createDataFromAnnotatedType, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType, throwFeatureDisabled };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/typescript",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "Atscript: typescript-gen support.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -19,11 +19,14 @@
19
19
  "directory": "packages/typescript"
20
20
  },
21
21
  "bin": {
22
- "asc": "./cli.cjs"
22
+ "asc": "./cli.cjs",
23
+ "setup-skills": "./scripts/setup-skills.js"
23
24
  },
24
25
  "files": [
25
26
  "dist",
26
- "cli.cjs"
27
+ "cli.cjs",
28
+ "skills",
29
+ "scripts/setup-skills.js"
27
30
  ],
28
31
  "type": "module",
29
32
  "main": "dist/index.mjs",
@@ -61,7 +64,7 @@
61
64
  "vitest": "3.2.4"
62
65
  },
63
66
  "peerDependencies": {
64
- "@atscript/core": "^0.1.19"
67
+ "@atscript/core": "^0.1.21"
65
68
  },
66
69
  "build": [
67
70
  {},
@@ -81,6 +84,7 @@
81
84
  ],
82
85
  "scripts": {
83
86
  "pub": "pnpm publish --access public",
84
- "test": "vitest"
87
+ "test": "vitest",
88
+ "setup-skills": "node ./scripts/setup-skills.js"
85
89
  }
86
90
  }
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ /* prettier-ignore */
3
+ import fs from 'fs'
4
+ import path from 'path'
5
+ import os from 'os'
6
+ import { fileURLToPath } from 'url'
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
9
+
10
+ const SKILL_NAME = 'atscript-typescript'
11
+ const SKILL_SRC = path.join(__dirname, '..', 'skills', SKILL_NAME)
12
+
13
+ if (!fs.existsSync(SKILL_SRC)) {
14
+ console.error(`No skills found at ${SKILL_SRC}`)
15
+ console.error('Add your SKILL.md files to the skills/' + SKILL_NAME + '/ directory first.')
16
+ process.exit(1)
17
+ }
18
+
19
+ const AGENTS = {
20
+ 'Claude Code': { dir: '.claude/skills', global: path.join(os.homedir(), '.claude', 'skills') },
21
+ 'Cursor': { dir: '.cursor/skills', global: path.join(os.homedir(), '.cursor', 'skills') },
22
+ 'Windsurf': { dir: '.windsurf/skills', global: path.join(os.homedir(), '.windsurf', 'skills') },
23
+ 'Codex': { dir: '.codex/skills', global: path.join(os.homedir(), '.codex', 'skills') },
24
+ 'OpenCode': { dir: '.opencode/skills', global: path.join(os.homedir(), '.opencode', 'skills') },
25
+ }
26
+
27
+ const args = process.argv.slice(2)
28
+ const isGlobal = args.includes('--global') || args.includes('-g')
29
+ const isPostinstall = args.includes('--postinstall')
30
+ let installed = 0, skipped = 0
31
+ const installedDirs = []
32
+
33
+ for (const [agentName, cfg] of Object.entries(AGENTS)) {
34
+ const targetBase = isGlobal ? cfg.global : path.join(process.cwd(), cfg.dir)
35
+ const agentRootDir = path.dirname(cfg.global) // Check if the agent has ever been installed globally
36
+
37
+ // In postinstall mode: silently skip agents that aren't set up globally
38
+ if (isPostinstall || isGlobal) {
39
+ if (!fs.existsSync(agentRootDir)) { skipped++; continue }
40
+ }
41
+
42
+ const dest = path.join(targetBase, SKILL_NAME)
43
+ try {
44
+ fs.mkdirSync(dest, { recursive: true })
45
+ fs.cpSync(SKILL_SRC, dest, { recursive: true })
46
+ console.log(`✅ ${agentName}: installed to ${dest}`)
47
+ installed++
48
+ if (!isGlobal) installedDirs.push(cfg.dir + '/' + SKILL_NAME)
49
+ } catch (err) {
50
+ console.warn(`⚠️ ${agentName}: failed — ${err.message}`)
51
+ }
52
+ }
53
+
54
+ // Add locally-installed skill dirs to .gitignore
55
+ if (!isGlobal && installedDirs.length > 0) {
56
+ const gitignorePath = path.join(process.cwd(), '.gitignore')
57
+ let gitignoreContent = ''
58
+ try { gitignoreContent = fs.readFileSync(gitignorePath, 'utf8') } catch {}
59
+ const linesToAdd = installedDirs.filter(d => !gitignoreContent.includes(d))
60
+ if (linesToAdd.length > 0) {
61
+ const hasHeader = gitignoreContent.includes('# AI agent skills')
62
+ const block = (gitignoreContent && !gitignoreContent.endsWith('\n') ? '\n' : '')
63
+ + (hasHeader ? '' : '\n# AI agent skills (auto-generated by setup-skills)\n')
64
+ + linesToAdd.join('\n') + '\n'
65
+ fs.appendFileSync(gitignorePath, block)
66
+ console.log(`📝 Added ${linesToAdd.length} entries to .gitignore`)
67
+ }
68
+ }
69
+
70
+ if (installed === 0 && isPostinstall) {
71
+ // Silence is fine — no agents present, nothing to do
72
+ } else if (installed === 0 && skipped === Object.keys(AGENTS).length) {
73
+ console.log('No agent directories detected. Try --global or run without it for project-local install.')
74
+ } else if (installed === 0) {
75
+ console.log('Nothing installed. Run without --global to install project-locally.')
76
+ } else {
77
+ console.log(`\n✨ Done! Restart your AI agent to pick up the "${SKILL_NAME}" skill.`)
78
+ }
File without changes