@atscript/typescript 0.1.18 → 0.1.20
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 +4 -4
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/utils.cjs +92 -11
- package/dist/utils.d.ts +40 -3
- package/dist/utils.mjs +92 -12
- package/package.json +10 -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 +120 -0
- package/skills/atscript-typescript/core.md +153 -0
- package/skills/atscript-typescript/runtime.md +276 -0
- package/skills/atscript-typescript/syntax.md +252 -0
- package/skills/atscript-typescript/utilities.md +323 -0
- package/skills/atscript-typescript/validation.md +293 -0
package/dist/cli.cjs
CHANGED
|
@@ -690,14 +690,14 @@ else {
|
|
|
690
690
|
passed = false;
|
|
691
691
|
if (this.isLimitExceeded()) return false;
|
|
692
692
|
}
|
|
693
|
-
} else if (this.opts.
|
|
694
|
-
if (this.opts.
|
|
693
|
+
} else if (this.opts.unknownProps !== "ignore") {
|
|
694
|
+
if (this.opts.unknownProps === "error") {
|
|
695
695
|
this.push(key);
|
|
696
696
|
this.error(`Unexpected property`);
|
|
697
697
|
this.pop(true);
|
|
698
698
|
if (this.isLimitExceeded()) return false;
|
|
699
699
|
passed = false;
|
|
700
|
-
} else if (this.opts.
|
|
700
|
+
} else if (this.opts.unknownProps === "strip") delete value[key];
|
|
701
701
|
}
|
|
702
702
|
}
|
|
703
703
|
return passed;
|
|
@@ -849,7 +849,7 @@ else {
|
|
|
849
849
|
this.stackPath = [];
|
|
850
850
|
this.opts = {
|
|
851
851
|
partial: false,
|
|
852
|
-
|
|
852
|
+
unknownProps: "error",
|
|
853
853
|
errorLimit: 10,
|
|
854
854
|
...opts,
|
|
855
855
|
plugins: opts?.plugins || []
|
package/dist/index.cjs
CHANGED
|
@@ -687,14 +687,14 @@ else {
|
|
|
687
687
|
passed = false;
|
|
688
688
|
if (this.isLimitExceeded()) return false;
|
|
689
689
|
}
|
|
690
|
-
} else if (this.opts.
|
|
691
|
-
if (this.opts.
|
|
690
|
+
} else if (this.opts.unknownProps !== "ignore") {
|
|
691
|
+
if (this.opts.unknownProps === "error") {
|
|
692
692
|
this.push(key);
|
|
693
693
|
this.error(`Unexpected property`);
|
|
694
694
|
this.pop(true);
|
|
695
695
|
if (this.isLimitExceeded()) return false;
|
|
696
696
|
passed = false;
|
|
697
|
-
} else if (this.opts.
|
|
697
|
+
} else if (this.opts.unknownProps === "strip") delete value[key];
|
|
698
698
|
}
|
|
699
699
|
}
|
|
700
700
|
return passed;
|
|
@@ -846,7 +846,7 @@ else {
|
|
|
846
846
|
this.stackPath = [];
|
|
847
847
|
this.opts = {
|
|
848
848
|
partial: false,
|
|
849
|
-
|
|
849
|
+
unknownProps: "error",
|
|
850
850
|
errorLimit: 10,
|
|
851
851
|
...opts,
|
|
852
852
|
plugins: opts?.plugins || []
|
package/dist/index.mjs
CHANGED
|
@@ -663,14 +663,14 @@ else {
|
|
|
663
663
|
passed = false;
|
|
664
664
|
if (this.isLimitExceeded()) return false;
|
|
665
665
|
}
|
|
666
|
-
} else if (this.opts.
|
|
667
|
-
if (this.opts.
|
|
666
|
+
} else if (this.opts.unknownProps !== "ignore") {
|
|
667
|
+
if (this.opts.unknownProps === "error") {
|
|
668
668
|
this.push(key);
|
|
669
669
|
this.error(`Unexpected property`);
|
|
670
670
|
this.pop(true);
|
|
671
671
|
if (this.isLimitExceeded()) return false;
|
|
672
672
|
passed = false;
|
|
673
|
-
} else if (this.opts.
|
|
673
|
+
} else if (this.opts.unknownProps === "strip") delete value[key];
|
|
674
674
|
}
|
|
675
675
|
}
|
|
676
676
|
return passed;
|
|
@@ -822,7 +822,7 @@ else {
|
|
|
822
822
|
this.stackPath = [];
|
|
823
823
|
this.opts = {
|
|
824
824
|
partial: false,
|
|
825
|
-
|
|
825
|
+
unknownProps: "error",
|
|
826
826
|
errorLimit: 10,
|
|
827
827
|
...opts,
|
|
828
828
|
plugins: opts?.plugins || []
|
package/dist/utils.cjs
CHANGED
|
@@ -242,14 +242,14 @@ else {
|
|
|
242
242
|
passed = false;
|
|
243
243
|
if (this.isLimitExceeded()) return false;
|
|
244
244
|
}
|
|
245
|
-
} else if (this.opts.
|
|
246
|
-
if (this.opts.
|
|
245
|
+
} else if (this.opts.unknownProps !== "ignore") {
|
|
246
|
+
if (this.opts.unknownProps === "error") {
|
|
247
247
|
this.push(key);
|
|
248
248
|
this.error(`Unexpected property`);
|
|
249
249
|
this.pop(true);
|
|
250
250
|
if (this.isLimitExceeded()) return false;
|
|
251
251
|
passed = false;
|
|
252
|
-
} else if (this.opts.
|
|
252
|
+
} else if (this.opts.unknownProps === "strip") delete value[key];
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
return passed;
|
|
@@ -401,7 +401,7 @@ else {
|
|
|
401
401
|
this.stackPath = [];
|
|
402
402
|
this.opts = {
|
|
403
403
|
partial: false,
|
|
404
|
-
|
|
404
|
+
unknownProps: "error",
|
|
405
405
|
errorLimit: 10,
|
|
406
406
|
...opts,
|
|
407
407
|
plugins: opts?.plugins || []
|
|
@@ -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,86 @@ 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
|
+
|
|
722
802
|
//#endregion
|
|
723
803
|
//#region packages/typescript/src/flatten.ts
|
|
724
804
|
function flattenAnnotatedType(type, options) {
|
|
@@ -969,6 +1049,7 @@ exports.Validator = Validator
|
|
|
969
1049
|
exports.ValidatorError = ValidatorError
|
|
970
1050
|
exports.annotate = annotate
|
|
971
1051
|
exports.buildJsonSchema = buildJsonSchema
|
|
1052
|
+
exports.createDataFromAnnotatedType = createDataFromAnnotatedType
|
|
972
1053
|
exports.defineAnnotatedType = defineAnnotatedType
|
|
973
1054
|
exports.deserializeAnnotatedType = deserializeAnnotatedType
|
|
974
1055
|
exports.flattenAnnotatedType = flattenAnnotatedType
|
package/dist/utils.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ interface TValidatorOptions {
|
|
|
15
15
|
partial: boolean | 'deep' | ((type: TAtscriptAnnotatedType<TAtscriptTypeObject>, path: string) => boolean);
|
|
16
16
|
replace?: (type: TAtscriptAnnotatedType, path: string) => TAtscriptAnnotatedType;
|
|
17
17
|
plugins: TValidatorPlugin[];
|
|
18
|
-
|
|
18
|
+
unknownProps: 'strip' | 'ignore' | 'error';
|
|
19
19
|
errorLimit: number;
|
|
20
20
|
skipList?: Set<string>;
|
|
21
21
|
}
|
|
@@ -305,6 +305,43 @@ 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
|
+
|
|
308
345
|
/**
|
|
309
346
|
* Options for controlling the flattening process.
|
|
310
347
|
*/
|
|
@@ -452,5 +489,5 @@ declare function serializeAnnotatedType(type: TAtscriptAnnotatedType, options?:
|
|
|
452
489
|
*/
|
|
453
490
|
declare function deserializeAnnotatedType(data: TSerializedAnnotatedType): TAtscriptAnnotatedType;
|
|
454
491
|
|
|
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 };
|
|
492
|
+
export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, createDataFromAnnotatedType, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType };
|
|
493
|
+
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
|
@@ -241,14 +241,14 @@ else {
|
|
|
241
241
|
passed = false;
|
|
242
242
|
if (this.isLimitExceeded()) return false;
|
|
243
243
|
}
|
|
244
|
-
} else if (this.opts.
|
|
245
|
-
if (this.opts.
|
|
244
|
+
} else if (this.opts.unknownProps !== "ignore") {
|
|
245
|
+
if (this.opts.unknownProps === "error") {
|
|
246
246
|
this.push(key);
|
|
247
247
|
this.error(`Unexpected property`);
|
|
248
248
|
this.pop(true);
|
|
249
249
|
if (this.isLimitExceeded()) return false;
|
|
250
250
|
passed = false;
|
|
251
|
-
} else if (this.opts.
|
|
251
|
+
} else if (this.opts.unknownProps === "strip") delete value[key];
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
return passed;
|
|
@@ -400,7 +400,7 @@ else {
|
|
|
400
400
|
this.stackPath = [];
|
|
401
401
|
this.opts = {
|
|
402
402
|
partial: false,
|
|
403
|
-
|
|
403
|
+
unknownProps: "error",
|
|
404
404
|
errorLimit: 10,
|
|
405
405
|
...opts,
|
|
406
406
|
plugins: opts?.plugins || []
|
|
@@ -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,86 @@ 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
|
+
|
|
721
801
|
//#endregion
|
|
722
802
|
//#region packages/typescript/src/flatten.ts
|
|
723
803
|
function flattenAnnotatedType(type, options) {
|
|
@@ -963,4 +1043,4 @@ function deserializeTypeDef(t) {
|
|
|
963
1043
|
}
|
|
964
1044
|
|
|
965
1045
|
//#endregion
|
|
966
|
-
export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType };
|
|
1046
|
+
export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, createDataFromAnnotatedType, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, serializeAnnotatedType };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
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.20"
|
|
65
68
|
},
|
|
66
69
|
"build": [
|
|
67
70
|
{},
|
|
@@ -81,6 +84,8 @@
|
|
|
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",
|
|
89
|
+
"postinstall": "node ./scripts/setup-skills.js --postinstall"
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -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
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atscript-typescript
|
|
3
|
+
description: Atscript TypeScript language extension — .as file syntax, code generation, runtime type system, validation, and utilities for the Atscript metadata description language.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @atscript/typescript
|
|
7
|
+
|
|
8
|
+
Atscript is a universal type and metadata description language. `@atscript/typescript` is the TypeScript language extension that compiles `.as` files into `.d.ts` type declarations and `.js` runtime modules with full metadata, validation, and JSON Schema support.
|
|
9
|
+
|
|
10
|
+
## How to use this skill
|
|
11
|
+
|
|
12
|
+
Read the domain file that matches the task. Do not load all files — only what you need.
|
|
13
|
+
|
|
14
|
+
| Domain | File | Load when… |
|
|
15
|
+
|--------|------|------------|
|
|
16
|
+
| Setup & configuration | [core.md](core.md) | Installing, configuring `atscript.config.ts`, using the `tsPlugin`, running the CLI |
|
|
17
|
+
| `.as` file syntax | [syntax.md](syntax.md) | Writing `.as` files — interfaces, types, imports/exports, property syntax |
|
|
18
|
+
| Annotations & primitives | [annotations.md](annotations.md) | Using built-in `@meta.*`/`@expect.*` annotations, defining custom annotations or primitives |
|
|
19
|
+
| Code generation | [codegen.md](codegen.md) | Understanding what `.d.ts` and `.js` files are generated, `atscript.d.ts` global types |
|
|
20
|
+
| Runtime type system | [runtime.md](runtime.md) | Reading/writing metadata, walking type definitions, understanding `TAtscriptAnnotatedType` |
|
|
21
|
+
| Validation | [validation.md](validation.md) | Validating data, type guards, error handling, custom validator plugins |
|
|
22
|
+
| Utility functions | [utilities.md](utilities.md) | Serialization, flattening, JSON Schema, `createDataFromAnnotatedType`, `forAnnotatedType` |
|
|
23
|
+
|
|
24
|
+
## Quick reference
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// Main export (plugin for atscript.config)
|
|
28
|
+
import tsPlugin from '@atscript/typescript'
|
|
29
|
+
|
|
30
|
+
// Runtime utilities (used in app code)
|
|
31
|
+
import {
|
|
32
|
+
defineAnnotatedType, isAnnotatedType, annotate,
|
|
33
|
+
Validator, ValidatorError,
|
|
34
|
+
buildJsonSchema, fromJsonSchema,
|
|
35
|
+
serializeAnnotatedType, deserializeAnnotatedType,
|
|
36
|
+
flattenAnnotatedType, createDataFromAnnotatedType,
|
|
37
|
+
forAnnotatedType,
|
|
38
|
+
} from '@atscript/typescript/utils'
|
|
39
|
+
|
|
40
|
+
// CLI
|
|
41
|
+
// npx asc -f dts — generate .d.ts files
|
|
42
|
+
// npx asc -f js — generate .js files (not usually needed with unplugin)
|
|
43
|
+
// npx asc — generate default formats (for typescript plugin this is d.ts only, but if there are other language plugins it may generate multiple formats)
|
|
44
|
+
```
|