@atscript/typescript 0.1.26 → 0.1.28
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/README.md +50 -0
- package/dist/cli.cjs +4 -4
- package/dist/index.cjs +7 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +5 -9
- package/dist/utils.cjs +12 -1
- package/dist/utils.d.ts +4 -2
- package/dist/utils.mjs +12 -1
- package/package.json +5 -5
- package/scripts/setup-skills.js +23 -13
- package/skills/atscript-typescript/SKILL.md +23 -15
- package/skills/atscript-typescript/annotations.md +78 -60
- package/skills/atscript-typescript/codegen.md +14 -10
- package/skills/atscript-typescript/core.md +23 -21
- package/skills/atscript-typescript/runtime.md +66 -54
- package/skills/atscript-typescript/syntax.md +31 -31
- package/skills/atscript-typescript/utilities.md +94 -67
- package/skills/atscript-typescript/validation.md +39 -39
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @atscript/typescript
|
|
2
|
+
|
|
3
|
+
TypeScript language extension for [Atscript](https://atscript.moost.org). Compiles `.as` files into `.d.ts` type declarations and `.js` runtime modules with full metadata, validation, and JSON Schema support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @atscript/typescript @atscript/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For build-tool integration (Vite, Webpack, Rollup, esbuild, Rspack), also add:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add unplugin-atscript
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## AI Agent Skills
|
|
18
|
+
|
|
19
|
+
This package ships with structured skill files for AI coding agents (Claude Code, Cursor, Windsurf, Codex, etc.).
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Project-local (recommended — version-locked, commits with your repo)
|
|
23
|
+
npx atscript-typescript-skill
|
|
24
|
+
|
|
25
|
+
# Global (available across all your projects)
|
|
26
|
+
npx atscript-typescript-skill --global
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
To keep skills automatically up-to-date, add a postinstall script to your `package.json`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"scripts": {
|
|
34
|
+
"postinstall": "atscript-typescript-skill --postinstall"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **Type declarations** — `.d.ts` files from `.as` interfaces and types
|
|
42
|
+
- **Runtime metadata** — `.js` files with full metadata for validators and serializers
|
|
43
|
+
- **JSON Schema** — Build, parse, and merge JSON schemas from annotated types
|
|
44
|
+
- **Validation** — Validate data against types with plugin support
|
|
45
|
+
- **Serialization** — JSON-safe round-trip serialization/deserialization
|
|
46
|
+
- **CLI** — `asc` command for compiling `.as` files
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
Full documentation: [atscript.moost.org](https://atscript.moost.org)
|
package/dist/cli.cjs
CHANGED
|
@@ -1089,7 +1089,7 @@ function buildJsonSchema(type) {
|
|
|
1089
1089
|
const oneOf = d.type.items.map(build$1);
|
|
1090
1090
|
const mapping = {};
|
|
1091
1091
|
for (const [val, origPath] of Object.entries(disc.mapping)) {
|
|
1092
|
-
const idx = Number.parseInt(origPath.split("/").pop());
|
|
1092
|
+
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
1093
1093
|
const item = d.type.items[idx];
|
|
1094
1094
|
if (item.id && defs[item.id]) mapping[val] = `#/$defs/${item.id}`;
|
|
1095
1095
|
else mapping[val] = origPath;
|
|
@@ -1176,7 +1176,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
1176
1176
|
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
|
|
1177
1177
|
const nameCounts = new Map();
|
|
1178
1178
|
const nodesByName = new Map();
|
|
1179
|
-
for (const node of this.doc.nodes) if (node.__typeId
|
|
1179
|
+
for (const node of this.doc.nodes) if (node.__typeId !== null && node.__typeId !== undefined && node.id) {
|
|
1180
1180
|
const name = node.id;
|
|
1181
1181
|
nameCounts.set(name, (nameCounts.get(name) || 0) + 1);
|
|
1182
1182
|
if (!nodesByName.has(name)) nodesByName.set(name, []);
|
|
@@ -1202,7 +1202,7 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
|
|
|
1202
1202
|
* meaning annotations target properties inside a referenced type.
|
|
1203
1203
|
*/ hasAdHocAnnotationsThroughRef() {
|
|
1204
1204
|
if (!this._adHocAnnotations || this._propPath.length === 0) return false;
|
|
1205
|
-
const prefix = this._propPath.join(".")
|
|
1205
|
+
const prefix = `${this._propPath.join(".")}.`;
|
|
1206
1206
|
for (const key of this._adHocAnnotations.keys()) if (key.startsWith(prefix)) return true;
|
|
1207
1207
|
return false;
|
|
1208
1208
|
}
|
|
@@ -1316,7 +1316,7 @@ else {
|
|
|
1316
1316
|
case "type": {
|
|
1317
1317
|
const def = node.getDefinition();
|
|
1318
1318
|
const handle = this.toAnnotatedHandle(def, true);
|
|
1319
|
-
const typeId = this.typeIds.get(node) ?? (node.__typeId
|
|
1319
|
+
const typeId = this.typeIds.get(node) ?? (node.__typeId !== null && node.__typeId !== undefined ? node.id : undefined);
|
|
1320
1320
|
if (typeId) handle.id(typeId);
|
|
1321
1321
|
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1322
1322
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
3
|
//#region rolldown:runtime
|
|
3
4
|
var __create = Object.create;
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
@@ -1086,7 +1087,7 @@ function buildJsonSchema(type) {
|
|
|
1086
1087
|
const oneOf = d.type.items.map(build);
|
|
1087
1088
|
const mapping = {};
|
|
1088
1089
|
for (const [val, origPath] of Object.entries(disc.mapping)) {
|
|
1089
|
-
const idx = Number.parseInt(origPath.split("/").pop());
|
|
1090
|
+
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
1090
1091
|
const item = d.type.items[idx];
|
|
1091
1092
|
if (item.id && defs[item.id]) mapping[val] = `#/$defs/${item.id}`;
|
|
1092
1093
|
else mapping[val] = origPath;
|
|
@@ -1173,7 +1174,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
1173
1174
|
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
|
|
1174
1175
|
const nameCounts = new Map();
|
|
1175
1176
|
const nodesByName = new Map();
|
|
1176
|
-
for (const node of this.doc.nodes) if (node.__typeId
|
|
1177
|
+
for (const node of this.doc.nodes) if (node.__typeId !== null && node.__typeId !== undefined && node.id) {
|
|
1177
1178
|
const name = node.id;
|
|
1178
1179
|
nameCounts.set(name, (nameCounts.get(name) || 0) + 1);
|
|
1179
1180
|
if (!nodesByName.has(name)) nodesByName.set(name, []);
|
|
@@ -1199,7 +1200,7 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
|
|
|
1199
1200
|
* meaning annotations target properties inside a referenced type.
|
|
1200
1201
|
*/ hasAdHocAnnotationsThroughRef() {
|
|
1201
1202
|
if (!this._adHocAnnotations || this._propPath.length === 0) return false;
|
|
1202
|
-
const prefix = this._propPath.join(".")
|
|
1203
|
+
const prefix = `${this._propPath.join(".")}.`;
|
|
1203
1204
|
for (const key of this._adHocAnnotations.keys()) if (key.startsWith(prefix)) return true;
|
|
1204
1205
|
return false;
|
|
1205
1206
|
}
|
|
@@ -1313,7 +1314,7 @@ else {
|
|
|
1313
1314
|
case "type": {
|
|
1314
1315
|
const def = node.getDefinition();
|
|
1315
1316
|
const handle = this.toAnnotatedHandle(def, true);
|
|
1316
|
-
const typeId = this.typeIds.get(node) ?? (node.__typeId
|
|
1317
|
+
const typeId = this.typeIds.get(node) ?? (node.__typeId !== null && node.__typeId !== undefined ? node.id : undefined);
|
|
1317
1318
|
if (typeId) handle.id(typeId);
|
|
1318
1319
|
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1319
1320
|
}
|
|
@@ -1870,8 +1871,5 @@ else return t.optional ? `${t.type} | true` : t.type;
|
|
|
1870
1871
|
};
|
|
1871
1872
|
|
|
1872
1873
|
//#endregion
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
//#endregion
|
|
1877
|
-
module.exports = src_default;
|
|
1874
|
+
exports.default = tsPlugin
|
|
1875
|
+
exports.tsPlugin = tsPlugin
|
package/dist/index.d.ts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1062,7 +1062,7 @@ function buildJsonSchema(type) {
|
|
|
1062
1062
|
const oneOf = d.type.items.map(build);
|
|
1063
1063
|
const mapping = {};
|
|
1064
1064
|
for (const [val, origPath] of Object.entries(disc.mapping)) {
|
|
1065
|
-
const idx = Number.parseInt(origPath.split("/").pop());
|
|
1065
|
+
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
1066
1066
|
const item = d.type.items[idx];
|
|
1067
1067
|
if (item.id && defs[item.id]) mapping[val] = `#/$defs/${item.id}`;
|
|
1068
1068
|
else mapping[val] = origPath;
|
|
@@ -1149,7 +1149,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
1149
1149
|
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
|
|
1150
1150
|
const nameCounts = new Map();
|
|
1151
1151
|
const nodesByName = new Map();
|
|
1152
|
-
for (const node of this.doc.nodes) if (node.__typeId
|
|
1152
|
+
for (const node of this.doc.nodes) if (node.__typeId !== null && node.__typeId !== undefined && node.id) {
|
|
1153
1153
|
const name = node.id;
|
|
1154
1154
|
nameCounts.set(name, (nameCounts.get(name) || 0) + 1);
|
|
1155
1155
|
if (!nodesByName.has(name)) nodesByName.set(name, []);
|
|
@@ -1175,7 +1175,7 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
|
|
|
1175
1175
|
* meaning annotations target properties inside a referenced type.
|
|
1176
1176
|
*/ hasAdHocAnnotationsThroughRef() {
|
|
1177
1177
|
if (!this._adHocAnnotations || this._propPath.length === 0) return false;
|
|
1178
|
-
const prefix = this._propPath.join(".")
|
|
1178
|
+
const prefix = `${this._propPath.join(".")}.`;
|
|
1179
1179
|
for (const key of this._adHocAnnotations.keys()) if (key.startsWith(prefix)) return true;
|
|
1180
1180
|
return false;
|
|
1181
1181
|
}
|
|
@@ -1289,7 +1289,7 @@ else {
|
|
|
1289
1289
|
case "type": {
|
|
1290
1290
|
const def = node.getDefinition();
|
|
1291
1291
|
const handle = this.toAnnotatedHandle(def, true);
|
|
1292
|
-
const typeId = this.typeIds.get(node) ?? (node.__typeId
|
|
1292
|
+
const typeId = this.typeIds.get(node) ?? (node.__typeId !== null && node.__typeId !== undefined ? node.id : undefined);
|
|
1293
1293
|
if (typeId) handle.id(typeId);
|
|
1294
1294
|
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1295
1295
|
}
|
|
@@ -1846,8 +1846,4 @@ else return t.optional ? `${t.type} | true` : t.type;
|
|
|
1846
1846
|
};
|
|
1847
1847
|
|
|
1848
1848
|
//#endregion
|
|
1849
|
-
|
|
1850
|
-
var src_default = tsPlugin;
|
|
1851
|
-
|
|
1852
|
-
//#endregion
|
|
1853
|
-
export { src_default as default };
|
|
1849
|
+
export { tsPlugin as default, tsPlugin };
|
package/dist/utils.cjs
CHANGED
|
@@ -707,7 +707,7 @@ function buildJsonSchema(type) {
|
|
|
707
707
|
const oneOf = d.type.items.map(build$1);
|
|
708
708
|
const mapping = {};
|
|
709
709
|
for (const [val, origPath] of Object.entries(disc.mapping)) {
|
|
710
|
-
const idx = Number.parseInt(origPath.split("/").pop());
|
|
710
|
+
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
711
711
|
const item = d.type.items[idx];
|
|
712
712
|
if (item.id && defs[item.id]) mapping[val] = `#/$defs/${item.id}`;
|
|
713
713
|
else mapping[val] = origPath;
|
|
@@ -901,6 +901,17 @@ function mergeJsonSchemas(types) {
|
|
|
901
901
|
if (prop.validator({ unknownProps: "ignore" }).validate(raw, true)) return { value: raw };
|
|
902
902
|
return undefined;
|
|
903
903
|
}
|
|
904
|
+
if (mode === "db") {
|
|
905
|
+
const dbValue = prop.metadata.get("db.default.value");
|
|
906
|
+
if (dbValue !== undefined) {
|
|
907
|
+
const parsed$1 = parseRawValue(dbValue, prop);
|
|
908
|
+
if (parsed$1 !== undefined && prop.validator({ unknownProps: "ignore" }).validate(parsed$1, true)) return { value: parsed$1 };
|
|
909
|
+
return undefined;
|
|
910
|
+
}
|
|
911
|
+
const dbFn = prop.metadata.get("db.default.fn");
|
|
912
|
+
if (dbFn !== undefined) return { value: dbFn };
|
|
913
|
+
return undefined;
|
|
914
|
+
}
|
|
904
915
|
const metaKey = mode === "default" ? "meta.default" : "meta.example";
|
|
905
916
|
const rawStr = prop.metadata.get(metaKey);
|
|
906
917
|
if (rawStr === undefined) return undefined;
|
package/dist/utils.d.ts
CHANGED
|
@@ -354,19 +354,21 @@ interface TCreateDataOptions {
|
|
|
354
354
|
* - `'empty'` — structural defaults only (`''`, `0`, `false`, `[]`, `{}`); optional props skipped
|
|
355
355
|
* - `'default'` — use `@meta.default` annotations; optional props skipped unless annotated
|
|
356
356
|
* - `'example'` — use `@meta.example` annotations; optional props always included; arrays get one sample item
|
|
357
|
+
* - `'db'` — use `@db.default.value` (parsed) or `@db.default.fn` (returns fn name string); optional props skipped unless annotated
|
|
357
358
|
* - `function` — custom resolver per field; optional props skipped unless resolver returns a value
|
|
358
359
|
*
|
|
359
360
|
* @default 'empty'
|
|
360
361
|
*/
|
|
361
|
-
mode?: 'empty' | 'default' | 'example' | TValueResolver;
|
|
362
|
+
mode?: 'empty' | 'default' | 'example' | 'db' | TValueResolver;
|
|
362
363
|
}
|
|
363
364
|
/**
|
|
364
365
|
* Creates a data object from an ATScript annotated type definition.
|
|
365
366
|
*
|
|
366
|
-
* Supports
|
|
367
|
+
* Supports five modes:
|
|
367
368
|
* - `'empty'` — structural defaults only; optional props omitted
|
|
368
369
|
* - `'default'` — uses `@meta.default` annotations; optional props omitted unless annotated
|
|
369
370
|
* - `'example'` — uses `@meta.example` annotations; optional props always included; arrays get one sample item
|
|
371
|
+
* - `'db'` — uses `@db.default.value` (parsed) or `@db.default.fn` (fn name string); optional props omitted unless annotated
|
|
370
372
|
* - `function` — custom resolver; optional props omitted unless resolver returns a value
|
|
371
373
|
*
|
|
372
374
|
* When a `@meta.default` / `@meta.example` value is set on a complex type (object, array)
|
package/dist/utils.mjs
CHANGED
|
@@ -706,7 +706,7 @@ function buildJsonSchema(type) {
|
|
|
706
706
|
const oneOf = d.type.items.map(build$1);
|
|
707
707
|
const mapping = {};
|
|
708
708
|
for (const [val, origPath] of Object.entries(disc.mapping)) {
|
|
709
|
-
const idx = Number.parseInt(origPath.split("/").pop());
|
|
709
|
+
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
710
710
|
const item = d.type.items[idx];
|
|
711
711
|
if (item.id && defs[item.id]) mapping[val] = `#/$defs/${item.id}`;
|
|
712
712
|
else mapping[val] = origPath;
|
|
@@ -900,6 +900,17 @@ function mergeJsonSchemas(types) {
|
|
|
900
900
|
if (prop.validator({ unknownProps: "ignore" }).validate(raw, true)) return { value: raw };
|
|
901
901
|
return undefined;
|
|
902
902
|
}
|
|
903
|
+
if (mode === "db") {
|
|
904
|
+
const dbValue = prop.metadata.get("db.default.value");
|
|
905
|
+
if (dbValue !== undefined) {
|
|
906
|
+
const parsed$1 = parseRawValue(dbValue, prop);
|
|
907
|
+
if (parsed$1 !== undefined && prop.validator({ unknownProps: "ignore" }).validate(parsed$1, true)) return { value: parsed$1 };
|
|
908
|
+
return undefined;
|
|
909
|
+
}
|
|
910
|
+
const dbFn = prop.metadata.get("db.default.fn");
|
|
911
|
+
if (dbFn !== undefined) return { value: dbFn };
|
|
912
|
+
return undefined;
|
|
913
|
+
}
|
|
903
914
|
const metaKey = mode === "default" ? "meta.default" : "meta.example";
|
|
904
915
|
const rawStr = prop.metadata.get(metaKey);
|
|
905
916
|
if (rawStr === undefined) return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
4
4
|
"description": "Atscript: typescript-gen support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"bin": {
|
|
22
22
|
"asc": "./cli.cjs",
|
|
23
|
-
"
|
|
23
|
+
"atscript-typescript-skill": "./scripts/setup-skills.js"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
@@ -57,14 +57,14 @@
|
|
|
57
57
|
"./package.json": "./package.json"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@moostjs/event-cli": "^0.
|
|
61
|
-
"moost": "^0.
|
|
60
|
+
"@moostjs/event-cli": "^0.6.2",
|
|
61
|
+
"moost": "^0.6.2"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"vitest": "3.2.4"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@atscript/core": "^0.1.
|
|
67
|
+
"@atscript/core": "^0.1.28"
|
|
68
68
|
},
|
|
69
69
|
"build": [
|
|
70
70
|
{},
|
package/scripts/setup-skills.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/* prettier-ignore */
|
|
3
3
|
import fs from 'fs'
|
|
4
|
-
import path from 'path'
|
|
5
4
|
import os from 'os'
|
|
5
|
+
import path from 'path'
|
|
6
6
|
import { fileURLToPath } from 'url'
|
|
7
7
|
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
@@ -17,17 +17,18 @@ if (!fs.existsSync(SKILL_SRC)) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const AGENTS = {
|
|
20
|
-
'Claude Code': { dir: '.claude/skills',
|
|
21
|
-
'Cursor':
|
|
22
|
-
'Windsurf':
|
|
23
|
-
'Codex':
|
|
24
|
-
'OpenCode':
|
|
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
25
|
}
|
|
26
26
|
|
|
27
27
|
const args = process.argv.slice(2)
|
|
28
28
|
const isGlobal = args.includes('--global') || args.includes('-g')
|
|
29
29
|
const isPostinstall = args.includes('--postinstall')
|
|
30
|
-
let installed = 0,
|
|
30
|
+
let installed = 0,
|
|
31
|
+
skipped = 0
|
|
31
32
|
const installedDirs = []
|
|
32
33
|
|
|
33
34
|
for (const [agentName, cfg] of Object.entries(AGENTS)) {
|
|
@@ -36,7 +37,10 @@ for (const [agentName, cfg] of Object.entries(AGENTS)) {
|
|
|
36
37
|
|
|
37
38
|
// In postinstall mode: silently skip agents that aren't set up globally
|
|
38
39
|
if (isPostinstall || isGlobal) {
|
|
39
|
-
if (!fs.existsSync(agentRootDir)) {
|
|
40
|
+
if (!fs.existsSync(agentRootDir)) {
|
|
41
|
+
skipped++
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
const dest = path.join(targetBase, SKILL_NAME)
|
|
@@ -55,13 +59,17 @@ for (const [agentName, cfg] of Object.entries(AGENTS)) {
|
|
|
55
59
|
if (!isGlobal && installedDirs.length > 0) {
|
|
56
60
|
const gitignorePath = path.join(process.cwd(), '.gitignore')
|
|
57
61
|
let gitignoreContent = ''
|
|
58
|
-
try {
|
|
62
|
+
try {
|
|
63
|
+
gitignoreContent = fs.readFileSync(gitignorePath, 'utf8')
|
|
64
|
+
} catch {}
|
|
59
65
|
const linesToAdd = installedDirs.filter(d => !gitignoreContent.includes(d))
|
|
60
66
|
if (linesToAdd.length > 0) {
|
|
61
67
|
const hasHeader = gitignoreContent.includes('# AI agent skills')
|
|
62
|
-
const block =
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
const block =
|
|
69
|
+
(gitignoreContent && !gitignoreContent.endsWith('\n') ? '\n' : '') +
|
|
70
|
+
(hasHeader ? '' : '\n# AI agent skills (auto-generated by setup-skills)\n') +
|
|
71
|
+
linesToAdd.join('\n') +
|
|
72
|
+
'\n'
|
|
65
73
|
fs.appendFileSync(gitignorePath, block)
|
|
66
74
|
console.log(`📝 Added ${linesToAdd.length} entries to .gitignore`)
|
|
67
75
|
}
|
|
@@ -70,7 +78,9 @@ if (!isGlobal && installedDirs.length > 0) {
|
|
|
70
78
|
if (installed === 0 && isPostinstall) {
|
|
71
79
|
// Silence is fine — no agents present, nothing to do
|
|
72
80
|
} else if (installed === 0 && skipped === Object.keys(AGENTS).length) {
|
|
73
|
-
console.log(
|
|
81
|
+
console.log(
|
|
82
|
+
'No agent directories detected. Try --global or run without it for project-local install.'
|
|
83
|
+
)
|
|
74
84
|
} else if (installed === 0) {
|
|
75
85
|
console.log('Nothing installed. Run without --global to install project-locally.')
|
|
76
86
|
} else {
|
|
@@ -11,15 +11,15 @@ Atscript is a universal type and metadata description language. `@atscript/types
|
|
|
11
11
|
|
|
12
12
|
Read the domain file that matches the task. Do not load all files — only what you need.
|
|
13
13
|
|
|
14
|
-
| Domain
|
|
15
|
-
|
|
16
|
-
| Setup & configuration
|
|
17
|
-
| `.as` file syntax
|
|
18
|
-
| Annotations & primitives | [annotations.md](annotations.md) | Using built-in `@meta.*`/`@expect.*` annotations, defining custom annotations or primitives |
|
|
19
|
-
| Code generation
|
|
20
|
-
| Runtime type system
|
|
21
|
-
| Validation
|
|
22
|
-
| Utility functions
|
|
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.*`/`@ui.*`/`@db.*` 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
23
|
|
|
24
24
|
## Quick reference
|
|
25
25
|
|
|
@@ -29,12 +29,20 @@ import tsPlugin from '@atscript/typescript'
|
|
|
29
29
|
|
|
30
30
|
// Runtime utilities (used in app code)
|
|
31
31
|
import {
|
|
32
|
-
defineAnnotatedType,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
defineAnnotatedType,
|
|
33
|
+
isAnnotatedType,
|
|
34
|
+
annotate,
|
|
35
|
+
Validator,
|
|
36
|
+
ValidatorError,
|
|
37
|
+
buildJsonSchema,
|
|
38
|
+
fromJsonSchema,
|
|
39
|
+
mergeJsonSchemas,
|
|
40
|
+
serializeAnnotatedType,
|
|
41
|
+
deserializeAnnotatedType,
|
|
42
|
+
flattenAnnotatedType,
|
|
43
|
+
createDataFromAnnotatedType,
|
|
44
|
+
forAnnotatedType,
|
|
45
|
+
throwFeatureDisabled,
|
|
38
46
|
} from '@atscript/typescript/utils'
|
|
39
47
|
|
|
40
48
|
// CLI
|
|
@@ -6,36 +6,53 @@
|
|
|
6
6
|
|
|
7
7
|
### `@meta.*` — Metadata Annotations
|
|
8
8
|
|
|
9
|
-
| Annotation
|
|
10
|
-
|
|
11
|
-
| `@meta.label`
|
|
12
|
-
| `@meta.id`
|
|
13
|
-
| `@meta.description`
|
|
14
|
-
| `@meta.documentation` | `text: string`
|
|
15
|
-
| `@meta.
|
|
16
|
-
| `@meta.
|
|
17
|
-
| `@meta.
|
|
18
|
-
| `@meta.
|
|
19
|
-
| `@meta.
|
|
20
|
-
| `@
|
|
21
|
-
| `@meta.isKey` | *(none)* | Mark field as key inside array (string/number types only) |
|
|
9
|
+
| Annotation | Arguments | Description |
|
|
10
|
+
| --------------------- | -------------------------- | ------------------------------------------------------------------ |
|
|
11
|
+
| `@meta.label` | `text: string` | Human-readable label for UI, logs, documentation |
|
|
12
|
+
| `@meta.id` | _(none)_ | Mark field as unique identifier; multiple fields form composite PK |
|
|
13
|
+
| `@meta.description` | `text: string` | Detailed description of a field or entity |
|
|
14
|
+
| `@meta.documentation` | `text: string` | Multi-line docs (Markdown). Multiple allowed — each appends |
|
|
15
|
+
| `@meta.sensitive` | _(none)_ | Mark as sensitive (passwords, API keys). Strips from serialization |
|
|
16
|
+
| `@meta.readonly` | _(none)_ | Mark as read-only |
|
|
17
|
+
| `@meta.required` | `message?: string` | Required field. Strings: non-whitespace. Booleans: must be `true` |
|
|
18
|
+
| `@meta.default` | `value: string` | Default value (strings as-is, others parsed as JSON) |
|
|
19
|
+
| `@meta.example` | `value: string` | Example value (strings as-is, others parsed as JSON) |
|
|
20
|
+
| `@expect.array.key` | _(none)_ | Mark field as key inside array (string/number types only) |
|
|
22
21
|
|
|
23
22
|
### `@expect.*` — Validation Constraints
|
|
24
23
|
|
|
25
|
-
| Annotation
|
|
26
|
-
|
|
27
|
-
| `@expect.minLength` | `length: number`, `message?: string`
|
|
28
|
-
| `@expect.maxLength` | `length: number`, `message?: string`
|
|
29
|
-
| `@expect.min`
|
|
30
|
-
| `@expect.max`
|
|
31
|
-
| `@expect.int`
|
|
32
|
-
| `@expect.pattern`
|
|
24
|
+
| Annotation | Arguments | Applies To | Description |
|
|
25
|
+
| ------------------- | ------------------------------------------------------- | ------------- | ------------------------------------------------------ |
|
|
26
|
+
| `@expect.minLength` | `length: number`, `message?: string` | string, array | Minimum length |
|
|
27
|
+
| `@expect.maxLength` | `length: number`, `message?: string` | string, array | Maximum length |
|
|
28
|
+
| `@expect.min` | `minValue: number`, `message?: string` | number | Minimum value |
|
|
29
|
+
| `@expect.max` | `maxValue: number`, `message?: string` | number | Maximum value |
|
|
30
|
+
| `@expect.int` | _(none)_ | number | Must be integer |
|
|
31
|
+
| `@expect.pattern` | `pattern: string`, `flags?: string`, `message?: string` | string | Regex validation. **Multiple allowed** (all must pass) |
|
|
32
|
+
|
|
33
|
+
### `@ui.*` — UI / Presentation Hints
|
|
34
|
+
|
|
35
|
+
| Annotation | Arguments | Description |
|
|
36
|
+
| ----------------- | ------------------------------ | ---------------------------------------------- |
|
|
37
|
+
| `@ui.placeholder` | `text: string` | Input placeholder text |
|
|
38
|
+
| `@ui.component` | `name: string` | UI component hint (`"select"`, `"datepicker"`) |
|
|
39
|
+
| `@ui.hidden` | _(none)_ | Hide from UI forms/tables |
|
|
40
|
+
| `@ui.group` | `name: string` | Group fields into form sections |
|
|
41
|
+
| `@ui.order` | `order: number` | Display order (lower = first) |
|
|
42
|
+
| `@ui.width` | `width: string` | Layout hint (`"half"`, `"full"`, `"third"`) |
|
|
43
|
+
| `@ui.icon` | `name: string` | Icon hint |
|
|
44
|
+
| `@ui.hint` | `text: string` | Help text / tooltip |
|
|
45
|
+
| `@ui.disabled` | _(none)_ | Non-interactive field |
|
|
46
|
+
| `@ui.type` | `type: string` | Input type (`"textarea"`, `"password"`, etc.) |
|
|
47
|
+
| `@ui.attr` | `key: string`, `value: string` | Arbitrary attribute (**multiple**, append) |
|
|
48
|
+
| `@ui.class` | `names: string` | CSS class names (**multiple**, append) |
|
|
49
|
+
| `@ui.style` | `css: string` | Inline CSS styles (**multiple**, append) |
|
|
33
50
|
|
|
34
51
|
### `@emit.*` — Build-time Directives
|
|
35
52
|
|
|
36
|
-
| Annotation
|
|
37
|
-
|
|
38
|
-
| `@emit.jsonSchema` | interface
|
|
53
|
+
| Annotation | Applies To | Description |
|
|
54
|
+
| ------------------ | ---------- | ----------------------------------------------- |
|
|
55
|
+
| `@emit.jsonSchema` | interface | Pre-compute and embed JSON Schema at build time |
|
|
39
56
|
|
|
40
57
|
## Custom Annotations
|
|
41
58
|
|
|
@@ -49,21 +66,21 @@ export default defineConfig({
|
|
|
49
66
|
plugins: [tsPlugin()],
|
|
50
67
|
annotations: {
|
|
51
68
|
// Namespaced annotations use nested objects
|
|
52
|
-
|
|
53
|
-
// @
|
|
54
|
-
|
|
55
|
-
argument: { name: '
|
|
56
|
-
description: '
|
|
69
|
+
grid: {
|
|
70
|
+
// @grid.column 200
|
|
71
|
+
column: new AnnotationSpec({
|
|
72
|
+
argument: { name: 'width', type: 'number' },
|
|
73
|
+
description: 'Table column width in data grid',
|
|
57
74
|
}),
|
|
58
75
|
|
|
59
|
-
// @
|
|
76
|
+
// @grid.hidden (no arguments — boolean flag)
|
|
60
77
|
hidden: new AnnotationSpec({
|
|
61
|
-
description: 'Hide
|
|
78
|
+
description: 'Hide column in data grid',
|
|
62
79
|
}),
|
|
63
80
|
|
|
64
|
-
// @
|
|
65
|
-
|
|
66
|
-
|
|
81
|
+
// @grid.sortable
|
|
82
|
+
sortable: new AnnotationSpec({
|
|
83
|
+
description: 'Allow sorting by this column',
|
|
67
84
|
}),
|
|
68
85
|
},
|
|
69
86
|
|
|
@@ -102,10 +119,10 @@ new AnnotationSpec({
|
|
|
102
119
|
],
|
|
103
120
|
|
|
104
121
|
// Allow multiple instances on the same target
|
|
105
|
-
multiple: true,
|
|
122
|
+
multiple: true, // default: false
|
|
106
123
|
|
|
107
124
|
// How duplicates merge: 'replace' (last wins) or 'append' (collect into array)
|
|
108
|
-
mergeStrategy: 'append',
|
|
125
|
+
mergeStrategy: 'append', // default: 'replace'
|
|
109
126
|
|
|
110
127
|
// Human-readable description
|
|
111
128
|
description: 'What this annotation does',
|
|
@@ -124,13 +141,13 @@ new AnnotationSpec({
|
|
|
124
141
|
|
|
125
142
|
Each argument accepts:
|
|
126
143
|
|
|
127
|
-
| Field
|
|
128
|
-
|
|
129
|
-
| `name`
|
|
130
|
-
| `type`
|
|
131
|
-
| `optional`
|
|
132
|
-
| `description` | `string`
|
|
133
|
-
| `values`
|
|
144
|
+
| Field | Type | Description |
|
|
145
|
+
| ------------- | ----------------------------------- | ------------------------------------------- |
|
|
146
|
+
| `name` | `string` | Argument name (used in metadata object key) |
|
|
147
|
+
| `type` | `'string' \| 'number' \| 'boolean'` | Expected type |
|
|
148
|
+
| `optional` | `boolean` | Whether the argument can be omitted |
|
|
149
|
+
| `description` | `string` | Human-readable description |
|
|
150
|
+
| `values` | `string[]` | Allowed values (enum-like constraint) |
|
|
134
151
|
|
|
135
152
|
### How Annotations Map to Runtime Metadata
|
|
136
153
|
|
|
@@ -140,6 +157,7 @@ Each argument accepts:
|
|
|
140
157
|
- **`multiple: true`** → metadata value is an array
|
|
141
158
|
|
|
142
159
|
Example: `@api.endpoint "/users" "GET"` becomes:
|
|
160
|
+
|
|
143
161
|
```ts
|
|
144
162
|
metadata.get('api.endpoint') // → { path: "/users", method: "GET" }
|
|
145
163
|
```
|
|
@@ -200,26 +218,26 @@ export default defineConfig({
|
|
|
200
218
|
|
|
201
219
|
### `TPrimitiveConfig` Options
|
|
202
220
|
|
|
203
|
-
| Field
|
|
204
|
-
|
|
205
|
-
| `type`
|
|
206
|
-
| `tags`
|
|
207
|
-
| `documentation` | `string`
|
|
208
|
-
| `expect`
|
|
209
|
-
| `extensions`
|
|
221
|
+
| Field | Type | Description |
|
|
222
|
+
| --------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
223
|
+
| `type` | `TPrimitiveTypeDef` | Base type: `'string'`, `'number'`, `'boolean'`, `'void'`, `'null'`, `'phantom'`, or complex type |
|
|
224
|
+
| `tags` | `string[]` | Custom tags for categorization |
|
|
225
|
+
| `documentation` | `string` | Documentation string |
|
|
226
|
+
| `expect` | object | Built-in validation constraints |
|
|
227
|
+
| `extensions` | `Record<string, Partial<TPrimitiveConfig>>` | Sub-types accessible via dot notation |
|
|
210
228
|
|
|
211
229
|
### `expect` Validation on Primitives
|
|
212
230
|
|
|
213
|
-
| Field
|
|
214
|
-
|
|
215
|
-
| `min`
|
|
216
|
-
| `max`
|
|
217
|
-
| `int`
|
|
218
|
-
| `minLength` | string, array
|
|
219
|
-
| `maxLength` | string, array
|
|
220
|
-
| `pattern`
|
|
221
|
-
| `required`
|
|
222
|
-
| `message`
|
|
231
|
+
| Field | Applies To | Description |
|
|
232
|
+
| ----------- | --------------- | -------------------------------- |
|
|
233
|
+
| `min` | number | Minimum value |
|
|
234
|
+
| `max` | number | Maximum value |
|
|
235
|
+
| `int` | number | Must be integer |
|
|
236
|
+
| `minLength` | string, array | Minimum length |
|
|
237
|
+
| `maxLength` | string, array | Maximum length |
|
|
238
|
+
| `pattern` | string | Regex pattern(s) |
|
|
239
|
+
| `required` | string, boolean | Non-empty / must be true |
|
|
240
|
+
| `message` | any | Custom error message for pattern |
|
|
223
241
|
|
|
224
242
|
### Usage in `.as` Files
|
|
225
243
|
|