@atscript/typescript 0.0.32 → 0.1.1
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 +204 -33
- package/dist/index.cjs +165 -29
- package/dist/index.mjs +165 -29
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -153,6 +153,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
153
153
|
}
|
|
154
154
|
renderInterface(node) {}
|
|
155
155
|
renderType(node) {}
|
|
156
|
+
renderAnnotate(node) {}
|
|
156
157
|
transformFromPath(path$3) {
|
|
157
158
|
return `${path$3}.as`;
|
|
158
159
|
}
|
|
@@ -187,6 +188,10 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
187
188
|
this.renderImport(node);
|
|
188
189
|
break;
|
|
189
190
|
}
|
|
191
|
+
case "annotate": {
|
|
192
|
+
this.renderAnnotate(node);
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
190
195
|
default: break;
|
|
191
196
|
}
|
|
192
197
|
}
|
|
@@ -346,6 +351,26 @@ else this.writeln("{}");
|
|
|
346
351
|
this.writeln();
|
|
347
352
|
this.renderTypeNamespace(node);
|
|
348
353
|
}
|
|
354
|
+
renderAnnotate(node) {
|
|
355
|
+
if (node.isMutating) return;
|
|
356
|
+
const targetName = node.targetName;
|
|
357
|
+
const unwound = this.doc.unwindType(targetName);
|
|
358
|
+
if (!unwound?.def) return;
|
|
359
|
+
const def = this.doc.mergeIntersection(unwound.def);
|
|
360
|
+
this.writeln();
|
|
361
|
+
const exported = node.token("export")?.text === "export";
|
|
362
|
+
this.renderJsDoc(node);
|
|
363
|
+
if ((0, __atscript_core.isStructure)(def) || (0, __atscript_core.isInterface)(def)) {
|
|
364
|
+
this.write(exported ? "export declare " : "declare ");
|
|
365
|
+
this.write(`class ${node.id} `);
|
|
366
|
+
this.renderStructure(def, node.id);
|
|
367
|
+
} else {
|
|
368
|
+
this.write(exported ? "export " : "declare ");
|
|
369
|
+
this.write(`type ${node.id} = `);
|
|
370
|
+
this.renderTypeDef(def);
|
|
371
|
+
}
|
|
372
|
+
this.writeln();
|
|
373
|
+
}
|
|
349
374
|
renderTypeNamespace(node) {
|
|
350
375
|
this.write(`declare namespace ${node.id} `);
|
|
351
376
|
this.blockln("{}");
|
|
@@ -947,36 +972,58 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
947
972
|
if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
|
|
948
973
|
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
|
|
949
974
|
}
|
|
975
|
+
buildAdHocMap(annotateNodes) {
|
|
976
|
+
const map = new Map();
|
|
977
|
+
for (const annotateNode of annotateNodes) for (const entry of annotateNode.entries) {
|
|
978
|
+
const path$3 = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)].join(".") : entry.id;
|
|
979
|
+
const anns = entry.annotations || [];
|
|
980
|
+
if (anns.length > 0) {
|
|
981
|
+
const existing = map.get(path$3);
|
|
982
|
+
map.set(path$3, existing ? [...existing, ...anns] : anns);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return map.size > 0 ? map : null;
|
|
986
|
+
}
|
|
950
987
|
post() {
|
|
951
|
-
for (const node of this.postAnnotate) {
|
|
988
|
+
for (const node of this.postAnnotate) if (node.entity === "annotate") {
|
|
989
|
+
const annotateNode = node;
|
|
990
|
+
const unwound = this.doc.unwindType(annotateNode.targetName);
|
|
991
|
+
if (unwound?.def) {
|
|
992
|
+
let def = this.doc.mergeIntersection(unwound.def);
|
|
993
|
+
if ((0, __atscript_core.isInterface)(def)) def = def.getDefinition() || def;
|
|
994
|
+
this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
|
|
995
|
+
this.annotateType(def, node.id);
|
|
996
|
+
this._adHocAnnotations = null;
|
|
997
|
+
this.indent();
|
|
998
|
+
this.defineMetadataForAnnotateAlias(annotateNode);
|
|
999
|
+
this.unindent();
|
|
1000
|
+
this.writeln();
|
|
1001
|
+
}
|
|
1002
|
+
} else {
|
|
1003
|
+
const mutatingNodes = this.doc.getAnnotateNodesFor(node.id).filter((n) => n.isMutating);
|
|
1004
|
+
this._adHocAnnotations = this.buildAdHocMap(mutatingNodes);
|
|
952
1005
|
this.annotateType(node.getDefinition(), node.id);
|
|
1006
|
+
this._adHocAnnotations = null;
|
|
953
1007
|
this.indent().defineMetadata(node).unindent();
|
|
954
1008
|
this.writeln();
|
|
955
1009
|
}
|
|
1010
|
+
this.renderMutatingAnnotates();
|
|
956
1011
|
this.writeln("// prettier-ignore-end");
|
|
957
1012
|
super.post();
|
|
958
1013
|
}
|
|
1014
|
+
renderClassStatics(node) {
|
|
1015
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
1016
|
+
this.writeln("static type = {}");
|
|
1017
|
+
this.writeln("static metadata = new Map()");
|
|
1018
|
+
this.renderJsonSchemaMethod(node);
|
|
1019
|
+
}
|
|
959
1020
|
renderInterface(node) {
|
|
960
1021
|
this.writeln();
|
|
961
1022
|
const exported = node.token("export")?.text === "export";
|
|
962
1023
|
this.write(exported ? "export " : "");
|
|
963
1024
|
this.write(`class ${node.id} `);
|
|
964
1025
|
this.blockln("{}");
|
|
965
|
-
this.
|
|
966
|
-
this.writeln("static type = {}");
|
|
967
|
-
this.writeln("static metadata = new Map()");
|
|
968
|
-
if (this.opts?.preRenderJsonSchema) {
|
|
969
|
-
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
970
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
971
|
-
this.writeln("static toJsonSchema() {");
|
|
972
|
-
this.indent().writeln("return this._jsonSchema").unindent();
|
|
973
|
-
this.writeln("}");
|
|
974
|
-
} else {
|
|
975
|
-
this.writeln("static _jsonSchema");
|
|
976
|
-
this.writeln("static toJsonSchema() {");
|
|
977
|
-
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
978
|
-
this.writeln("}");
|
|
979
|
-
}
|
|
1026
|
+
this.renderClassStatics(node);
|
|
980
1027
|
this.popln();
|
|
981
1028
|
this.postAnnotate.push(node);
|
|
982
1029
|
this.writeln();
|
|
@@ -987,24 +1034,40 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
987
1034
|
this.write(exported ? "export " : "");
|
|
988
1035
|
this.write(`class ${node.id} `);
|
|
989
1036
|
this.blockln("{}");
|
|
990
|
-
this.
|
|
991
|
-
this.
|
|
992
|
-
this.
|
|
1037
|
+
this.renderClassStatics(node);
|
|
1038
|
+
this.popln();
|
|
1039
|
+
this.postAnnotate.push(node);
|
|
1040
|
+
this.writeln();
|
|
1041
|
+
}
|
|
1042
|
+
renderAnnotate(node) {
|
|
1043
|
+
if (node.isMutating) {
|
|
1044
|
+
this.mutatingAnnotates.push(node);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
const targetName = node.targetName;
|
|
1048
|
+
const unwound = this.doc.unwindType(targetName);
|
|
1049
|
+
if (!unwound?.def) return;
|
|
1050
|
+
this.writeln();
|
|
1051
|
+
const exported = node.token("export")?.text === "export";
|
|
1052
|
+
this.write(exported ? "export " : "");
|
|
1053
|
+
this.write(`class ${node.id} `);
|
|
1054
|
+
this.blockln("{}");
|
|
1055
|
+
this.renderClassStatics(node);
|
|
1056
|
+
this.popln();
|
|
1057
|
+
this.postAnnotate.push(node);
|
|
1058
|
+
this.writeln();
|
|
1059
|
+
}
|
|
1060
|
+
renderJsonSchemaMethod(node) {
|
|
993
1061
|
if (this.opts?.preRenderJsonSchema) {
|
|
994
1062
|
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
995
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
996
1063
|
this.writeln("static toJsonSchema() {");
|
|
997
|
-
this.indent().writeln(
|
|
1064
|
+
this.indent().writeln(`return ${schema}`).unindent();
|
|
998
1065
|
this.writeln("}");
|
|
999
1066
|
} else {
|
|
1000
|
-
this.writeln("static _jsonSchema");
|
|
1001
1067
|
this.writeln("static toJsonSchema() {");
|
|
1002
1068
|
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
1003
1069
|
this.writeln("}");
|
|
1004
1070
|
}
|
|
1005
|
-
this.popln();
|
|
1006
|
-
this.postAnnotate.push(node);
|
|
1007
|
-
this.writeln();
|
|
1008
1071
|
}
|
|
1009
1072
|
toAnnotatedType(node) {
|
|
1010
1073
|
return this.toAnnotatedHandle(node).$type;
|
|
@@ -1235,6 +1298,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1235
1298
|
for (const prop of props) {
|
|
1236
1299
|
const pattern = prop.token("identifier")?.pattern;
|
|
1237
1300
|
const optional = !!prop.token("optional");
|
|
1301
|
+
this._propPath.push(prop.id);
|
|
1238
1302
|
if (pattern) {
|
|
1239
1303
|
this.writeln(`.propPattern(`);
|
|
1240
1304
|
this.indent();
|
|
@@ -1250,6 +1314,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1250
1314
|
this.writeln(" .$type");
|
|
1251
1315
|
this.unindent();
|
|
1252
1316
|
this.write(`)`);
|
|
1317
|
+
this._propPath.pop();
|
|
1253
1318
|
}
|
|
1254
1319
|
this.writeln();
|
|
1255
1320
|
return this;
|
|
@@ -1265,12 +1330,43 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1265
1330
|
}
|
|
1266
1331
|
defineMetadata(node) {
|
|
1267
1332
|
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1333
|
+
let adHocNames;
|
|
1334
|
+
let adHoc;
|
|
1335
|
+
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1336
|
+
const path$3 = this._propPath.join(".");
|
|
1337
|
+
adHoc = this._adHocAnnotations.get(path$3);
|
|
1338
|
+
if (adHoc) adHocNames = new Set(adHoc.map((a) => a.name));
|
|
1339
|
+
}
|
|
1268
1340
|
annotations?.forEach((an) => {
|
|
1341
|
+
if (!adHocNames || !adHocNames.has(an.name)) this.resolveAnnotationValue(node, an);
|
|
1342
|
+
});
|
|
1343
|
+
adHoc?.forEach((an) => {
|
|
1269
1344
|
this.resolveAnnotationValue(node, an);
|
|
1270
1345
|
});
|
|
1271
1346
|
return this;
|
|
1272
1347
|
}
|
|
1348
|
+
/**
|
|
1349
|
+
* For non-mutating annotate aliases: merge the target's type-level annotations
|
|
1350
|
+
* with the annotate block's own annotations (annotate's take priority).
|
|
1351
|
+
*/ defineMetadataForAnnotateAlias(annotateNode) {
|
|
1352
|
+
const annotateAnnotations = this.doc.evalAnnotationsForNode(annotateNode);
|
|
1353
|
+
const targetDecl = this.doc.getDeclarationOwnerNode(annotateNode.targetName);
|
|
1354
|
+
const targetAnnotations = targetDecl?.node ? targetDecl.doc.evalAnnotationsForNode(targetDecl.node) : undefined;
|
|
1355
|
+
const overriddenNames = new Set(annotateAnnotations?.map((a) => a.name));
|
|
1356
|
+
targetAnnotations?.forEach((an) => {
|
|
1357
|
+
if (!overriddenNames.has(an.name)) this.resolveAnnotationValue(annotateNode, an);
|
|
1358
|
+
});
|
|
1359
|
+
annotateAnnotations?.forEach((an) => {
|
|
1360
|
+
this.resolveAnnotationValue(annotateNode, an);
|
|
1361
|
+
});
|
|
1362
|
+
return this;
|
|
1363
|
+
}
|
|
1273
1364
|
resolveAnnotationValue(node, an) {
|
|
1365
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1366
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
|
|
1367
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
|
|
1368
|
+
}
|
|
1369
|
+
computeAnnotationValue(node, an) {
|
|
1274
1370
|
const spec = this.doc.resolveAnnotation(an.name);
|
|
1275
1371
|
let targetValue = "true";
|
|
1276
1372
|
let multiple = false;
|
|
@@ -1282,7 +1378,6 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1282
1378
|
let i = 0;
|
|
1283
1379
|
for (const aSpec of spec.arguments) {
|
|
1284
1380
|
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
1285
|
-
else {}
|
|
1286
1381
|
i++;
|
|
1287
1382
|
}
|
|
1288
1383
|
targetValue += "}";
|
|
@@ -1295,11 +1390,52 @@ else targetValue = "true";
|
|
|
1295
1390
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1296
1391
|
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1297
1392
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1393
|
+
return {
|
|
1394
|
+
value: targetValue,
|
|
1395
|
+
multiple: !!multiple
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
renderMutatingAnnotates() {
|
|
1399
|
+
for (const node of this.mutatingAnnotates) {
|
|
1400
|
+
const targetName = node.targetName;
|
|
1401
|
+
for (const entry of node.entries) {
|
|
1402
|
+
const anns = entry.annotations;
|
|
1403
|
+
if (!anns || anns.length === 0) continue;
|
|
1404
|
+
const parts = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)] : [entry.id];
|
|
1405
|
+
let accessor = targetName;
|
|
1406
|
+
for (const part of parts) accessor += `.type.props.get("${escapeQuotes(part)}")?`;
|
|
1407
|
+
for (const an of anns) {
|
|
1408
|
+
const { value, multiple } = this.computeAnnotationValue(entry, an);
|
|
1409
|
+
if (multiple) {
|
|
1410
|
+
this.writeln(`{`);
|
|
1411
|
+
this.indent();
|
|
1412
|
+
this.writeln(`const __t = ${accessor}.metadata`);
|
|
1413
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1414
|
+
this.writeln(`const __v = ${value}`);
|
|
1415
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1416
|
+
this.unindent();
|
|
1417
|
+
this.writeln(`}`);
|
|
1418
|
+
} else this.writeln(`${accessor}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
const topAnnotations = node.annotations;
|
|
1422
|
+
if (topAnnotations && topAnnotations.length > 0) for (const an of topAnnotations) {
|
|
1423
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1424
|
+
if (multiple) {
|
|
1425
|
+
this.writeln(`{`);
|
|
1426
|
+
this.indent();
|
|
1427
|
+
this.writeln(`const __t = ${targetName}.metadata`);
|
|
1428
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1429
|
+
this.writeln(`const __v = ${value}`);
|
|
1430
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1431
|
+
this.unindent();
|
|
1432
|
+
this.writeln(`}`);
|
|
1433
|
+
} else this.writeln(`${targetName}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1300
1436
|
}
|
|
1301
1437
|
constructor(doc, opts) {
|
|
1302
|
-
super(doc), _define_property$1(this, "opts", void 0), _define_property$1(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1438
|
+
super(doc), _define_property$1(this, "opts", void 0), _define_property$1(this, "postAnnotate", void 0), _define_property$1(this, "mutatingAnnotates", void 0), _define_property$1(this, "_adHocAnnotations", void 0), _define_property$1(this, "_propPath", void 0), this.opts = opts, this.postAnnotate = [], this.mutatingAnnotates = [], this._adHocAnnotations = null, this._propPath = [];
|
|
1303
1439
|
}
|
|
1304
1440
|
};
|
|
1305
1441
|
|
|
@@ -1370,13 +1506,35 @@ function _ts_param(paramIndex, decorator) {
|
|
|
1370
1506
|
};
|
|
1371
1507
|
}
|
|
1372
1508
|
var Commands = class {
|
|
1373
|
-
async default(configFile, format) {
|
|
1509
|
+
async default(configFile, format, noEmit, skipDiag) {
|
|
1374
1510
|
const config = await this.getConfig(configFile);
|
|
1375
1511
|
if (format) config.format = format;
|
|
1376
1512
|
this.logger.log(`Format: ${"\x1B[36m"}${config.format}${"\x1B[39m"}`);
|
|
1377
1513
|
const builder = await (0, __atscript_core.build)(config);
|
|
1378
|
-
|
|
1379
|
-
|
|
1514
|
+
let errorCount = 0;
|
|
1515
|
+
let warningCount = 0;
|
|
1516
|
+
if (!skipDiag) {
|
|
1517
|
+
const diagMap = await builder.diagnostics();
|
|
1518
|
+
for (const [docId, messages] of diagMap) {
|
|
1519
|
+
const doc = builder.getDoc(docId);
|
|
1520
|
+
for (const m of messages) {
|
|
1521
|
+
if (m.severity === 1) errorCount++;
|
|
1522
|
+
else if (m.severity === 2) warningCount++;
|
|
1523
|
+
if (doc) this.logger.log(doc.renderDiagMessage(m, true, true));
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
if (!noEmit) {
|
|
1528
|
+
const out = await builder.write(config);
|
|
1529
|
+
for (const { target } of out) this.logger.log(`✅ created ${"\x1B[32m"}${target}${"\x1B[39m"}`);
|
|
1530
|
+
}
|
|
1531
|
+
if (errorCount > 0 || warningCount > 0) {
|
|
1532
|
+
const parts = [];
|
|
1533
|
+
if (errorCount > 0) parts.push(`${"\x1B[31m"}${errorCount} error${errorCount > 1 ? "s" : ""}${"\x1B[39m"}`);
|
|
1534
|
+
if (warningCount > 0) parts.push(`${"\x1B[33m"}${warningCount} warning${warningCount > 1 ? "s" : ""}${"\x1B[39m"}`);
|
|
1535
|
+
this.logger.log(`\nFound ${parts.join(" and ")}`);
|
|
1536
|
+
}
|
|
1537
|
+
if (errorCount > 0) process.exit(1);
|
|
1380
1538
|
}
|
|
1381
1539
|
async getConfig(configFile) {
|
|
1382
1540
|
const root = process.cwd();
|
|
@@ -1411,14 +1569,27 @@ _ts_decorate([
|
|
|
1411
1569
|
(0, moost.Description)("Builds .as files using --config and --format"),
|
|
1412
1570
|
(0, __moostjs_event_cli.CliExample)("-c atscript.config.js", "Build .as files using atscript.config.js"),
|
|
1413
1571
|
(0, __moostjs_event_cli.CliExample)("-f dts", "Build \"d.ts\" files for \".as\" files"),
|
|
1572
|
+
(0, __moostjs_event_cli.CliExample)("--noEmit", "Only check for errors, do not emit files"),
|
|
1573
|
+
(0, __moostjs_event_cli.CliExample)("--skipDiag", "Emit files without running diagnostics"),
|
|
1414
1574
|
_ts_param(0, (0, __moostjs_event_cli.CliOption)("c", "config")),
|
|
1415
1575
|
_ts_param(0, (0, moost.Optional)()),
|
|
1416
1576
|
_ts_param(0, (0, moost.Description)("Path to config file")),
|
|
1417
1577
|
_ts_param(1, (0, __moostjs_event_cli.CliOption)("f", "format")),
|
|
1418
1578
|
_ts_param(1, (0, moost.Optional)()),
|
|
1419
1579
|
_ts_param(1, (0, moost.Description)("Output format (js|dts), default: \"dts\"")),
|
|
1580
|
+
_ts_param(2, (0, __moostjs_event_cli.CliOption)("noEmit")),
|
|
1581
|
+
_ts_param(2, (0, moost.Optional)()),
|
|
1582
|
+
_ts_param(2, (0, moost.Description)("Only run diagnostics without emitting files")),
|
|
1583
|
+
_ts_param(3, (0, __moostjs_event_cli.CliOption)("skipDiag")),
|
|
1584
|
+
_ts_param(3, (0, moost.Optional)()),
|
|
1585
|
+
_ts_param(3, (0, moost.Description)("Skip diagnostics and always emit files")),
|
|
1420
1586
|
_ts_metadata("design:type", Function),
|
|
1421
|
-
_ts_metadata("design:paramtypes", [
|
|
1587
|
+
_ts_metadata("design:paramtypes", [
|
|
1588
|
+
String,
|
|
1589
|
+
String,
|
|
1590
|
+
Boolean,
|
|
1591
|
+
Boolean
|
|
1592
|
+
]),
|
|
1422
1593
|
_ts_metadata("design:returntype", Promise)
|
|
1423
1594
|
], Commands.prototype, "default", null);
|
|
1424
1595
|
Commands = _ts_decorate([
|
package/dist/index.cjs
CHANGED
|
@@ -150,6 +150,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
150
150
|
}
|
|
151
151
|
renderInterface(node) {}
|
|
152
152
|
renderType(node) {}
|
|
153
|
+
renderAnnotate(node) {}
|
|
153
154
|
transformFromPath(path$2) {
|
|
154
155
|
return `${path$2}.as`;
|
|
155
156
|
}
|
|
@@ -184,6 +185,10 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
184
185
|
this.renderImport(node);
|
|
185
186
|
break;
|
|
186
187
|
}
|
|
188
|
+
case "annotate": {
|
|
189
|
+
this.renderAnnotate(node);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
187
192
|
default: break;
|
|
188
193
|
}
|
|
189
194
|
}
|
|
@@ -343,6 +348,26 @@ else this.writeln("{}");
|
|
|
343
348
|
this.writeln();
|
|
344
349
|
this.renderTypeNamespace(node);
|
|
345
350
|
}
|
|
351
|
+
renderAnnotate(node) {
|
|
352
|
+
if (node.isMutating) return;
|
|
353
|
+
const targetName = node.targetName;
|
|
354
|
+
const unwound = this.doc.unwindType(targetName);
|
|
355
|
+
if (!unwound?.def) return;
|
|
356
|
+
const def = this.doc.mergeIntersection(unwound.def);
|
|
357
|
+
this.writeln();
|
|
358
|
+
const exported = node.token("export")?.text === "export";
|
|
359
|
+
this.renderJsDoc(node);
|
|
360
|
+
if ((0, __atscript_core.isStructure)(def) || (0, __atscript_core.isInterface)(def)) {
|
|
361
|
+
this.write(exported ? "export declare " : "declare ");
|
|
362
|
+
this.write(`class ${node.id} `);
|
|
363
|
+
this.renderStructure(def, node.id);
|
|
364
|
+
} else {
|
|
365
|
+
this.write(exported ? "export " : "declare ");
|
|
366
|
+
this.write(`type ${node.id} = `);
|
|
367
|
+
this.renderTypeDef(def);
|
|
368
|
+
}
|
|
369
|
+
this.writeln();
|
|
370
|
+
}
|
|
346
371
|
renderTypeNamespace(node) {
|
|
347
372
|
this.write(`declare namespace ${node.id} `);
|
|
348
373
|
this.blockln("{}");
|
|
@@ -944,36 +969,58 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
944
969
|
if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
|
|
945
970
|
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
|
|
946
971
|
}
|
|
972
|
+
buildAdHocMap(annotateNodes) {
|
|
973
|
+
const map = new Map();
|
|
974
|
+
for (const annotateNode of annotateNodes) for (const entry of annotateNode.entries) {
|
|
975
|
+
const path$2 = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)].join(".") : entry.id;
|
|
976
|
+
const anns = entry.annotations || [];
|
|
977
|
+
if (anns.length > 0) {
|
|
978
|
+
const existing = map.get(path$2);
|
|
979
|
+
map.set(path$2, existing ? [...existing, ...anns] : anns);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
return map.size > 0 ? map : null;
|
|
983
|
+
}
|
|
947
984
|
post() {
|
|
948
|
-
for (const node of this.postAnnotate) {
|
|
985
|
+
for (const node of this.postAnnotate) if (node.entity === "annotate") {
|
|
986
|
+
const annotateNode = node;
|
|
987
|
+
const unwound = this.doc.unwindType(annotateNode.targetName);
|
|
988
|
+
if (unwound?.def) {
|
|
989
|
+
let def = this.doc.mergeIntersection(unwound.def);
|
|
990
|
+
if ((0, __atscript_core.isInterface)(def)) def = def.getDefinition() || def;
|
|
991
|
+
this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
|
|
992
|
+
this.annotateType(def, node.id);
|
|
993
|
+
this._adHocAnnotations = null;
|
|
994
|
+
this.indent();
|
|
995
|
+
this.defineMetadataForAnnotateAlias(annotateNode);
|
|
996
|
+
this.unindent();
|
|
997
|
+
this.writeln();
|
|
998
|
+
}
|
|
999
|
+
} else {
|
|
1000
|
+
const mutatingNodes = this.doc.getAnnotateNodesFor(node.id).filter((n) => n.isMutating);
|
|
1001
|
+
this._adHocAnnotations = this.buildAdHocMap(mutatingNodes);
|
|
949
1002
|
this.annotateType(node.getDefinition(), node.id);
|
|
1003
|
+
this._adHocAnnotations = null;
|
|
950
1004
|
this.indent().defineMetadata(node).unindent();
|
|
951
1005
|
this.writeln();
|
|
952
1006
|
}
|
|
1007
|
+
this.renderMutatingAnnotates();
|
|
953
1008
|
this.writeln("// prettier-ignore-end");
|
|
954
1009
|
super.post();
|
|
955
1010
|
}
|
|
1011
|
+
renderClassStatics(node) {
|
|
1012
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
1013
|
+
this.writeln("static type = {}");
|
|
1014
|
+
this.writeln("static metadata = new Map()");
|
|
1015
|
+
this.renderJsonSchemaMethod(node);
|
|
1016
|
+
}
|
|
956
1017
|
renderInterface(node) {
|
|
957
1018
|
this.writeln();
|
|
958
1019
|
const exported = node.token("export")?.text === "export";
|
|
959
1020
|
this.write(exported ? "export " : "");
|
|
960
1021
|
this.write(`class ${node.id} `);
|
|
961
1022
|
this.blockln("{}");
|
|
962
|
-
this.
|
|
963
|
-
this.writeln("static type = {}");
|
|
964
|
-
this.writeln("static metadata = new Map()");
|
|
965
|
-
if (this.opts?.preRenderJsonSchema) {
|
|
966
|
-
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
967
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
968
|
-
this.writeln("static toJsonSchema() {");
|
|
969
|
-
this.indent().writeln("return this._jsonSchema").unindent();
|
|
970
|
-
this.writeln("}");
|
|
971
|
-
} else {
|
|
972
|
-
this.writeln("static _jsonSchema");
|
|
973
|
-
this.writeln("static toJsonSchema() {");
|
|
974
|
-
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
975
|
-
this.writeln("}");
|
|
976
|
-
}
|
|
1023
|
+
this.renderClassStatics(node);
|
|
977
1024
|
this.popln();
|
|
978
1025
|
this.postAnnotate.push(node);
|
|
979
1026
|
this.writeln();
|
|
@@ -984,24 +1031,40 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
984
1031
|
this.write(exported ? "export " : "");
|
|
985
1032
|
this.write(`class ${node.id} `);
|
|
986
1033
|
this.blockln("{}");
|
|
987
|
-
this.
|
|
988
|
-
this.
|
|
989
|
-
this.
|
|
1034
|
+
this.renderClassStatics(node);
|
|
1035
|
+
this.popln();
|
|
1036
|
+
this.postAnnotate.push(node);
|
|
1037
|
+
this.writeln();
|
|
1038
|
+
}
|
|
1039
|
+
renderAnnotate(node) {
|
|
1040
|
+
if (node.isMutating) {
|
|
1041
|
+
this.mutatingAnnotates.push(node);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
const targetName = node.targetName;
|
|
1045
|
+
const unwound = this.doc.unwindType(targetName);
|
|
1046
|
+
if (!unwound?.def) return;
|
|
1047
|
+
this.writeln();
|
|
1048
|
+
const exported = node.token("export")?.text === "export";
|
|
1049
|
+
this.write(exported ? "export " : "");
|
|
1050
|
+
this.write(`class ${node.id} `);
|
|
1051
|
+
this.blockln("{}");
|
|
1052
|
+
this.renderClassStatics(node);
|
|
1053
|
+
this.popln();
|
|
1054
|
+
this.postAnnotate.push(node);
|
|
1055
|
+
this.writeln();
|
|
1056
|
+
}
|
|
1057
|
+
renderJsonSchemaMethod(node) {
|
|
990
1058
|
if (this.opts?.preRenderJsonSchema) {
|
|
991
1059
|
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
992
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
993
1060
|
this.writeln("static toJsonSchema() {");
|
|
994
|
-
this.indent().writeln(
|
|
1061
|
+
this.indent().writeln(`return ${schema}`).unindent();
|
|
995
1062
|
this.writeln("}");
|
|
996
1063
|
} else {
|
|
997
|
-
this.writeln("static _jsonSchema");
|
|
998
1064
|
this.writeln("static toJsonSchema() {");
|
|
999
1065
|
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
1000
1066
|
this.writeln("}");
|
|
1001
1067
|
}
|
|
1002
|
-
this.popln();
|
|
1003
|
-
this.postAnnotate.push(node);
|
|
1004
|
-
this.writeln();
|
|
1005
1068
|
}
|
|
1006
1069
|
toAnnotatedType(node) {
|
|
1007
1070
|
return this.toAnnotatedHandle(node).$type;
|
|
@@ -1232,6 +1295,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1232
1295
|
for (const prop of props) {
|
|
1233
1296
|
const pattern = prop.token("identifier")?.pattern;
|
|
1234
1297
|
const optional = !!prop.token("optional");
|
|
1298
|
+
this._propPath.push(prop.id);
|
|
1235
1299
|
if (pattern) {
|
|
1236
1300
|
this.writeln(`.propPattern(`);
|
|
1237
1301
|
this.indent();
|
|
@@ -1247,6 +1311,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1247
1311
|
this.writeln(" .$type");
|
|
1248
1312
|
this.unindent();
|
|
1249
1313
|
this.write(`)`);
|
|
1314
|
+
this._propPath.pop();
|
|
1250
1315
|
}
|
|
1251
1316
|
this.writeln();
|
|
1252
1317
|
return this;
|
|
@@ -1262,12 +1327,43 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1262
1327
|
}
|
|
1263
1328
|
defineMetadata(node) {
|
|
1264
1329
|
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1330
|
+
let adHocNames;
|
|
1331
|
+
let adHoc;
|
|
1332
|
+
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1333
|
+
const path$2 = this._propPath.join(".");
|
|
1334
|
+
adHoc = this._adHocAnnotations.get(path$2);
|
|
1335
|
+
if (adHoc) adHocNames = new Set(adHoc.map((a) => a.name));
|
|
1336
|
+
}
|
|
1265
1337
|
annotations?.forEach((an) => {
|
|
1338
|
+
if (!adHocNames || !adHocNames.has(an.name)) this.resolveAnnotationValue(node, an);
|
|
1339
|
+
});
|
|
1340
|
+
adHoc?.forEach((an) => {
|
|
1266
1341
|
this.resolveAnnotationValue(node, an);
|
|
1267
1342
|
});
|
|
1268
1343
|
return this;
|
|
1269
1344
|
}
|
|
1345
|
+
/**
|
|
1346
|
+
* For non-mutating annotate aliases: merge the target's type-level annotations
|
|
1347
|
+
* with the annotate block's own annotations (annotate's take priority).
|
|
1348
|
+
*/ defineMetadataForAnnotateAlias(annotateNode) {
|
|
1349
|
+
const annotateAnnotations = this.doc.evalAnnotationsForNode(annotateNode);
|
|
1350
|
+
const targetDecl = this.doc.getDeclarationOwnerNode(annotateNode.targetName);
|
|
1351
|
+
const targetAnnotations = targetDecl?.node ? targetDecl.doc.evalAnnotationsForNode(targetDecl.node) : undefined;
|
|
1352
|
+
const overriddenNames = new Set(annotateAnnotations?.map((a) => a.name));
|
|
1353
|
+
targetAnnotations?.forEach((an) => {
|
|
1354
|
+
if (!overriddenNames.has(an.name)) this.resolveAnnotationValue(annotateNode, an);
|
|
1355
|
+
});
|
|
1356
|
+
annotateAnnotations?.forEach((an) => {
|
|
1357
|
+
this.resolveAnnotationValue(annotateNode, an);
|
|
1358
|
+
});
|
|
1359
|
+
return this;
|
|
1360
|
+
}
|
|
1270
1361
|
resolveAnnotationValue(node, an) {
|
|
1362
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1363
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
|
|
1364
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
|
|
1365
|
+
}
|
|
1366
|
+
computeAnnotationValue(node, an) {
|
|
1271
1367
|
const spec = this.doc.resolveAnnotation(an.name);
|
|
1272
1368
|
let targetValue = "true";
|
|
1273
1369
|
let multiple = false;
|
|
@@ -1279,7 +1375,6 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1279
1375
|
let i = 0;
|
|
1280
1376
|
for (const aSpec of spec.arguments) {
|
|
1281
1377
|
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
1282
|
-
else {}
|
|
1283
1378
|
i++;
|
|
1284
1379
|
}
|
|
1285
1380
|
targetValue += "}";
|
|
@@ -1292,11 +1387,52 @@ else targetValue = "true";
|
|
|
1292
1387
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1293
1388
|
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1294
1389
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1390
|
+
return {
|
|
1391
|
+
value: targetValue,
|
|
1392
|
+
multiple: !!multiple
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
renderMutatingAnnotates() {
|
|
1396
|
+
for (const node of this.mutatingAnnotates) {
|
|
1397
|
+
const targetName = node.targetName;
|
|
1398
|
+
for (const entry of node.entries) {
|
|
1399
|
+
const anns = entry.annotations;
|
|
1400
|
+
if (!anns || anns.length === 0) continue;
|
|
1401
|
+
const parts = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)] : [entry.id];
|
|
1402
|
+
let accessor = targetName;
|
|
1403
|
+
for (const part of parts) accessor += `.type.props.get("${escapeQuotes(part)}")?`;
|
|
1404
|
+
for (const an of anns) {
|
|
1405
|
+
const { value, multiple } = this.computeAnnotationValue(entry, an);
|
|
1406
|
+
if (multiple) {
|
|
1407
|
+
this.writeln(`{`);
|
|
1408
|
+
this.indent();
|
|
1409
|
+
this.writeln(`const __t = ${accessor}.metadata`);
|
|
1410
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1411
|
+
this.writeln(`const __v = ${value}`);
|
|
1412
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1413
|
+
this.unindent();
|
|
1414
|
+
this.writeln(`}`);
|
|
1415
|
+
} else this.writeln(`${accessor}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
const topAnnotations = node.annotations;
|
|
1419
|
+
if (topAnnotations && topAnnotations.length > 0) for (const an of topAnnotations) {
|
|
1420
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1421
|
+
if (multiple) {
|
|
1422
|
+
this.writeln(`{`);
|
|
1423
|
+
this.indent();
|
|
1424
|
+
this.writeln(`const __t = ${targetName}.metadata`);
|
|
1425
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1426
|
+
this.writeln(`const __v = ${value}`);
|
|
1427
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1428
|
+
this.unindent();
|
|
1429
|
+
this.writeln(`}`);
|
|
1430
|
+
} else this.writeln(`${targetName}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1297
1433
|
}
|
|
1298
1434
|
constructor(doc, opts) {
|
|
1299
|
-
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1435
|
+
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), _define_property(this, "mutatingAnnotates", void 0), _define_property(this, "_adHocAnnotations", void 0), _define_property(this, "_propPath", void 0), this.opts = opts, this.postAnnotate = [], this.mutatingAnnotates = [], this._adHocAnnotations = null, this._propPath = [];
|
|
1300
1436
|
}
|
|
1301
1437
|
};
|
|
1302
1438
|
|
package/dist/index.mjs
CHANGED
|
@@ -126,6 +126,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
126
126
|
}
|
|
127
127
|
renderInterface(node) {}
|
|
128
128
|
renderType(node) {}
|
|
129
|
+
renderAnnotate(node) {}
|
|
129
130
|
transformFromPath(path$1) {
|
|
130
131
|
return `${path$1}.as`;
|
|
131
132
|
}
|
|
@@ -160,6 +161,10 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
160
161
|
this.renderImport(node);
|
|
161
162
|
break;
|
|
162
163
|
}
|
|
164
|
+
case "annotate": {
|
|
165
|
+
this.renderAnnotate(node);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
163
168
|
default: break;
|
|
164
169
|
}
|
|
165
170
|
}
|
|
@@ -319,6 +324,26 @@ else this.writeln("{}");
|
|
|
319
324
|
this.writeln();
|
|
320
325
|
this.renderTypeNamespace(node);
|
|
321
326
|
}
|
|
327
|
+
renderAnnotate(node) {
|
|
328
|
+
if (node.isMutating) return;
|
|
329
|
+
const targetName = node.targetName;
|
|
330
|
+
const unwound = this.doc.unwindType(targetName);
|
|
331
|
+
if (!unwound?.def) return;
|
|
332
|
+
const def = this.doc.mergeIntersection(unwound.def);
|
|
333
|
+
this.writeln();
|
|
334
|
+
const exported = node.token("export")?.text === "export";
|
|
335
|
+
this.renderJsDoc(node);
|
|
336
|
+
if (isStructure(def) || isInterface(def)) {
|
|
337
|
+
this.write(exported ? "export declare " : "declare ");
|
|
338
|
+
this.write(`class ${node.id} `);
|
|
339
|
+
this.renderStructure(def, node.id);
|
|
340
|
+
} else {
|
|
341
|
+
this.write(exported ? "export " : "declare ");
|
|
342
|
+
this.write(`type ${node.id} = `);
|
|
343
|
+
this.renderTypeDef(def);
|
|
344
|
+
}
|
|
345
|
+
this.writeln();
|
|
346
|
+
}
|
|
322
347
|
renderTypeNamespace(node) {
|
|
323
348
|
this.write(`declare namespace ${node.id} `);
|
|
324
349
|
this.blockln("{}");
|
|
@@ -920,36 +945,58 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
920
945
|
if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
|
|
921
946
|
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
|
|
922
947
|
}
|
|
948
|
+
buildAdHocMap(annotateNodes) {
|
|
949
|
+
const map = new Map();
|
|
950
|
+
for (const annotateNode of annotateNodes) for (const entry of annotateNode.entries) {
|
|
951
|
+
const path$1 = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)].join(".") : entry.id;
|
|
952
|
+
const anns = entry.annotations || [];
|
|
953
|
+
if (anns.length > 0) {
|
|
954
|
+
const existing = map.get(path$1);
|
|
955
|
+
map.set(path$1, existing ? [...existing, ...anns] : anns);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return map.size > 0 ? map : null;
|
|
959
|
+
}
|
|
923
960
|
post() {
|
|
924
|
-
for (const node of this.postAnnotate) {
|
|
961
|
+
for (const node of this.postAnnotate) if (node.entity === "annotate") {
|
|
962
|
+
const annotateNode = node;
|
|
963
|
+
const unwound = this.doc.unwindType(annotateNode.targetName);
|
|
964
|
+
if (unwound?.def) {
|
|
965
|
+
let def = this.doc.mergeIntersection(unwound.def);
|
|
966
|
+
if (isInterface(def)) def = def.getDefinition() || def;
|
|
967
|
+
this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
|
|
968
|
+
this.annotateType(def, node.id);
|
|
969
|
+
this._adHocAnnotations = null;
|
|
970
|
+
this.indent();
|
|
971
|
+
this.defineMetadataForAnnotateAlias(annotateNode);
|
|
972
|
+
this.unindent();
|
|
973
|
+
this.writeln();
|
|
974
|
+
}
|
|
975
|
+
} else {
|
|
976
|
+
const mutatingNodes = this.doc.getAnnotateNodesFor(node.id).filter((n) => n.isMutating);
|
|
977
|
+
this._adHocAnnotations = this.buildAdHocMap(mutatingNodes);
|
|
925
978
|
this.annotateType(node.getDefinition(), node.id);
|
|
979
|
+
this._adHocAnnotations = null;
|
|
926
980
|
this.indent().defineMetadata(node).unindent();
|
|
927
981
|
this.writeln();
|
|
928
982
|
}
|
|
983
|
+
this.renderMutatingAnnotates();
|
|
929
984
|
this.writeln("// prettier-ignore-end");
|
|
930
985
|
super.post();
|
|
931
986
|
}
|
|
987
|
+
renderClassStatics(node) {
|
|
988
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
989
|
+
this.writeln("static type = {}");
|
|
990
|
+
this.writeln("static metadata = new Map()");
|
|
991
|
+
this.renderJsonSchemaMethod(node);
|
|
992
|
+
}
|
|
932
993
|
renderInterface(node) {
|
|
933
994
|
this.writeln();
|
|
934
995
|
const exported = node.token("export")?.text === "export";
|
|
935
996
|
this.write(exported ? "export " : "");
|
|
936
997
|
this.write(`class ${node.id} `);
|
|
937
998
|
this.blockln("{}");
|
|
938
|
-
this.
|
|
939
|
-
this.writeln("static type = {}");
|
|
940
|
-
this.writeln("static metadata = new Map()");
|
|
941
|
-
if (this.opts?.preRenderJsonSchema) {
|
|
942
|
-
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
943
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
944
|
-
this.writeln("static toJsonSchema() {");
|
|
945
|
-
this.indent().writeln("return this._jsonSchema").unindent();
|
|
946
|
-
this.writeln("}");
|
|
947
|
-
} else {
|
|
948
|
-
this.writeln("static _jsonSchema");
|
|
949
|
-
this.writeln("static toJsonSchema() {");
|
|
950
|
-
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
951
|
-
this.writeln("}");
|
|
952
|
-
}
|
|
999
|
+
this.renderClassStatics(node);
|
|
953
1000
|
this.popln();
|
|
954
1001
|
this.postAnnotate.push(node);
|
|
955
1002
|
this.writeln();
|
|
@@ -960,24 +1007,40 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
960
1007
|
this.write(exported ? "export " : "");
|
|
961
1008
|
this.write(`class ${node.id} `);
|
|
962
1009
|
this.blockln("{}");
|
|
963
|
-
this.
|
|
964
|
-
this.
|
|
965
|
-
this.
|
|
1010
|
+
this.renderClassStatics(node);
|
|
1011
|
+
this.popln();
|
|
1012
|
+
this.postAnnotate.push(node);
|
|
1013
|
+
this.writeln();
|
|
1014
|
+
}
|
|
1015
|
+
renderAnnotate(node) {
|
|
1016
|
+
if (node.isMutating) {
|
|
1017
|
+
this.mutatingAnnotates.push(node);
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const targetName = node.targetName;
|
|
1021
|
+
const unwound = this.doc.unwindType(targetName);
|
|
1022
|
+
if (!unwound?.def) return;
|
|
1023
|
+
this.writeln();
|
|
1024
|
+
const exported = node.token("export")?.text === "export";
|
|
1025
|
+
this.write(exported ? "export " : "");
|
|
1026
|
+
this.write(`class ${node.id} `);
|
|
1027
|
+
this.blockln("{}");
|
|
1028
|
+
this.renderClassStatics(node);
|
|
1029
|
+
this.popln();
|
|
1030
|
+
this.postAnnotate.push(node);
|
|
1031
|
+
this.writeln();
|
|
1032
|
+
}
|
|
1033
|
+
renderJsonSchemaMethod(node) {
|
|
966
1034
|
if (this.opts?.preRenderJsonSchema) {
|
|
967
1035
|
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
968
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
969
1036
|
this.writeln("static toJsonSchema() {");
|
|
970
|
-
this.indent().writeln(
|
|
1037
|
+
this.indent().writeln(`return ${schema}`).unindent();
|
|
971
1038
|
this.writeln("}");
|
|
972
1039
|
} else {
|
|
973
|
-
this.writeln("static _jsonSchema");
|
|
974
1040
|
this.writeln("static toJsonSchema() {");
|
|
975
1041
|
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
976
1042
|
this.writeln("}");
|
|
977
1043
|
}
|
|
978
|
-
this.popln();
|
|
979
|
-
this.postAnnotate.push(node);
|
|
980
|
-
this.writeln();
|
|
981
1044
|
}
|
|
982
1045
|
toAnnotatedType(node) {
|
|
983
1046
|
return this.toAnnotatedHandle(node).$type;
|
|
@@ -1208,6 +1271,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1208
1271
|
for (const prop of props) {
|
|
1209
1272
|
const pattern = prop.token("identifier")?.pattern;
|
|
1210
1273
|
const optional = !!prop.token("optional");
|
|
1274
|
+
this._propPath.push(prop.id);
|
|
1211
1275
|
if (pattern) {
|
|
1212
1276
|
this.writeln(`.propPattern(`);
|
|
1213
1277
|
this.indent();
|
|
@@ -1223,6 +1287,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1223
1287
|
this.writeln(" .$type");
|
|
1224
1288
|
this.unindent();
|
|
1225
1289
|
this.write(`)`);
|
|
1290
|
+
this._propPath.pop();
|
|
1226
1291
|
}
|
|
1227
1292
|
this.writeln();
|
|
1228
1293
|
return this;
|
|
@@ -1238,12 +1303,43 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1238
1303
|
}
|
|
1239
1304
|
defineMetadata(node) {
|
|
1240
1305
|
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1306
|
+
let adHocNames;
|
|
1307
|
+
let adHoc;
|
|
1308
|
+
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1309
|
+
const path$1 = this._propPath.join(".");
|
|
1310
|
+
adHoc = this._adHocAnnotations.get(path$1);
|
|
1311
|
+
if (adHoc) adHocNames = new Set(adHoc.map((a) => a.name));
|
|
1312
|
+
}
|
|
1241
1313
|
annotations?.forEach((an) => {
|
|
1314
|
+
if (!adHocNames || !adHocNames.has(an.name)) this.resolveAnnotationValue(node, an);
|
|
1315
|
+
});
|
|
1316
|
+
adHoc?.forEach((an) => {
|
|
1242
1317
|
this.resolveAnnotationValue(node, an);
|
|
1243
1318
|
});
|
|
1244
1319
|
return this;
|
|
1245
1320
|
}
|
|
1321
|
+
/**
|
|
1322
|
+
* For non-mutating annotate aliases: merge the target's type-level annotations
|
|
1323
|
+
* with the annotate block's own annotations (annotate's take priority).
|
|
1324
|
+
*/ defineMetadataForAnnotateAlias(annotateNode) {
|
|
1325
|
+
const annotateAnnotations = this.doc.evalAnnotationsForNode(annotateNode);
|
|
1326
|
+
const targetDecl = this.doc.getDeclarationOwnerNode(annotateNode.targetName);
|
|
1327
|
+
const targetAnnotations = targetDecl?.node ? targetDecl.doc.evalAnnotationsForNode(targetDecl.node) : undefined;
|
|
1328
|
+
const overriddenNames = new Set(annotateAnnotations?.map((a) => a.name));
|
|
1329
|
+
targetAnnotations?.forEach((an) => {
|
|
1330
|
+
if (!overriddenNames.has(an.name)) this.resolveAnnotationValue(annotateNode, an);
|
|
1331
|
+
});
|
|
1332
|
+
annotateAnnotations?.forEach((an) => {
|
|
1333
|
+
this.resolveAnnotationValue(annotateNode, an);
|
|
1334
|
+
});
|
|
1335
|
+
return this;
|
|
1336
|
+
}
|
|
1246
1337
|
resolveAnnotationValue(node, an) {
|
|
1338
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1339
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
|
|
1340
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
|
|
1341
|
+
}
|
|
1342
|
+
computeAnnotationValue(node, an) {
|
|
1247
1343
|
const spec = this.doc.resolveAnnotation(an.name);
|
|
1248
1344
|
let targetValue = "true";
|
|
1249
1345
|
let multiple = false;
|
|
@@ -1255,7 +1351,6 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1255
1351
|
let i = 0;
|
|
1256
1352
|
for (const aSpec of spec.arguments) {
|
|
1257
1353
|
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
1258
|
-
else {}
|
|
1259
1354
|
i++;
|
|
1260
1355
|
}
|
|
1261
1356
|
targetValue += "}";
|
|
@@ -1268,11 +1363,52 @@ else targetValue = "true";
|
|
|
1268
1363
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1269
1364
|
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1270
1365
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1366
|
+
return {
|
|
1367
|
+
value: targetValue,
|
|
1368
|
+
multiple: !!multiple
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
renderMutatingAnnotates() {
|
|
1372
|
+
for (const node of this.mutatingAnnotates) {
|
|
1373
|
+
const targetName = node.targetName;
|
|
1374
|
+
for (const entry of node.entries) {
|
|
1375
|
+
const anns = entry.annotations;
|
|
1376
|
+
if (!anns || anns.length === 0) continue;
|
|
1377
|
+
const parts = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)] : [entry.id];
|
|
1378
|
+
let accessor = targetName;
|
|
1379
|
+
for (const part of parts) accessor += `.type.props.get("${escapeQuotes(part)}")?`;
|
|
1380
|
+
for (const an of anns) {
|
|
1381
|
+
const { value, multiple } = this.computeAnnotationValue(entry, an);
|
|
1382
|
+
if (multiple) {
|
|
1383
|
+
this.writeln(`{`);
|
|
1384
|
+
this.indent();
|
|
1385
|
+
this.writeln(`const __t = ${accessor}.metadata`);
|
|
1386
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1387
|
+
this.writeln(`const __v = ${value}`);
|
|
1388
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1389
|
+
this.unindent();
|
|
1390
|
+
this.writeln(`}`);
|
|
1391
|
+
} else this.writeln(`${accessor}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
const topAnnotations = node.annotations;
|
|
1395
|
+
if (topAnnotations && topAnnotations.length > 0) for (const an of topAnnotations) {
|
|
1396
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1397
|
+
if (multiple) {
|
|
1398
|
+
this.writeln(`{`);
|
|
1399
|
+
this.indent();
|
|
1400
|
+
this.writeln(`const __t = ${targetName}.metadata`);
|
|
1401
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1402
|
+
this.writeln(`const __v = ${value}`);
|
|
1403
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1404
|
+
this.unindent();
|
|
1405
|
+
this.writeln(`}`);
|
|
1406
|
+
} else this.writeln(`${targetName}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1273
1409
|
}
|
|
1274
1410
|
constructor(doc, opts) {
|
|
1275
|
-
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1411
|
+
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), _define_property(this, "mutatingAnnotates", void 0), _define_property(this, "_adHocAnnotations", void 0), _define_property(this, "_propPath", void 0), this.opts = opts, this.postAnnotate = [], this.mutatingAnnotates = [], this._adHocAnnotations = null, this._propPath = [];
|
|
1276
1412
|
}
|
|
1277
1413
|
};
|
|
1278
1414
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Atscript: typescript-gen support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"homepage": "https://github.com/moostjs/atscript/tree/main/packages/typescript#readme",
|
|
71
71
|
"license": "ISC",
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@atscript/core": "^0.
|
|
73
|
+
"@atscript/core": "^0.1.1"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@moostjs/event-cli": "^0.5.32",
|