@atscript/typescript 0.0.31 → 0.1.0
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 +198 -33
- package/dist/index.cjs +159 -29
- package/dist/index.mjs +159 -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,12 +972,42 @@ 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
|
}
|
|
@@ -962,21 +1017,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
962
1017
|
this.write(exported ? "export " : "");
|
|
963
1018
|
this.write(`class ${node.id} `);
|
|
964
1019
|
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
|
-
}
|
|
1020
|
+
this.renderJsonSchemaMethod(node);
|
|
980
1021
|
this.popln();
|
|
981
1022
|
this.postAnnotate.push(node);
|
|
982
1023
|
this.writeln();
|
|
@@ -987,24 +1028,40 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
987
1028
|
this.write(exported ? "export " : "");
|
|
988
1029
|
this.write(`class ${node.id} `);
|
|
989
1030
|
this.blockln("{}");
|
|
990
|
-
this.
|
|
991
|
-
this.
|
|
992
|
-
this.
|
|
1031
|
+
this.renderJsonSchemaMethod(node);
|
|
1032
|
+
this.popln();
|
|
1033
|
+
this.postAnnotate.push(node);
|
|
1034
|
+
this.writeln();
|
|
1035
|
+
}
|
|
1036
|
+
renderAnnotate(node) {
|
|
1037
|
+
if (node.isMutating) {
|
|
1038
|
+
this.mutatingAnnotates.push(node);
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
const targetName = node.targetName;
|
|
1042
|
+
const unwound = this.doc.unwindType(targetName);
|
|
1043
|
+
if (!unwound?.def) return;
|
|
1044
|
+
this.writeln();
|
|
1045
|
+
const exported = node.token("export")?.text === "export";
|
|
1046
|
+
this.write(exported ? "export " : "");
|
|
1047
|
+
this.write(`class ${node.id} `);
|
|
1048
|
+
this.blockln("{}");
|
|
1049
|
+
this.renderJsonSchemaMethod(node);
|
|
1050
|
+
this.popln();
|
|
1051
|
+
this.postAnnotate.push(node);
|
|
1052
|
+
this.writeln();
|
|
1053
|
+
}
|
|
1054
|
+
renderJsonSchemaMethod(node) {
|
|
993
1055
|
if (this.opts?.preRenderJsonSchema) {
|
|
994
1056
|
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
995
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
996
1057
|
this.writeln("static toJsonSchema() {");
|
|
997
|
-
this.indent().writeln(
|
|
1058
|
+
this.indent().writeln(`return ${schema}`).unindent();
|
|
998
1059
|
this.writeln("}");
|
|
999
1060
|
} else {
|
|
1000
|
-
this.writeln("static _jsonSchema");
|
|
1001
1061
|
this.writeln("static toJsonSchema() {");
|
|
1002
1062
|
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
1003
1063
|
this.writeln("}");
|
|
1004
1064
|
}
|
|
1005
|
-
this.popln();
|
|
1006
|
-
this.postAnnotate.push(node);
|
|
1007
|
-
this.writeln();
|
|
1008
1065
|
}
|
|
1009
1066
|
toAnnotatedType(node) {
|
|
1010
1067
|
return this.toAnnotatedHandle(node).$type;
|
|
@@ -1235,6 +1292,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1235
1292
|
for (const prop of props) {
|
|
1236
1293
|
const pattern = prop.token("identifier")?.pattern;
|
|
1237
1294
|
const optional = !!prop.token("optional");
|
|
1295
|
+
this._propPath.push(prop.id);
|
|
1238
1296
|
if (pattern) {
|
|
1239
1297
|
this.writeln(`.propPattern(`);
|
|
1240
1298
|
this.indent();
|
|
@@ -1250,6 +1308,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1250
1308
|
this.writeln(" .$type");
|
|
1251
1309
|
this.unindent();
|
|
1252
1310
|
this.write(`)`);
|
|
1311
|
+
this._propPath.pop();
|
|
1253
1312
|
}
|
|
1254
1313
|
this.writeln();
|
|
1255
1314
|
return this;
|
|
@@ -1265,12 +1324,43 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1265
1324
|
}
|
|
1266
1325
|
defineMetadata(node) {
|
|
1267
1326
|
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1327
|
+
let adHocNames;
|
|
1328
|
+
let adHoc;
|
|
1329
|
+
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1330
|
+
const path$3 = this._propPath.join(".");
|
|
1331
|
+
adHoc = this._adHocAnnotations.get(path$3);
|
|
1332
|
+
if (adHoc) adHocNames = new Set(adHoc.map((a) => a.name));
|
|
1333
|
+
}
|
|
1268
1334
|
annotations?.forEach((an) => {
|
|
1335
|
+
if (!adHocNames || !adHocNames.has(an.name)) this.resolveAnnotationValue(node, an);
|
|
1336
|
+
});
|
|
1337
|
+
adHoc?.forEach((an) => {
|
|
1269
1338
|
this.resolveAnnotationValue(node, an);
|
|
1270
1339
|
});
|
|
1271
1340
|
return this;
|
|
1272
1341
|
}
|
|
1342
|
+
/**
|
|
1343
|
+
* For non-mutating annotate aliases: merge the target's type-level annotations
|
|
1344
|
+
* with the annotate block's own annotations (annotate's take priority).
|
|
1345
|
+
*/ defineMetadataForAnnotateAlias(annotateNode) {
|
|
1346
|
+
const annotateAnnotations = this.doc.evalAnnotationsForNode(annotateNode);
|
|
1347
|
+
const targetDecl = this.doc.getDeclarationOwnerNode(annotateNode.targetName);
|
|
1348
|
+
const targetAnnotations = targetDecl?.node ? targetDecl.doc.evalAnnotationsForNode(targetDecl.node) : undefined;
|
|
1349
|
+
const overriddenNames = new Set(annotateAnnotations?.map((a) => a.name));
|
|
1350
|
+
targetAnnotations?.forEach((an) => {
|
|
1351
|
+
if (!overriddenNames.has(an.name)) this.resolveAnnotationValue(annotateNode, an);
|
|
1352
|
+
});
|
|
1353
|
+
annotateAnnotations?.forEach((an) => {
|
|
1354
|
+
this.resolveAnnotationValue(annotateNode, an);
|
|
1355
|
+
});
|
|
1356
|
+
return this;
|
|
1357
|
+
}
|
|
1273
1358
|
resolveAnnotationValue(node, an) {
|
|
1359
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1360
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
|
|
1361
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
|
|
1362
|
+
}
|
|
1363
|
+
computeAnnotationValue(node, an) {
|
|
1274
1364
|
const spec = this.doc.resolveAnnotation(an.name);
|
|
1275
1365
|
let targetValue = "true";
|
|
1276
1366
|
let multiple = false;
|
|
@@ -1282,7 +1372,6 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1282
1372
|
let i = 0;
|
|
1283
1373
|
for (const aSpec of spec.arguments) {
|
|
1284
1374
|
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
1375
|
i++;
|
|
1287
1376
|
}
|
|
1288
1377
|
targetValue += "}";
|
|
@@ -1295,11 +1384,52 @@ else targetValue = "true";
|
|
|
1295
1384
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1296
1385
|
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1297
1386
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1387
|
+
return {
|
|
1388
|
+
value: targetValue,
|
|
1389
|
+
multiple: !!multiple
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
renderMutatingAnnotates() {
|
|
1393
|
+
for (const node of this.mutatingAnnotates) {
|
|
1394
|
+
const targetName = node.targetName;
|
|
1395
|
+
for (const entry of node.entries) {
|
|
1396
|
+
const anns = entry.annotations;
|
|
1397
|
+
if (!anns || anns.length === 0) continue;
|
|
1398
|
+
const parts = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)] : [entry.id];
|
|
1399
|
+
let accessor = targetName;
|
|
1400
|
+
for (const part of parts) accessor += `.type.props.get("${escapeQuotes(part)}")?`;
|
|
1401
|
+
for (const an of anns) {
|
|
1402
|
+
const { value, multiple } = this.computeAnnotationValue(entry, an);
|
|
1403
|
+
if (multiple) {
|
|
1404
|
+
this.writeln(`{`);
|
|
1405
|
+
this.indent();
|
|
1406
|
+
this.writeln(`const __t = ${accessor}.metadata`);
|
|
1407
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1408
|
+
this.writeln(`const __v = ${value}`);
|
|
1409
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1410
|
+
this.unindent();
|
|
1411
|
+
this.writeln(`}`);
|
|
1412
|
+
} else this.writeln(`${accessor}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
const topAnnotations = node.annotations;
|
|
1416
|
+
if (topAnnotations && topAnnotations.length > 0) for (const an of topAnnotations) {
|
|
1417
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1418
|
+
if (multiple) {
|
|
1419
|
+
this.writeln(`{`);
|
|
1420
|
+
this.indent();
|
|
1421
|
+
this.writeln(`const __t = ${targetName}.metadata`);
|
|
1422
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1423
|
+
this.writeln(`const __v = ${value}`);
|
|
1424
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1425
|
+
this.unindent();
|
|
1426
|
+
this.writeln(`}`);
|
|
1427
|
+
} else this.writeln(`${targetName}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1300
1430
|
}
|
|
1301
1431
|
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 = [];
|
|
1432
|
+
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
1433
|
}
|
|
1304
1434
|
};
|
|
1305
1435
|
|
|
@@ -1370,13 +1500,35 @@ function _ts_param(paramIndex, decorator) {
|
|
|
1370
1500
|
};
|
|
1371
1501
|
}
|
|
1372
1502
|
var Commands = class {
|
|
1373
|
-
async default(configFile, format) {
|
|
1503
|
+
async default(configFile, format, noEmit, skipDiag) {
|
|
1374
1504
|
const config = await this.getConfig(configFile);
|
|
1375
1505
|
if (format) config.format = format;
|
|
1376
1506
|
this.logger.log(`Format: ${"\x1B[36m"}${config.format}${"\x1B[39m"}`);
|
|
1377
1507
|
const builder = await (0, __atscript_core.build)(config);
|
|
1378
|
-
|
|
1379
|
-
|
|
1508
|
+
let errorCount = 0;
|
|
1509
|
+
let warningCount = 0;
|
|
1510
|
+
if (!skipDiag) {
|
|
1511
|
+
const diagMap = await builder.diagnostics();
|
|
1512
|
+
for (const [docId, messages] of diagMap) {
|
|
1513
|
+
const doc = builder.getDoc(docId);
|
|
1514
|
+
for (const m of messages) {
|
|
1515
|
+
if (m.severity === 1) errorCount++;
|
|
1516
|
+
else if (m.severity === 2) warningCount++;
|
|
1517
|
+
if (doc) this.logger.log(doc.renderDiagMessage(m, true, true));
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
if (!noEmit) {
|
|
1522
|
+
const out = await builder.write(config);
|
|
1523
|
+
for (const { target } of out) this.logger.log(`✅ created ${"\x1B[32m"}${target}${"\x1B[39m"}`);
|
|
1524
|
+
}
|
|
1525
|
+
if (errorCount > 0 || warningCount > 0) {
|
|
1526
|
+
const parts = [];
|
|
1527
|
+
if (errorCount > 0) parts.push(`${"\x1B[31m"}${errorCount} error${errorCount > 1 ? "s" : ""}${"\x1B[39m"}`);
|
|
1528
|
+
if (warningCount > 0) parts.push(`${"\x1B[33m"}${warningCount} warning${warningCount > 1 ? "s" : ""}${"\x1B[39m"}`);
|
|
1529
|
+
this.logger.log(`\nFound ${parts.join(" and ")}`);
|
|
1530
|
+
}
|
|
1531
|
+
if (errorCount > 0) process.exit(1);
|
|
1380
1532
|
}
|
|
1381
1533
|
async getConfig(configFile) {
|
|
1382
1534
|
const root = process.cwd();
|
|
@@ -1411,14 +1563,27 @@ _ts_decorate([
|
|
|
1411
1563
|
(0, moost.Description)("Builds .as files using --config and --format"),
|
|
1412
1564
|
(0, __moostjs_event_cli.CliExample)("-c atscript.config.js", "Build .as files using atscript.config.js"),
|
|
1413
1565
|
(0, __moostjs_event_cli.CliExample)("-f dts", "Build \"d.ts\" files for \".as\" files"),
|
|
1566
|
+
(0, __moostjs_event_cli.CliExample)("--noEmit", "Only check for errors, do not emit files"),
|
|
1567
|
+
(0, __moostjs_event_cli.CliExample)("--skipDiag", "Emit files without running diagnostics"),
|
|
1414
1568
|
_ts_param(0, (0, __moostjs_event_cli.CliOption)("c", "config")),
|
|
1415
1569
|
_ts_param(0, (0, moost.Optional)()),
|
|
1416
1570
|
_ts_param(0, (0, moost.Description)("Path to config file")),
|
|
1417
1571
|
_ts_param(1, (0, __moostjs_event_cli.CliOption)("f", "format")),
|
|
1418
1572
|
_ts_param(1, (0, moost.Optional)()),
|
|
1419
1573
|
_ts_param(1, (0, moost.Description)("Output format (js|dts), default: \"dts\"")),
|
|
1574
|
+
_ts_param(2, (0, __moostjs_event_cli.CliOption)("noEmit")),
|
|
1575
|
+
_ts_param(2, (0, moost.Optional)()),
|
|
1576
|
+
_ts_param(2, (0, moost.Description)("Only run diagnostics without emitting files")),
|
|
1577
|
+
_ts_param(3, (0, __moostjs_event_cli.CliOption)("skipDiag")),
|
|
1578
|
+
_ts_param(3, (0, moost.Optional)()),
|
|
1579
|
+
_ts_param(3, (0, moost.Description)("Skip diagnostics and always emit files")),
|
|
1420
1580
|
_ts_metadata("design:type", Function),
|
|
1421
|
-
_ts_metadata("design:paramtypes", [
|
|
1581
|
+
_ts_metadata("design:paramtypes", [
|
|
1582
|
+
String,
|
|
1583
|
+
String,
|
|
1584
|
+
Boolean,
|
|
1585
|
+
Boolean
|
|
1586
|
+
]),
|
|
1422
1587
|
_ts_metadata("design:returntype", Promise)
|
|
1423
1588
|
], Commands.prototype, "default", null);
|
|
1424
1589
|
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,12 +969,42 @@ 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
|
}
|
|
@@ -959,21 +1014,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
959
1014
|
this.write(exported ? "export " : "");
|
|
960
1015
|
this.write(`class ${node.id} `);
|
|
961
1016
|
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
|
-
}
|
|
1017
|
+
this.renderJsonSchemaMethod(node);
|
|
977
1018
|
this.popln();
|
|
978
1019
|
this.postAnnotate.push(node);
|
|
979
1020
|
this.writeln();
|
|
@@ -984,24 +1025,40 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
984
1025
|
this.write(exported ? "export " : "");
|
|
985
1026
|
this.write(`class ${node.id} `);
|
|
986
1027
|
this.blockln("{}");
|
|
987
|
-
this.
|
|
988
|
-
this.
|
|
989
|
-
this.
|
|
1028
|
+
this.renderJsonSchemaMethod(node);
|
|
1029
|
+
this.popln();
|
|
1030
|
+
this.postAnnotate.push(node);
|
|
1031
|
+
this.writeln();
|
|
1032
|
+
}
|
|
1033
|
+
renderAnnotate(node) {
|
|
1034
|
+
if (node.isMutating) {
|
|
1035
|
+
this.mutatingAnnotates.push(node);
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
const targetName = node.targetName;
|
|
1039
|
+
const unwound = this.doc.unwindType(targetName);
|
|
1040
|
+
if (!unwound?.def) return;
|
|
1041
|
+
this.writeln();
|
|
1042
|
+
const exported = node.token("export")?.text === "export";
|
|
1043
|
+
this.write(exported ? "export " : "");
|
|
1044
|
+
this.write(`class ${node.id} `);
|
|
1045
|
+
this.blockln("{}");
|
|
1046
|
+
this.renderJsonSchemaMethod(node);
|
|
1047
|
+
this.popln();
|
|
1048
|
+
this.postAnnotate.push(node);
|
|
1049
|
+
this.writeln();
|
|
1050
|
+
}
|
|
1051
|
+
renderJsonSchemaMethod(node) {
|
|
990
1052
|
if (this.opts?.preRenderJsonSchema) {
|
|
991
1053
|
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
992
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
993
1054
|
this.writeln("static toJsonSchema() {");
|
|
994
|
-
this.indent().writeln(
|
|
1055
|
+
this.indent().writeln(`return ${schema}`).unindent();
|
|
995
1056
|
this.writeln("}");
|
|
996
1057
|
} else {
|
|
997
|
-
this.writeln("static _jsonSchema");
|
|
998
1058
|
this.writeln("static toJsonSchema() {");
|
|
999
1059
|
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
1000
1060
|
this.writeln("}");
|
|
1001
1061
|
}
|
|
1002
|
-
this.popln();
|
|
1003
|
-
this.postAnnotate.push(node);
|
|
1004
|
-
this.writeln();
|
|
1005
1062
|
}
|
|
1006
1063
|
toAnnotatedType(node) {
|
|
1007
1064
|
return this.toAnnotatedHandle(node).$type;
|
|
@@ -1232,6 +1289,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1232
1289
|
for (const prop of props) {
|
|
1233
1290
|
const pattern = prop.token("identifier")?.pattern;
|
|
1234
1291
|
const optional = !!prop.token("optional");
|
|
1292
|
+
this._propPath.push(prop.id);
|
|
1235
1293
|
if (pattern) {
|
|
1236
1294
|
this.writeln(`.propPattern(`);
|
|
1237
1295
|
this.indent();
|
|
@@ -1247,6 +1305,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1247
1305
|
this.writeln(" .$type");
|
|
1248
1306
|
this.unindent();
|
|
1249
1307
|
this.write(`)`);
|
|
1308
|
+
this._propPath.pop();
|
|
1250
1309
|
}
|
|
1251
1310
|
this.writeln();
|
|
1252
1311
|
return this;
|
|
@@ -1262,12 +1321,43 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1262
1321
|
}
|
|
1263
1322
|
defineMetadata(node) {
|
|
1264
1323
|
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1324
|
+
let adHocNames;
|
|
1325
|
+
let adHoc;
|
|
1326
|
+
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1327
|
+
const path$2 = this._propPath.join(".");
|
|
1328
|
+
adHoc = this._adHocAnnotations.get(path$2);
|
|
1329
|
+
if (adHoc) adHocNames = new Set(adHoc.map((a) => a.name));
|
|
1330
|
+
}
|
|
1265
1331
|
annotations?.forEach((an) => {
|
|
1332
|
+
if (!adHocNames || !adHocNames.has(an.name)) this.resolveAnnotationValue(node, an);
|
|
1333
|
+
});
|
|
1334
|
+
adHoc?.forEach((an) => {
|
|
1266
1335
|
this.resolveAnnotationValue(node, an);
|
|
1267
1336
|
});
|
|
1268
1337
|
return this;
|
|
1269
1338
|
}
|
|
1339
|
+
/**
|
|
1340
|
+
* For non-mutating annotate aliases: merge the target's type-level annotations
|
|
1341
|
+
* with the annotate block's own annotations (annotate's take priority).
|
|
1342
|
+
*/ defineMetadataForAnnotateAlias(annotateNode) {
|
|
1343
|
+
const annotateAnnotations = this.doc.evalAnnotationsForNode(annotateNode);
|
|
1344
|
+
const targetDecl = this.doc.getDeclarationOwnerNode(annotateNode.targetName);
|
|
1345
|
+
const targetAnnotations = targetDecl?.node ? targetDecl.doc.evalAnnotationsForNode(targetDecl.node) : undefined;
|
|
1346
|
+
const overriddenNames = new Set(annotateAnnotations?.map((a) => a.name));
|
|
1347
|
+
targetAnnotations?.forEach((an) => {
|
|
1348
|
+
if (!overriddenNames.has(an.name)) this.resolveAnnotationValue(annotateNode, an);
|
|
1349
|
+
});
|
|
1350
|
+
annotateAnnotations?.forEach((an) => {
|
|
1351
|
+
this.resolveAnnotationValue(annotateNode, an);
|
|
1352
|
+
});
|
|
1353
|
+
return this;
|
|
1354
|
+
}
|
|
1270
1355
|
resolveAnnotationValue(node, an) {
|
|
1356
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1357
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
|
|
1358
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
|
|
1359
|
+
}
|
|
1360
|
+
computeAnnotationValue(node, an) {
|
|
1271
1361
|
const spec = this.doc.resolveAnnotation(an.name);
|
|
1272
1362
|
let targetValue = "true";
|
|
1273
1363
|
let multiple = false;
|
|
@@ -1279,7 +1369,6 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1279
1369
|
let i = 0;
|
|
1280
1370
|
for (const aSpec of spec.arguments) {
|
|
1281
1371
|
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
1372
|
i++;
|
|
1284
1373
|
}
|
|
1285
1374
|
targetValue += "}";
|
|
@@ -1292,11 +1381,52 @@ else targetValue = "true";
|
|
|
1292
1381
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1293
1382
|
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1294
1383
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1384
|
+
return {
|
|
1385
|
+
value: targetValue,
|
|
1386
|
+
multiple: !!multiple
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
renderMutatingAnnotates() {
|
|
1390
|
+
for (const node of this.mutatingAnnotates) {
|
|
1391
|
+
const targetName = node.targetName;
|
|
1392
|
+
for (const entry of node.entries) {
|
|
1393
|
+
const anns = entry.annotations;
|
|
1394
|
+
if (!anns || anns.length === 0) continue;
|
|
1395
|
+
const parts = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)] : [entry.id];
|
|
1396
|
+
let accessor = targetName;
|
|
1397
|
+
for (const part of parts) accessor += `.type.props.get("${escapeQuotes(part)}")?`;
|
|
1398
|
+
for (const an of anns) {
|
|
1399
|
+
const { value, multiple } = this.computeAnnotationValue(entry, an);
|
|
1400
|
+
if (multiple) {
|
|
1401
|
+
this.writeln(`{`);
|
|
1402
|
+
this.indent();
|
|
1403
|
+
this.writeln(`const __t = ${accessor}.metadata`);
|
|
1404
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1405
|
+
this.writeln(`const __v = ${value}`);
|
|
1406
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1407
|
+
this.unindent();
|
|
1408
|
+
this.writeln(`}`);
|
|
1409
|
+
} else this.writeln(`${accessor}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
const topAnnotations = node.annotations;
|
|
1413
|
+
if (topAnnotations && topAnnotations.length > 0) for (const an of topAnnotations) {
|
|
1414
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1415
|
+
if (multiple) {
|
|
1416
|
+
this.writeln(`{`);
|
|
1417
|
+
this.indent();
|
|
1418
|
+
this.writeln(`const __t = ${targetName}.metadata`);
|
|
1419
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1420
|
+
this.writeln(`const __v = ${value}`);
|
|
1421
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1422
|
+
this.unindent();
|
|
1423
|
+
this.writeln(`}`);
|
|
1424
|
+
} else this.writeln(`${targetName}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1297
1427
|
}
|
|
1298
1428
|
constructor(doc, opts) {
|
|
1299
|
-
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1429
|
+
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
1430
|
}
|
|
1301
1431
|
};
|
|
1302
1432
|
|
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,12 +945,42 @@ 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
|
}
|
|
@@ -935,21 +990,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
935
990
|
this.write(exported ? "export " : "");
|
|
936
991
|
this.write(`class ${node.id} `);
|
|
937
992
|
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
|
-
}
|
|
993
|
+
this.renderJsonSchemaMethod(node);
|
|
953
994
|
this.popln();
|
|
954
995
|
this.postAnnotate.push(node);
|
|
955
996
|
this.writeln();
|
|
@@ -960,24 +1001,40 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
960
1001
|
this.write(exported ? "export " : "");
|
|
961
1002
|
this.write(`class ${node.id} `);
|
|
962
1003
|
this.blockln("{}");
|
|
963
|
-
this.
|
|
964
|
-
this.
|
|
965
|
-
this.
|
|
1004
|
+
this.renderJsonSchemaMethod(node);
|
|
1005
|
+
this.popln();
|
|
1006
|
+
this.postAnnotate.push(node);
|
|
1007
|
+
this.writeln();
|
|
1008
|
+
}
|
|
1009
|
+
renderAnnotate(node) {
|
|
1010
|
+
if (node.isMutating) {
|
|
1011
|
+
this.mutatingAnnotates.push(node);
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
const targetName = node.targetName;
|
|
1015
|
+
const unwound = this.doc.unwindType(targetName);
|
|
1016
|
+
if (!unwound?.def) return;
|
|
1017
|
+
this.writeln();
|
|
1018
|
+
const exported = node.token("export")?.text === "export";
|
|
1019
|
+
this.write(exported ? "export " : "");
|
|
1020
|
+
this.write(`class ${node.id} `);
|
|
1021
|
+
this.blockln("{}");
|
|
1022
|
+
this.renderJsonSchemaMethod(node);
|
|
1023
|
+
this.popln();
|
|
1024
|
+
this.postAnnotate.push(node);
|
|
1025
|
+
this.writeln();
|
|
1026
|
+
}
|
|
1027
|
+
renderJsonSchemaMethod(node) {
|
|
966
1028
|
if (this.opts?.preRenderJsonSchema) {
|
|
967
1029
|
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
968
|
-
this.writeln(`static _jsonSchema = ${schema}`);
|
|
969
1030
|
this.writeln("static toJsonSchema() {");
|
|
970
|
-
this.indent().writeln(
|
|
1031
|
+
this.indent().writeln(`return ${schema}`).unindent();
|
|
971
1032
|
this.writeln("}");
|
|
972
1033
|
} else {
|
|
973
|
-
this.writeln("static _jsonSchema");
|
|
974
1034
|
this.writeln("static toJsonSchema() {");
|
|
975
1035
|
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
976
1036
|
this.writeln("}");
|
|
977
1037
|
}
|
|
978
|
-
this.popln();
|
|
979
|
-
this.postAnnotate.push(node);
|
|
980
|
-
this.writeln();
|
|
981
1038
|
}
|
|
982
1039
|
toAnnotatedType(node) {
|
|
983
1040
|
return this.toAnnotatedHandle(node).$type;
|
|
@@ -1208,6 +1265,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1208
1265
|
for (const prop of props) {
|
|
1209
1266
|
const pattern = prop.token("identifier")?.pattern;
|
|
1210
1267
|
const optional = !!prop.token("optional");
|
|
1268
|
+
this._propPath.push(prop.id);
|
|
1211
1269
|
if (pattern) {
|
|
1212
1270
|
this.writeln(`.propPattern(`);
|
|
1213
1271
|
this.indent();
|
|
@@ -1223,6 +1281,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1223
1281
|
this.writeln(" .$type");
|
|
1224
1282
|
this.unindent();
|
|
1225
1283
|
this.write(`)`);
|
|
1284
|
+
this._propPath.pop();
|
|
1226
1285
|
}
|
|
1227
1286
|
this.writeln();
|
|
1228
1287
|
return this;
|
|
@@ -1238,12 +1297,43 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1238
1297
|
}
|
|
1239
1298
|
defineMetadata(node) {
|
|
1240
1299
|
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1300
|
+
let adHocNames;
|
|
1301
|
+
let adHoc;
|
|
1302
|
+
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1303
|
+
const path$1 = this._propPath.join(".");
|
|
1304
|
+
adHoc = this._adHocAnnotations.get(path$1);
|
|
1305
|
+
if (adHoc) adHocNames = new Set(adHoc.map((a) => a.name));
|
|
1306
|
+
}
|
|
1241
1307
|
annotations?.forEach((an) => {
|
|
1308
|
+
if (!adHocNames || !adHocNames.has(an.name)) this.resolveAnnotationValue(node, an);
|
|
1309
|
+
});
|
|
1310
|
+
adHoc?.forEach((an) => {
|
|
1242
1311
|
this.resolveAnnotationValue(node, an);
|
|
1243
1312
|
});
|
|
1244
1313
|
return this;
|
|
1245
1314
|
}
|
|
1315
|
+
/**
|
|
1316
|
+
* For non-mutating annotate aliases: merge the target's type-level annotations
|
|
1317
|
+
* with the annotate block's own annotations (annotate's take priority).
|
|
1318
|
+
*/ defineMetadataForAnnotateAlias(annotateNode) {
|
|
1319
|
+
const annotateAnnotations = this.doc.evalAnnotationsForNode(annotateNode);
|
|
1320
|
+
const targetDecl = this.doc.getDeclarationOwnerNode(annotateNode.targetName);
|
|
1321
|
+
const targetAnnotations = targetDecl?.node ? targetDecl.doc.evalAnnotationsForNode(targetDecl.node) : undefined;
|
|
1322
|
+
const overriddenNames = new Set(annotateAnnotations?.map((a) => a.name));
|
|
1323
|
+
targetAnnotations?.forEach((an) => {
|
|
1324
|
+
if (!overriddenNames.has(an.name)) this.resolveAnnotationValue(annotateNode, an);
|
|
1325
|
+
});
|
|
1326
|
+
annotateAnnotations?.forEach((an) => {
|
|
1327
|
+
this.resolveAnnotationValue(annotateNode, an);
|
|
1328
|
+
});
|
|
1329
|
+
return this;
|
|
1330
|
+
}
|
|
1246
1331
|
resolveAnnotationValue(node, an) {
|
|
1332
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1333
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
|
|
1334
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
|
|
1335
|
+
}
|
|
1336
|
+
computeAnnotationValue(node, an) {
|
|
1247
1337
|
const spec = this.doc.resolveAnnotation(an.name);
|
|
1248
1338
|
let targetValue = "true";
|
|
1249
1339
|
let multiple = false;
|
|
@@ -1255,7 +1345,6 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1255
1345
|
let i = 0;
|
|
1256
1346
|
for (const aSpec of spec.arguments) {
|
|
1257
1347
|
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
1348
|
i++;
|
|
1260
1349
|
}
|
|
1261
1350
|
targetValue += "}";
|
|
@@ -1268,11 +1357,52 @@ else targetValue = "true";
|
|
|
1268
1357
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1269
1358
|
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1270
1359
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1360
|
+
return {
|
|
1361
|
+
value: targetValue,
|
|
1362
|
+
multiple: !!multiple
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
renderMutatingAnnotates() {
|
|
1366
|
+
for (const node of this.mutatingAnnotates) {
|
|
1367
|
+
const targetName = node.targetName;
|
|
1368
|
+
for (const entry of node.entries) {
|
|
1369
|
+
const anns = entry.annotations;
|
|
1370
|
+
if (!anns || anns.length === 0) continue;
|
|
1371
|
+
const parts = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)] : [entry.id];
|
|
1372
|
+
let accessor = targetName;
|
|
1373
|
+
for (const part of parts) accessor += `.type.props.get("${escapeQuotes(part)}")?`;
|
|
1374
|
+
for (const an of anns) {
|
|
1375
|
+
const { value, multiple } = this.computeAnnotationValue(entry, an);
|
|
1376
|
+
if (multiple) {
|
|
1377
|
+
this.writeln(`{`);
|
|
1378
|
+
this.indent();
|
|
1379
|
+
this.writeln(`const __t = ${accessor}.metadata`);
|
|
1380
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1381
|
+
this.writeln(`const __v = ${value}`);
|
|
1382
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1383
|
+
this.unindent();
|
|
1384
|
+
this.writeln(`}`);
|
|
1385
|
+
} else this.writeln(`${accessor}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
const topAnnotations = node.annotations;
|
|
1389
|
+
if (topAnnotations && topAnnotations.length > 0) for (const an of topAnnotations) {
|
|
1390
|
+
const { value, multiple } = this.computeAnnotationValue(node, an);
|
|
1391
|
+
if (multiple) {
|
|
1392
|
+
this.writeln(`{`);
|
|
1393
|
+
this.indent();
|
|
1394
|
+
this.writeln(`const __t = ${targetName}.metadata`);
|
|
1395
|
+
this.writeln(`const __k = "${escapeQuotes(an.name)}"`);
|
|
1396
|
+
this.writeln(`const __v = ${value}`);
|
|
1397
|
+
this.writeln(`if (__t) { const __e = __t.get(__k); __t.set(__k, Array.isArray(__e) ? [...__e, __v] : __e !== undefined ? [__e, __v] : [__v]) }`);
|
|
1398
|
+
this.unindent();
|
|
1399
|
+
this.writeln(`}`);
|
|
1400
|
+
} else this.writeln(`${targetName}.metadata.set("${escapeQuotes(an.name)}", ${value})`);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1273
1403
|
}
|
|
1274
1404
|
constructor(doc, opts) {
|
|
1275
|
-
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1405
|
+
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
1406
|
}
|
|
1277
1407
|
};
|
|
1278
1408
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
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.0
|
|
73
|
+
"@atscript/core": "^0.1.0"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@moostjs/event-cli": "^0.5.32",
|