@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 +17 -2
- package/dist/index.cjs +17 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +17 -2
- package/dist/utils.cjs +96 -8
- package/dist/utils.d.ts +45 -2
- package/dist/utils.mjs +94 -8
- package/package.json +9 -5
- package/scripts/setup-skills.js +78 -0
- package/skills/atscript-typescript/.gitkeep +0 -0
- package/skills/atscript-typescript/SKILL.md +44 -0
- package/skills/atscript-typescript/annotations.md +240 -0
- package/skills/atscript-typescript/codegen.md +126 -0
- package/skills/atscript-typescript/core.md +164 -0
- package/skills/atscript-typescript/runtime.md +276 -0
- package/skills/atscript-typescript/syntax.md +252 -0
- package/skills/atscript-typescript/utilities.md +329 -0
- package/skills/atscript-typescript/validation.md +293 -0
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
|
-
|
|
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("
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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("
|
|
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.
|
|
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.
|
|
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
|