@atscript/typescript 0.0.27 → 0.0.29
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 +712 -33
- package/dist/index.cjs +599 -369
- package/dist/index.d.ts +11 -2
- package/dist/index.mjs +599 -370
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -27,7 +27,7 @@ const __atscript_core = __toESM(require("@atscript/core"));
|
|
|
27
27
|
const path = __toESM(require("path"));
|
|
28
28
|
|
|
29
29
|
//#region packages/typescript/src/codegen/code-printer.ts
|
|
30
|
-
function _define_property$
|
|
30
|
+
function _define_property$4(obj, key, value) {
|
|
31
31
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
32
32
|
value,
|
|
33
33
|
enumerable: true,
|
|
@@ -120,17 +120,17 @@ else this.write(closing);
|
|
|
120
120
|
return " ".repeat(this.indentLevel * this.indentSize);
|
|
121
121
|
}
|
|
122
122
|
constructor() {
|
|
123
|
-
_define_property$
|
|
124
|
-
_define_property$
|
|
125
|
-
_define_property$
|
|
126
|
-
_define_property$
|
|
127
|
-
_define_property$
|
|
123
|
+
_define_property$4(this, "lines", []);
|
|
124
|
+
_define_property$4(this, "currentLine", "");
|
|
125
|
+
_define_property$4(this, "indentLevel", 0);
|
|
126
|
+
_define_property$4(this, "indentSize", 2);
|
|
127
|
+
_define_property$4(this, "blockStack", []);
|
|
128
128
|
}
|
|
129
129
|
};
|
|
130
130
|
|
|
131
131
|
//#endregion
|
|
132
132
|
//#region packages/typescript/src/codegen/base-renderer.ts
|
|
133
|
-
function _define_property$
|
|
133
|
+
function _define_property$3(obj, key, value) {
|
|
134
134
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
135
135
|
value,
|
|
136
136
|
enumerable: true,
|
|
@@ -152,7 +152,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
152
152
|
renderInterface(node) {}
|
|
153
153
|
renderType(node) {}
|
|
154
154
|
transformFromPath(path$2) {
|
|
155
|
-
return path$2
|
|
155
|
+
return `${path$2}.as`;
|
|
156
156
|
}
|
|
157
157
|
renderImport(node) {
|
|
158
158
|
const def = node.getDefinition();
|
|
@@ -189,7 +189,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
constructor(doc) {
|
|
192
|
-
super(), _define_property$
|
|
192
|
+
super(), _define_property$3(this, "doc", void 0), _define_property$3(this, "unused", void 0), this.doc = doc;
|
|
193
193
|
this.unused = new Set(this.doc.getUnusedTokens().map((t) => t.text));
|
|
194
194
|
}
|
|
195
195
|
};
|
|
@@ -207,7 +207,17 @@ function escapeQuotes(str) {
|
|
|
207
207
|
|
|
208
208
|
//#endregion
|
|
209
209
|
//#region packages/typescript/src/codegen/type-renderer.ts
|
|
210
|
-
|
|
210
|
+
function _define_property$2(obj, key, value) {
|
|
211
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
212
|
+
value,
|
|
213
|
+
enumerable: true,
|
|
214
|
+
configurable: true,
|
|
215
|
+
writable: true
|
|
216
|
+
});
|
|
217
|
+
else obj[key] = value;
|
|
218
|
+
return obj;
|
|
219
|
+
}
|
|
220
|
+
var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
211
221
|
pre() {
|
|
212
222
|
this.writeln("// prettier-ignore-start");
|
|
213
223
|
this.writeln("/* eslint-disable */");
|
|
@@ -222,6 +232,11 @@ var TypeRenderer = class extends BaseRenderer {
|
|
|
222
232
|
post() {
|
|
223
233
|
this.writeln("// prettier-ignore-end");
|
|
224
234
|
}
|
|
235
|
+
renderTypeDefString(def) {
|
|
236
|
+
const newThis = new TypeRenderer(this.doc, this.opts);
|
|
237
|
+
newThis.renderTypeDef(def);
|
|
238
|
+
return newThis.toString();
|
|
239
|
+
}
|
|
225
240
|
renderTypeDef(def) {
|
|
226
241
|
if (!def) {
|
|
227
242
|
this.write("unknown");
|
|
@@ -270,33 +285,33 @@ var TypeRenderer = class extends BaseRenderer {
|
|
|
270
285
|
renderStructure(struct, asClass) {
|
|
271
286
|
this.blockln("{}");
|
|
272
287
|
const patterns = [];
|
|
273
|
-
|
|
288
|
+
const propsDefs = new Set();
|
|
274
289
|
for (const prop of Array.from(struct.props.values())) {
|
|
275
290
|
if (prop.token("identifier")?.pattern) {
|
|
276
291
|
patterns.push(prop);
|
|
277
292
|
continue;
|
|
278
293
|
}
|
|
279
|
-
hasProp = true;
|
|
280
294
|
const optional = !!prop.token("optional");
|
|
281
295
|
this.write(wrapProp(prop.id), optional ? "?" : "", ": ");
|
|
282
|
-
this.
|
|
283
|
-
|
|
296
|
+
const renderedDef = this.renderTypeDefString(prop.getDefinition());
|
|
297
|
+
propsDefs.add(renderedDef);
|
|
298
|
+
renderedDef.split("\n").forEach((l) => this.writeln(l));
|
|
284
299
|
}
|
|
285
300
|
if (patterns.length) {
|
|
286
301
|
this.write(`[key: string]: `);
|
|
287
|
-
if (
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
302
|
+
if (patterns.length > 0) {
|
|
303
|
+
for (const prop of patterns) propsDefs.add(this.renderTypeDefString(prop.getDefinition()));
|
|
304
|
+
const defs = Array.from(propsDefs);
|
|
305
|
+
if (defs.length > 1) {
|
|
306
|
+
this.indent();
|
|
307
|
+
for (const def of defs) {
|
|
308
|
+
this.writeln();
|
|
309
|
+
this.write("| ");
|
|
310
|
+
def.split("\n").forEach((l) => this.write(l.trim()));
|
|
311
|
+
}
|
|
312
|
+
this.unindent();
|
|
294
313
|
this.writeln();
|
|
295
|
-
|
|
296
|
-
this.renderTypeDef(prop.getDefinition());
|
|
297
|
-
}
|
|
298
|
-
this.unindent();
|
|
299
|
-
this.writeln();
|
|
314
|
+
} else defs[0].split("\n").forEach((l) => this.writeln(l));
|
|
300
315
|
}
|
|
301
316
|
}
|
|
302
317
|
if (asClass) {
|
|
@@ -304,6 +319,7 @@ else if (patterns.length === 1) {
|
|
|
304
319
|
this.writeln(`static type: TAtscriptTypeObject<keyof ${asClass}>`);
|
|
305
320
|
this.writeln(`static metadata: TMetadataMap<AtscriptMetadata>`);
|
|
306
321
|
this.writeln(`static validator: <TT extends TAtscriptAnnotatedTypeConstructor = ${asClass}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
|
|
322
|
+
this.writeln("static toJsonSchema: () => any");
|
|
307
323
|
}
|
|
308
324
|
this.pop();
|
|
309
325
|
}
|
|
@@ -346,6 +362,7 @@ else if ((0, __atscript_core.isPrimitive)(realDef)) typeDef = "TAtscriptTypeFina
|
|
|
346
362
|
this.writeln(`const type: ${typeDef}`);
|
|
347
363
|
this.writeln(`const metadata: TMetadataMap<AtscriptMetadata>`);
|
|
348
364
|
this.writeln(`const validator: <TT extends TAtscriptAnnotatedTypeConstructor = ${node.id}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
|
|
365
|
+
this.writeln("const toJsonSchema: () => any");
|
|
349
366
|
this.popln();
|
|
350
367
|
}
|
|
351
368
|
renderJsDoc(node) {
|
|
@@ -356,6 +373,9 @@ else if ((0, __atscript_core.isPrimitive)(realDef)) typeDef = "TAtscriptTypeFina
|
|
|
356
373
|
this.writeln(` * @see {@link ./${this.doc.name}${rangeStr}}`);
|
|
357
374
|
this.writeln(` */`);
|
|
358
375
|
}
|
|
376
|
+
constructor(doc, opts) {
|
|
377
|
+
super(doc), _define_property$2(this, "opts", void 0), this.opts = opts;
|
|
378
|
+
}
|
|
359
379
|
};
|
|
360
380
|
function renderPrimitiveTypeDef(def) {
|
|
361
381
|
if (!def) return "unknown";
|
|
@@ -375,7 +395,7 @@ function renderPrimitiveTypeDef(def) {
|
|
|
375
395
|
}
|
|
376
396
|
|
|
377
397
|
//#endregion
|
|
378
|
-
//#region packages/typescript/src/
|
|
398
|
+
//#region packages/typescript/src/validator.ts
|
|
379
399
|
function _define_property$1(obj, key, value) {
|
|
380
400
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
381
401
|
value,
|
|
@@ -386,352 +406,64 @@ function _define_property$1(obj, key, value) {
|
|
|
386
406
|
else obj[key] = value;
|
|
387
407
|
return obj;
|
|
388
408
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
this.
|
|
393
|
-
this.
|
|
394
|
-
}
|
|
395
|
-
post() {
|
|
396
|
-
for (const node of this.postAnnotate) {
|
|
397
|
-
this.annotateType(node.getDefinition(), node.id);
|
|
398
|
-
this.indent().defineMetadata(node).unindent();
|
|
399
|
-
this.writeln();
|
|
400
|
-
}
|
|
401
|
-
this.writeln("// prettier-ignore-end");
|
|
402
|
-
super.post();
|
|
409
|
+
const regexCache = new Map();
|
|
410
|
+
var Validator = class {
|
|
411
|
+
isLimitExceeded() {
|
|
412
|
+
if (this.stackErrors.length > 0) return this.stackErrors[this.stackErrors.length - 1].length >= this.opts.errorLimit;
|
|
413
|
+
return this.errors.length >= this.opts.errorLimit;
|
|
403
414
|
}
|
|
404
|
-
|
|
405
|
-
this.
|
|
406
|
-
|
|
407
|
-
this.write(exported ? "export " : "");
|
|
408
|
-
this.write(`class ${node.id} `);
|
|
409
|
-
this.blockln("{}");
|
|
410
|
-
this.writeln("static __is_atscript_annotated_type = true");
|
|
411
|
-
this.writeln("static type = {}");
|
|
412
|
-
this.writeln("static metadata = new Map()");
|
|
413
|
-
this.popln();
|
|
414
|
-
this.postAnnotate.push(node);
|
|
415
|
-
this.writeln();
|
|
415
|
+
push(name) {
|
|
416
|
+
this.stackPath.push(name);
|
|
417
|
+
this.stackErrors.push([]);
|
|
416
418
|
}
|
|
417
|
-
|
|
418
|
-
this.
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
this.writeln("static type = {}");
|
|
425
|
-
this.writeln("static metadata = new Map()");
|
|
426
|
-
this.popln();
|
|
427
|
-
this.postAnnotate.push(node);
|
|
428
|
-
this.writeln();
|
|
419
|
+
pop(saveErrors) {
|
|
420
|
+
this.stackPath.pop();
|
|
421
|
+
const popped = this.stackErrors.pop();
|
|
422
|
+
if (saveErrors && popped?.length) popped.forEach((error) => {
|
|
423
|
+
this.error(error.message, error.path, error.details);
|
|
424
|
+
});
|
|
425
|
+
return popped;
|
|
429
426
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const node = this.doc.mergeIntersection(_node);
|
|
433
|
-
let kind = node.entity;
|
|
434
|
-
switch (node.entity) {
|
|
435
|
-
case "ref": {
|
|
436
|
-
const ref = node;
|
|
437
|
-
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
438
|
-
if ((0, __atscript_core.isPrimitive)(decl)) {
|
|
439
|
-
this.annotateType(decl, name);
|
|
440
|
-
return this;
|
|
441
|
-
}
|
|
442
|
-
const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
|
|
443
|
-
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`).unindent();
|
|
444
|
-
return this;
|
|
445
|
-
}
|
|
446
|
-
case "primitive": {
|
|
447
|
-
this.definePrimitive(node, name);
|
|
448
|
-
return this;
|
|
449
|
-
}
|
|
450
|
-
case "const": {
|
|
451
|
-
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().defineConst(node).unindent();
|
|
452
|
-
return this;
|
|
453
|
-
}
|
|
454
|
-
case "structure": {
|
|
455
|
-
this.writeln(`$("object"${name ? `, ${name}` : ""})`).indent().defineObject(node).unindent();
|
|
456
|
-
return this;
|
|
457
|
-
}
|
|
458
|
-
case "group": {
|
|
459
|
-
kind = node.op === "|" ? "union" : "intersection";
|
|
460
|
-
this.writeln(`$("${kind}"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
461
|
-
return this;
|
|
462
|
-
}
|
|
463
|
-
case "tuple": {
|
|
464
|
-
this.writeln(`$("tuple"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
465
|
-
return this;
|
|
466
|
-
}
|
|
467
|
-
case "array": {
|
|
468
|
-
this.writeln(`$("array"${name ? `, ${name}` : ""})`).indent().defineArray(node).unindent();
|
|
469
|
-
return this;
|
|
470
|
-
}
|
|
471
|
-
default: {
|
|
472
|
-
console.log("!!!!!!! UNKNOWN ", node.entity);
|
|
473
|
-
return this;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
427
|
+
clear() {
|
|
428
|
+
this.stackErrors[this.stackErrors.length - 1] = [];
|
|
476
429
|
}
|
|
477
|
-
|
|
478
|
-
const
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
430
|
+
error(message, path$2, details) {
|
|
431
|
+
const errors = this.stackErrors[this.stackErrors.length - 1] || this.errors;
|
|
432
|
+
const error = {
|
|
433
|
+
path: path$2 || this.path,
|
|
434
|
+
message
|
|
435
|
+
};
|
|
436
|
+
if (details?.length) error.details = details;
|
|
437
|
+
errors.push(error);
|
|
484
438
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
this.writeln(` .tags(${Array.from(node.tags).map((f) => `"${escapeQuotes(f)}"`).join(", ")})`);
|
|
488
|
-
return this;
|
|
439
|
+
throw() {
|
|
440
|
+
throw new ValidatorError(this.errors);
|
|
489
441
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
this.writeln(`$(${d(def.kind)})`);
|
|
500
|
-
this.indent();
|
|
501
|
-
for (const itemDef of def.items) {
|
|
502
|
-
this.write(`.item(`);
|
|
503
|
-
this.indent();
|
|
504
|
-
this.renderPrimitiveDef(itemDef);
|
|
505
|
-
this.writeln(".$type");
|
|
506
|
-
this.unindent();
|
|
507
|
-
this.write(`)`);
|
|
508
|
-
}
|
|
509
|
-
this.unindent();
|
|
510
|
-
return;
|
|
511
|
-
case "array":
|
|
512
|
-
this.writeln(`$(${d("array")})`);
|
|
513
|
-
this.indent();
|
|
514
|
-
this.write(".of(");
|
|
515
|
-
this.indent();
|
|
516
|
-
this.renderPrimitiveDef(def.of);
|
|
517
|
-
this.writeln(`.$type`);
|
|
518
|
-
this.unindent();
|
|
519
|
-
this.writeln(`)`);
|
|
520
|
-
this.unindent();
|
|
521
|
-
return;
|
|
522
|
-
case "object":
|
|
523
|
-
this.writeln(`$(${d("object")})`);
|
|
524
|
-
this.indent();
|
|
525
|
-
for (const [key, propDef] of Object.entries(def.props)) {
|
|
526
|
-
const optional = typeof propDef === "object" && propDef.optional;
|
|
527
|
-
this.writeln(`.prop(`);
|
|
528
|
-
this.indent();
|
|
529
|
-
this.writeln(`"${escapeQuotes(key)}",`);
|
|
530
|
-
this.renderPrimitiveDef(propDef);
|
|
531
|
-
if (optional) this.writeln(".optional()");
|
|
532
|
-
this.writeln(".$type");
|
|
533
|
-
this.unindent();
|
|
534
|
-
this.write(`)`);
|
|
535
|
-
}
|
|
536
|
-
for (const [key, propDef] of Object.entries(def.propsPatterns)) {
|
|
537
|
-
const optional = typeof propDef === "object" && propDef.optional;
|
|
538
|
-
this.writeln(`.propPattern(`);
|
|
539
|
-
this.indent();
|
|
540
|
-
this.writeln(`${key},`);
|
|
541
|
-
this.renderPrimitiveDef(propDef);
|
|
542
|
-
if (optional) this.writeln(".optional()");
|
|
543
|
-
this.writeln(".$type");
|
|
544
|
-
this.unindent();
|
|
545
|
-
this.write(`)`);
|
|
546
|
-
}
|
|
547
|
-
this.unindent();
|
|
548
|
-
return;
|
|
549
|
-
default: return this.writeln(`$(${d()}).designType("any")`);
|
|
442
|
+
validate(value, safe) {
|
|
443
|
+
this.push("");
|
|
444
|
+
this.errors = [];
|
|
445
|
+
this.stackErrors = [];
|
|
446
|
+
const passed = this.validateSafe(this.def, value);
|
|
447
|
+
this.pop(!passed);
|
|
448
|
+
if (!passed) {
|
|
449
|
+
if (safe) return false;
|
|
450
|
+
this.throw();
|
|
550
451
|
}
|
|
452
|
+
return true;
|
|
551
453
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
this.writeln(`/${pattern.source}/${pattern.flags},`);
|
|
561
|
-
} else {
|
|
562
|
-
this.writeln(`.prop(`);
|
|
563
|
-
this.indent();
|
|
564
|
-
this.writeln(`"${escapeQuotes(prop.id)}",`);
|
|
565
|
-
}
|
|
566
|
-
this.annotateType(prop.getDefinition());
|
|
567
|
-
this.indent().defineMetadata(prop).unindent();
|
|
568
|
-
if (optional) this.writeln(" .optional()");
|
|
569
|
-
this.writeln(" .$type");
|
|
570
|
-
this.unindent();
|
|
571
|
-
this.write(`)`);
|
|
454
|
+
validateSafe(def, value) {
|
|
455
|
+
if (this.isLimitExceeded()) return false;
|
|
456
|
+
if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
|
|
457
|
+
if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.path);
|
|
458
|
+
if (def.optional && value === undefined) return true;
|
|
459
|
+
for (const plugin of this.opts.plugins) {
|
|
460
|
+
const result = plugin(this, def, value);
|
|
461
|
+
if (result === false || result === true) return result;
|
|
572
462
|
}
|
|
573
|
-
this.
|
|
574
|
-
return this;
|
|
575
|
-
}
|
|
576
|
-
defineGroup(node) {
|
|
577
|
-
const items = node.unwrap();
|
|
578
|
-
for (const item of items) this.write(".item(").indent().annotateType(item).write(" .$type").writeln(`)`).unindent();
|
|
579
|
-
return this;
|
|
463
|
+
return this.validateAnnotatedType(def, value);
|
|
580
464
|
}
|
|
581
|
-
|
|
582
|
-
this.
|
|
583
|
-
return this;
|
|
584
|
-
}
|
|
585
|
-
defineMetadata(node) {
|
|
586
|
-
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
587
|
-
annotations?.forEach((an) => {
|
|
588
|
-
this.resolveAnnotationValue(node, an);
|
|
589
|
-
});
|
|
590
|
-
return this;
|
|
591
|
-
}
|
|
592
|
-
resolveAnnotationValue(node, an) {
|
|
593
|
-
const spec = this.doc.resolveAnnotation(an.name);
|
|
594
|
-
let targetValue = "true";
|
|
595
|
-
let multiple = false;
|
|
596
|
-
if (spec) {
|
|
597
|
-
multiple = spec.config.multiple;
|
|
598
|
-
const length = spec.arguments.length;
|
|
599
|
-
if (length !== 0) if (Array.isArray(spec.config.argument)) {
|
|
600
|
-
targetValue = "{ ";
|
|
601
|
-
let i = 0;
|
|
602
|
-
for (const aSpec of spec.arguments) {
|
|
603
|
-
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
604
|
-
else {}
|
|
605
|
-
i++;
|
|
606
|
-
}
|
|
607
|
-
targetValue += "}";
|
|
608
|
-
} else {
|
|
609
|
-
const aSpec = spec.arguments[0];
|
|
610
|
-
if (an.args[0]) targetValue = aSpec.type === "string" ? `"${escapeQuotes(an.args[0]?.text)}"` : an.args[0]?.text;
|
|
611
|
-
else targetValue = "true";
|
|
612
|
-
}
|
|
613
|
-
} else {
|
|
614
|
-
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
615
|
-
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
616
|
-
}
|
|
617
|
-
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue}, true)`);
|
|
618
|
-
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue})`);
|
|
619
|
-
}
|
|
620
|
-
constructor(...args) {
|
|
621
|
-
super(...args), _define_property$1(this, "postAnnotate", []);
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
//#endregion
|
|
626
|
-
//#region packages/typescript/src/plugin.ts
|
|
627
|
-
const tsPlugin = () => {
|
|
628
|
-
return {
|
|
629
|
-
name: "typesccript",
|
|
630
|
-
render(doc, format) {
|
|
631
|
-
if (format === "dts") return [{
|
|
632
|
-
fileName: `${doc.name}.d.ts`,
|
|
633
|
-
content: new TypeRenderer(doc).render()
|
|
634
|
-
}];
|
|
635
|
-
if (format === "js") return [{
|
|
636
|
-
fileName: `${doc.name}.js`,
|
|
637
|
-
content: new JsRenderer(doc).render()
|
|
638
|
-
}];
|
|
639
|
-
},
|
|
640
|
-
async buildEnd(output, format, repo) {
|
|
641
|
-
if (format === "dts") {
|
|
642
|
-
const annotations = await repo.getUsedAnnotations();
|
|
643
|
-
const tags = await repo.getPrimitivesTags() || new Set();
|
|
644
|
-
let rendered = [];
|
|
645
|
-
for (const [key, val] of Object.entries(annotations)) {
|
|
646
|
-
const multiple = val.multiple;
|
|
647
|
-
let typeLine = Array.from(val.types).map((t) => {
|
|
648
|
-
if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
|
|
649
|
-
else return t.optional ? `${t.type} | true` : t.type;
|
|
650
|
-
}).join(" | ");
|
|
651
|
-
rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
|
|
652
|
-
}
|
|
653
|
-
let renderedTags = Array.from(tags).map((f) => `"${escapeQuotes(f)}"`).join(" | ");
|
|
654
|
-
output.push({
|
|
655
|
-
content: "// prettier-ignore-start\n/* eslint-disable */\n/**\n * 🪄 This file was generated by Atscript\n * It is generated based on annotations used in this project\n * Do not edit this file!\n *\n * Use `npx asc -f dts` command to re-generate this file\n */\nexport {}\n\ndeclare global {\n interface AtscriptMetadata {\n " + rendered.join("\n ") + "\n }\n" + " type AtscriptPrimitiveTags = " + renderedTags + "\n" + "}\n" + "// prettier-ignore-end",
|
|
656
|
-
fileName: "atscript.d.ts",
|
|
657
|
-
source: "",
|
|
658
|
-
target: path.default.join(repo.root, "atscript.d.ts")
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
|
-
};
|
|
664
|
-
|
|
665
|
-
//#endregion
|
|
666
|
-
//#region packages/typescript/src/validator.ts
|
|
667
|
-
function _define_property(obj, key, value) {
|
|
668
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
669
|
-
value,
|
|
670
|
-
enumerable: true,
|
|
671
|
-
configurable: true,
|
|
672
|
-
writable: true
|
|
673
|
-
});
|
|
674
|
-
else obj[key] = value;
|
|
675
|
-
return obj;
|
|
676
|
-
}
|
|
677
|
-
const regexCache = new Map();
|
|
678
|
-
var Validator = class {
|
|
679
|
-
isLimitExceeded() {
|
|
680
|
-
if (this.stackErrors.length > 0) return this.stackErrors[this.stackErrors.length - 1].length >= this.opts.errorLimit;
|
|
681
|
-
return this.errors.length >= this.opts.errorLimit;
|
|
682
|
-
}
|
|
683
|
-
push(name) {
|
|
684
|
-
this.stackPath.push(name);
|
|
685
|
-
this.stackErrors.push([]);
|
|
686
|
-
}
|
|
687
|
-
pop(saveErrors) {
|
|
688
|
-
this.stackPath.pop();
|
|
689
|
-
const popped = this.stackErrors.pop();
|
|
690
|
-
if (saveErrors && popped?.length) popped.forEach((error) => {
|
|
691
|
-
this.error(error.message, error.path, error.details);
|
|
692
|
-
});
|
|
693
|
-
return popped;
|
|
694
|
-
}
|
|
695
|
-
clear() {
|
|
696
|
-
this.stackErrors[this.stackErrors.length - 1] = [];
|
|
697
|
-
}
|
|
698
|
-
error(message, path$2, details) {
|
|
699
|
-
const errors = this.stackErrors[this.stackErrors.length - 1] || this.errors;
|
|
700
|
-
const error = {
|
|
701
|
-
path: path$2 || this.path,
|
|
702
|
-
message
|
|
703
|
-
};
|
|
704
|
-
if (details?.length) error.details = details;
|
|
705
|
-
errors.push(error);
|
|
706
|
-
}
|
|
707
|
-
throw() {
|
|
708
|
-
throw new ValidatorError(this.errors);
|
|
709
|
-
}
|
|
710
|
-
validate(value, safe) {
|
|
711
|
-
this.push("");
|
|
712
|
-
this.errors = [];
|
|
713
|
-
this.stackErrors = [];
|
|
714
|
-
const passed = this.validateSafe(this.def, value);
|
|
715
|
-
this.pop(!passed);
|
|
716
|
-
if (!passed) {
|
|
717
|
-
if (safe) return false;
|
|
718
|
-
this.throw();
|
|
719
|
-
}
|
|
720
|
-
return true;
|
|
721
|
-
}
|
|
722
|
-
validateSafe(def, value) {
|
|
723
|
-
if (this.isLimitExceeded()) return false;
|
|
724
|
-
if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
|
|
725
|
-
if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.path);
|
|
726
|
-
if (def.optional && value === undefined) return true;
|
|
727
|
-
for (const plugin of this.opts.plugins) {
|
|
728
|
-
const result = plugin(this, def, value);
|
|
729
|
-
if (result === false || result === true) return result;
|
|
730
|
-
}
|
|
731
|
-
return this.validateAnnotatedType(def, value);
|
|
732
|
-
}
|
|
733
|
-
get path() {
|
|
734
|
-
return this.stackPath.slice(1).join(".");
|
|
465
|
+
get path() {
|
|
466
|
+
return this.stackPath.slice(1).join(".");
|
|
735
467
|
}
|
|
736
468
|
validateAnnotatedType(def, value) {
|
|
737
469
|
switch (def.type.kind) {
|
|
@@ -972,11 +704,11 @@ else {
|
|
|
972
704
|
return true;
|
|
973
705
|
}
|
|
974
706
|
constructor(def, opts) {
|
|
975
|
-
_define_property(this, "def", void 0);
|
|
976
|
-
_define_property(this, "opts", void 0);
|
|
977
|
-
_define_property(this, "errors", void 0);
|
|
978
|
-
_define_property(this, "stackErrors", void 0);
|
|
979
|
-
_define_property(this, "stackPath", void 0);
|
|
707
|
+
_define_property$1(this, "def", void 0);
|
|
708
|
+
_define_property$1(this, "opts", void 0);
|
|
709
|
+
_define_property$1(this, "errors", void 0);
|
|
710
|
+
_define_property$1(this, "stackErrors", void 0);
|
|
711
|
+
_define_property$1(this, "stackPath", void 0);
|
|
980
712
|
this.def = def;
|
|
981
713
|
this.errors = [];
|
|
982
714
|
this.stackErrors = [];
|
|
@@ -992,7 +724,7 @@ else {
|
|
|
992
724
|
};
|
|
993
725
|
var ValidatorError = class extends Error {
|
|
994
726
|
constructor(errors) {
|
|
995
|
-
super(`${errors[0].path ? errors[0].path + ": " : ""}${errors[0].message}`), _define_property(this, "errors", void 0), _define_property(this, "name", void 0), this.errors = errors, this.name = "Validation Error";
|
|
727
|
+
super(`${errors[0].path ? errors[0].path + ": " : ""}${errors[0].message}`), _define_property$1(this, "errors", void 0), _define_property$1(this, "name", void 0), this.errors = errors, this.name = "Validation Error";
|
|
996
728
|
}
|
|
997
729
|
};
|
|
998
730
|
|
|
@@ -1125,6 +857,503 @@ function isAnnotatedTypeOfPrimitive(t) {
|
|
|
1125
857
|
return false;
|
|
1126
858
|
}
|
|
1127
859
|
|
|
860
|
+
//#endregion
|
|
861
|
+
//#region packages/typescript/src/json-schema.ts
|
|
862
|
+
function buildJsonSchema(type) {
|
|
863
|
+
const build = (def) => {
|
|
864
|
+
const t = def.type;
|
|
865
|
+
const meta = def.metadata;
|
|
866
|
+
switch (t.kind) {
|
|
867
|
+
case "object": {
|
|
868
|
+
const obj = t;
|
|
869
|
+
const properties = {};
|
|
870
|
+
const required = [];
|
|
871
|
+
for (const [key, val] of obj.props.entries()) {
|
|
872
|
+
properties[key] = build(val);
|
|
873
|
+
if (!val.optional) required.push(key);
|
|
874
|
+
}
|
|
875
|
+
const schema = {
|
|
876
|
+
type: "object",
|
|
877
|
+
properties
|
|
878
|
+
};
|
|
879
|
+
if (required.length) schema.required = required;
|
|
880
|
+
return schema;
|
|
881
|
+
}
|
|
882
|
+
case "array": {
|
|
883
|
+
const arr = t;
|
|
884
|
+
const schema = {
|
|
885
|
+
type: "array",
|
|
886
|
+
items: build(arr.of)
|
|
887
|
+
};
|
|
888
|
+
const minLength = meta.get("expect.minLength");
|
|
889
|
+
if (typeof minLength === "number") schema.minItems = minLength;
|
|
890
|
+
const maxLength = meta.get("expect.maxLength");
|
|
891
|
+
if (typeof maxLength === "number") schema.maxItems = maxLength;
|
|
892
|
+
return schema;
|
|
893
|
+
}
|
|
894
|
+
case "union": {
|
|
895
|
+
const grp = t;
|
|
896
|
+
return { anyOf: grp.items.map(build) };
|
|
897
|
+
}
|
|
898
|
+
case "intersection": {
|
|
899
|
+
const grp = t;
|
|
900
|
+
return { allOf: grp.items.map(build) };
|
|
901
|
+
}
|
|
902
|
+
case "tuple": {
|
|
903
|
+
const grp = t;
|
|
904
|
+
return {
|
|
905
|
+
type: "array",
|
|
906
|
+
items: grp.items.map(build),
|
|
907
|
+
additionalItems: false
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
case "": {
|
|
911
|
+
const fin = t;
|
|
912
|
+
const schema = {};
|
|
913
|
+
if (fin.value !== undefined) schema.const = fin.value;
|
|
914
|
+
if (fin.designType && fin.designType !== "any") {
|
|
915
|
+
schema.type = fin.designType === "undefined" ? "null" : fin.designType;
|
|
916
|
+
if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
|
|
917
|
+
}
|
|
918
|
+
if (schema.type === "string") {
|
|
919
|
+
const minLength = meta.get("expect.minLength");
|
|
920
|
+
if (typeof minLength === "number") schema.minLength = minLength;
|
|
921
|
+
const maxLength = meta.get("expect.maxLength");
|
|
922
|
+
if (typeof maxLength === "number") schema.maxLength = maxLength;
|
|
923
|
+
const patterns = meta.get("expect.pattern");
|
|
924
|
+
if (patterns?.length) if (patterns.length === 1) schema.pattern = patterns[0].pattern;
|
|
925
|
+
else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
|
|
926
|
+
}
|
|
927
|
+
if (schema.type === "number" || schema.type === "integer") {
|
|
928
|
+
const min = meta.get("expect.min");
|
|
929
|
+
if (typeof min === "number") schema.minimum = min;
|
|
930
|
+
const max = meta.get("expect.max");
|
|
931
|
+
if (typeof max === "number") schema.maximum = max;
|
|
932
|
+
}
|
|
933
|
+
return schema;
|
|
934
|
+
}
|
|
935
|
+
default: return {};
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
return build(type);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
//#endregion
|
|
942
|
+
//#region packages/typescript/src/codegen/js-renderer.ts
|
|
943
|
+
function _define_property(obj, key, value) {
|
|
944
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
945
|
+
value,
|
|
946
|
+
enumerable: true,
|
|
947
|
+
configurable: true,
|
|
948
|
+
writable: true
|
|
949
|
+
});
|
|
950
|
+
else obj[key] = value;
|
|
951
|
+
return obj;
|
|
952
|
+
}
|
|
953
|
+
var JsRenderer = class extends BaseRenderer {
|
|
954
|
+
pre() {
|
|
955
|
+
this.writeln("// prettier-ignore-start");
|
|
956
|
+
this.writeln("/* eslint-disable */");
|
|
957
|
+
const imports = ["defineAnnotatedType as $"];
|
|
958
|
+
if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
|
|
959
|
+
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript"`);
|
|
960
|
+
}
|
|
961
|
+
post() {
|
|
962
|
+
for (const node of this.postAnnotate) {
|
|
963
|
+
this.annotateType(node.getDefinition(), node.id);
|
|
964
|
+
this.indent().defineMetadata(node).unindent();
|
|
965
|
+
this.writeln();
|
|
966
|
+
}
|
|
967
|
+
this.writeln("// prettier-ignore-end");
|
|
968
|
+
super.post();
|
|
969
|
+
}
|
|
970
|
+
renderInterface(node) {
|
|
971
|
+
this.writeln();
|
|
972
|
+
const exported = node.token("export")?.text === "export";
|
|
973
|
+
this.write(exported ? "export " : "");
|
|
974
|
+
this.write(`class ${node.id} `);
|
|
975
|
+
this.blockln("{}");
|
|
976
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
977
|
+
this.writeln("static type = {}");
|
|
978
|
+
this.writeln("static metadata = new Map()");
|
|
979
|
+
if (this.opts?.preRenderJsonSchema) {
|
|
980
|
+
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
981
|
+
this.writeln(`static _jsonSchema = ${schema}`);
|
|
982
|
+
this.writeln("static toJsonSchema() {");
|
|
983
|
+
this.indent().writeln("return this._jsonSchema").unindent();
|
|
984
|
+
this.writeln("}");
|
|
985
|
+
} else {
|
|
986
|
+
this.writeln("static _jsonSchema");
|
|
987
|
+
this.writeln("static toJsonSchema() {");
|
|
988
|
+
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
989
|
+
this.writeln("}");
|
|
990
|
+
}
|
|
991
|
+
this.popln();
|
|
992
|
+
this.postAnnotate.push(node);
|
|
993
|
+
this.writeln();
|
|
994
|
+
}
|
|
995
|
+
renderType(node) {
|
|
996
|
+
this.writeln();
|
|
997
|
+
const exported = node.token("export")?.text === "export";
|
|
998
|
+
this.write(exported ? "export " : "");
|
|
999
|
+
this.write(`class ${node.id} `);
|
|
1000
|
+
this.blockln("{}");
|
|
1001
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
1002
|
+
this.writeln("static type = {}");
|
|
1003
|
+
this.writeln("static metadata = new Map()");
|
|
1004
|
+
if (this.opts?.jsonSchema) if (typeof this.opts.jsonSchema === "object" && this.opts.jsonSchema.preRender) {
|
|
1005
|
+
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
1006
|
+
this.writeln(`static _jsonSchema = ${schema}`);
|
|
1007
|
+
this.writeln("static toJsonSchema() {");
|
|
1008
|
+
this.indent().writeln("return this._jsonSchema").unindent();
|
|
1009
|
+
this.writeln("}");
|
|
1010
|
+
} else {
|
|
1011
|
+
this.writeln("static _jsonSchema");
|
|
1012
|
+
this.writeln("static toJsonSchema() {");
|
|
1013
|
+
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
1014
|
+
this.writeln("}");
|
|
1015
|
+
}
|
|
1016
|
+
this.popln();
|
|
1017
|
+
this.postAnnotate.push(node);
|
|
1018
|
+
this.writeln();
|
|
1019
|
+
}
|
|
1020
|
+
toAnnotatedType(node) {
|
|
1021
|
+
return this.toAnnotatedHandle(node).$type;
|
|
1022
|
+
}
|
|
1023
|
+
toAnnotatedHandle(node, skipAnnotations = false) {
|
|
1024
|
+
if (!node) return defineAnnotatedType();
|
|
1025
|
+
switch (node.entity) {
|
|
1026
|
+
case "interface":
|
|
1027
|
+
case "type": {
|
|
1028
|
+
const def = node.getDefinition();
|
|
1029
|
+
const handle = this.toAnnotatedHandle(def, true);
|
|
1030
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1031
|
+
}
|
|
1032
|
+
case "prop": {
|
|
1033
|
+
const prop = node;
|
|
1034
|
+
const def = prop.getDefinition();
|
|
1035
|
+
const handle = this.toAnnotatedHandle(def, true);
|
|
1036
|
+
if (!skipAnnotations) {
|
|
1037
|
+
this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(prop));
|
|
1038
|
+
if (prop.token("optional")) handle.optional();
|
|
1039
|
+
}
|
|
1040
|
+
return handle;
|
|
1041
|
+
}
|
|
1042
|
+
case "ref": {
|
|
1043
|
+
const ref = node;
|
|
1044
|
+
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1045
|
+
const handle = this.toAnnotatedHandle(decl, true);
|
|
1046
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1047
|
+
}
|
|
1048
|
+
case "primitive": {
|
|
1049
|
+
const prim = node;
|
|
1050
|
+
const handle = defineAnnotatedType();
|
|
1051
|
+
handle.designType(prim.id === "never" ? "never" : prim.config.type);
|
|
1052
|
+
if (!skipAnnotations) this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1053
|
+
return handle;
|
|
1054
|
+
}
|
|
1055
|
+
case "const": {
|
|
1056
|
+
const c = node;
|
|
1057
|
+
const handle = defineAnnotatedType();
|
|
1058
|
+
const t = c.token("identifier")?.type;
|
|
1059
|
+
handle.designType(t === "number" ? "number" : "string");
|
|
1060
|
+
handle.value(t === "number" ? Number(c.id) : c.id);
|
|
1061
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1062
|
+
}
|
|
1063
|
+
case "structure": {
|
|
1064
|
+
const struct = node;
|
|
1065
|
+
const handle = defineAnnotatedType("object");
|
|
1066
|
+
for (const prop of Array.from(struct.props.values())) {
|
|
1067
|
+
const propHandle = this.toAnnotatedHandle(prop);
|
|
1068
|
+
const pattern = prop.token("identifier")?.pattern;
|
|
1069
|
+
if (pattern) handle.propPattern(pattern, propHandle.$type);
|
|
1070
|
+
else handle.prop(prop.id, propHandle.$type);
|
|
1071
|
+
}
|
|
1072
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1073
|
+
}
|
|
1074
|
+
case "group": {
|
|
1075
|
+
const group = node;
|
|
1076
|
+
const kind = group.op === "|" ? "union" : "intersection";
|
|
1077
|
+
const handle = defineAnnotatedType(kind);
|
|
1078
|
+
for (const item of group.unwrap()) handle.item(this.toAnnotatedHandle(item).$type);
|
|
1079
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1080
|
+
}
|
|
1081
|
+
case "tuple": {
|
|
1082
|
+
const group = node;
|
|
1083
|
+
const handle = defineAnnotatedType("tuple");
|
|
1084
|
+
for (const item of group.unwrap()) handle.item(this.toAnnotatedHandle(item).$type);
|
|
1085
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1086
|
+
}
|
|
1087
|
+
case "array": {
|
|
1088
|
+
const arr = node;
|
|
1089
|
+
const handle = defineAnnotatedType("array");
|
|
1090
|
+
handle.of(this.toAnnotatedHandle(arr.getDefinition()).$type);
|
|
1091
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1092
|
+
}
|
|
1093
|
+
default: {
|
|
1094
|
+
const handle = defineAnnotatedType();
|
|
1095
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
applyExpectAnnotations(handle, annotations) {
|
|
1100
|
+
annotations?.forEach((a) => {
|
|
1101
|
+
switch (a.name) {
|
|
1102
|
+
case "expect.minLength":
|
|
1103
|
+
case "expect.maxLength":
|
|
1104
|
+
case "expect.min":
|
|
1105
|
+
case "expect.max":
|
|
1106
|
+
if (a.args[0]) handle.annotate(a.name, Number(a.args[0].text));
|
|
1107
|
+
break;
|
|
1108
|
+
case "expect.pattern":
|
|
1109
|
+
handle.annotate(a.name, {
|
|
1110
|
+
pattern: a.args[0]?.text || "",
|
|
1111
|
+
flags: a.args[1]?.text,
|
|
1112
|
+
message: a.args[2]?.text
|
|
1113
|
+
}, true);
|
|
1114
|
+
break;
|
|
1115
|
+
case "expect.int":
|
|
1116
|
+
handle.annotate(a.name, true);
|
|
1117
|
+
break;
|
|
1118
|
+
default:
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
return handle;
|
|
1122
|
+
}
|
|
1123
|
+
annotateType(_node, name) {
|
|
1124
|
+
if (!_node) return this;
|
|
1125
|
+
const node = this.doc.mergeIntersection(_node);
|
|
1126
|
+
let kind = node.entity;
|
|
1127
|
+
switch (node.entity) {
|
|
1128
|
+
case "ref": {
|
|
1129
|
+
const ref = node;
|
|
1130
|
+
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1131
|
+
if ((0, __atscript_core.isPrimitive)(decl)) {
|
|
1132
|
+
this.annotateType(decl, name);
|
|
1133
|
+
return this;
|
|
1134
|
+
}
|
|
1135
|
+
const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
|
|
1136
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`).unindent();
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
case "primitive": {
|
|
1140
|
+
this.definePrimitive(node, name);
|
|
1141
|
+
return this;
|
|
1142
|
+
}
|
|
1143
|
+
case "const": {
|
|
1144
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().defineConst(node).unindent();
|
|
1145
|
+
return this;
|
|
1146
|
+
}
|
|
1147
|
+
case "structure": {
|
|
1148
|
+
this.writeln(`$("object"${name ? `, ${name}` : ""})`).indent().defineObject(node).unindent();
|
|
1149
|
+
return this;
|
|
1150
|
+
}
|
|
1151
|
+
case "group": {
|
|
1152
|
+
kind = node.op === "|" ? "union" : "intersection";
|
|
1153
|
+
this.writeln(`$("${kind}"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
1154
|
+
return this;
|
|
1155
|
+
}
|
|
1156
|
+
case "tuple": {
|
|
1157
|
+
this.writeln(`$("tuple"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
1158
|
+
return this;
|
|
1159
|
+
}
|
|
1160
|
+
case "array": {
|
|
1161
|
+
this.writeln(`$("array"${name ? `, ${name}` : ""})`).indent().defineArray(node).unindent();
|
|
1162
|
+
return this;
|
|
1163
|
+
}
|
|
1164
|
+
default: {
|
|
1165
|
+
console.log("!!!!!!! UNKNOWN ", node.entity);
|
|
1166
|
+
return this;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
defineConst(node) {
|
|
1171
|
+
const t = node.token("identifier")?.type;
|
|
1172
|
+
const designType = t === "text" ? "string" : t === "number" ? "number" : "unknown";
|
|
1173
|
+
this.writeln(`.designType("${escapeQuotes(designType)}")`);
|
|
1174
|
+
this.writeln(`.value(${t === "text" ? `"${escapeQuotes(node.id)}"` : node.id})`);
|
|
1175
|
+
return this;
|
|
1176
|
+
}
|
|
1177
|
+
definePrimitive(node, name) {
|
|
1178
|
+
this.renderPrimitiveDef(node.id === "never" ? "never" : node.config.type, name);
|
|
1179
|
+
this.writeln(` .tags(${Array.from(node.tags).map((f) => `"${escapeQuotes(f)}"`).join(", ")})`);
|
|
1180
|
+
return this;
|
|
1181
|
+
}
|
|
1182
|
+
renderPrimitiveDef(def, name) {
|
|
1183
|
+
const d = (t) => [`"${t || ""}"`, name].filter(Boolean).join(", ").replace(/^""$/, "");
|
|
1184
|
+
if (!def) return this.writeln(`$(${d()}).designType("any")`);
|
|
1185
|
+
if (typeof def === "string") return this.writeln(`$(${d()}).designType("${def === "void" ? "undefined" : def}")`);
|
|
1186
|
+
switch (def.kind) {
|
|
1187
|
+
case "final": return this.writeln(`$(${d()}).designType("${def.value === "void" ? "undefined" : def.value}")`);
|
|
1188
|
+
case "union":
|
|
1189
|
+
case "intersection":
|
|
1190
|
+
case "tuple":
|
|
1191
|
+
this.writeln(`$(${d(def.kind)})`);
|
|
1192
|
+
this.indent();
|
|
1193
|
+
for (const itemDef of def.items) {
|
|
1194
|
+
this.write(`.item(`);
|
|
1195
|
+
this.indent();
|
|
1196
|
+
this.renderPrimitiveDef(itemDef);
|
|
1197
|
+
this.writeln(".$type");
|
|
1198
|
+
this.unindent();
|
|
1199
|
+
this.write(`)`);
|
|
1200
|
+
}
|
|
1201
|
+
this.unindent();
|
|
1202
|
+
return;
|
|
1203
|
+
case "array":
|
|
1204
|
+
this.writeln(`$(${d("array")})`);
|
|
1205
|
+
this.indent();
|
|
1206
|
+
this.write(".of(");
|
|
1207
|
+
this.indent();
|
|
1208
|
+
this.renderPrimitiveDef(def.of);
|
|
1209
|
+
this.writeln(`.$type`);
|
|
1210
|
+
this.unindent();
|
|
1211
|
+
this.writeln(`)`);
|
|
1212
|
+
this.unindent();
|
|
1213
|
+
return;
|
|
1214
|
+
case "object":
|
|
1215
|
+
this.writeln(`$(${d("object")})`);
|
|
1216
|
+
this.indent();
|
|
1217
|
+
for (const [key, propDef] of Object.entries(def.props)) {
|
|
1218
|
+
const optional = typeof propDef === "object" && propDef.optional;
|
|
1219
|
+
this.writeln(`.prop(`);
|
|
1220
|
+
this.indent();
|
|
1221
|
+
this.writeln(`"${escapeQuotes(key)}",`);
|
|
1222
|
+
this.renderPrimitiveDef(propDef);
|
|
1223
|
+
if (optional) this.writeln(".optional()");
|
|
1224
|
+
this.writeln(".$type");
|
|
1225
|
+
this.unindent();
|
|
1226
|
+
this.write(`)`);
|
|
1227
|
+
}
|
|
1228
|
+
for (const [key, propDef] of Object.entries(def.propsPatterns)) {
|
|
1229
|
+
const optional = typeof propDef === "object" && propDef.optional;
|
|
1230
|
+
this.writeln(`.propPattern(`);
|
|
1231
|
+
this.indent();
|
|
1232
|
+
this.writeln(`${key},`);
|
|
1233
|
+
this.renderPrimitiveDef(propDef);
|
|
1234
|
+
if (optional) this.writeln(".optional()");
|
|
1235
|
+
this.writeln(".$type");
|
|
1236
|
+
this.unindent();
|
|
1237
|
+
this.write(`)`);
|
|
1238
|
+
}
|
|
1239
|
+
this.unindent();
|
|
1240
|
+
return;
|
|
1241
|
+
default: return this.writeln(`$(${d()}).designType("any")`);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
defineObject(node) {
|
|
1245
|
+
const props = Array.from(node.props.values());
|
|
1246
|
+
for (const prop of props) {
|
|
1247
|
+
const pattern = prop.token("identifier")?.pattern;
|
|
1248
|
+
const optional = !!prop.token("optional");
|
|
1249
|
+
if (pattern) {
|
|
1250
|
+
this.writeln(`.propPattern(`);
|
|
1251
|
+
this.indent();
|
|
1252
|
+
this.writeln(`/${pattern.source}/${pattern.flags},`);
|
|
1253
|
+
} else {
|
|
1254
|
+
this.writeln(`.prop(`);
|
|
1255
|
+
this.indent();
|
|
1256
|
+
this.writeln(`"${escapeQuotes(prop.id)}",`);
|
|
1257
|
+
}
|
|
1258
|
+
this.annotateType(prop.getDefinition());
|
|
1259
|
+
this.indent().defineMetadata(prop).unindent();
|
|
1260
|
+
if (optional) this.writeln(" .optional()");
|
|
1261
|
+
this.writeln(" .$type");
|
|
1262
|
+
this.unindent();
|
|
1263
|
+
this.write(`)`);
|
|
1264
|
+
}
|
|
1265
|
+
this.writeln();
|
|
1266
|
+
return this;
|
|
1267
|
+
}
|
|
1268
|
+
defineGroup(node) {
|
|
1269
|
+
const items = node.unwrap();
|
|
1270
|
+
for (const item of items) this.write(".item(").indent().annotateType(item).write(" .$type").writeln(`)`).unindent();
|
|
1271
|
+
return this;
|
|
1272
|
+
}
|
|
1273
|
+
defineArray(node) {
|
|
1274
|
+
this.write(".of(").indent().annotateType(node.getDefinition()).write(" .$type").writeln(`)`).unindent();
|
|
1275
|
+
return this;
|
|
1276
|
+
}
|
|
1277
|
+
defineMetadata(node) {
|
|
1278
|
+
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1279
|
+
annotations?.forEach((an) => {
|
|
1280
|
+
this.resolveAnnotationValue(node, an);
|
|
1281
|
+
});
|
|
1282
|
+
return this;
|
|
1283
|
+
}
|
|
1284
|
+
resolveAnnotationValue(node, an) {
|
|
1285
|
+
const spec = this.doc.resolveAnnotation(an.name);
|
|
1286
|
+
let targetValue = "true";
|
|
1287
|
+
let multiple = false;
|
|
1288
|
+
if (spec) {
|
|
1289
|
+
multiple = spec.config.multiple;
|
|
1290
|
+
const length = spec.arguments.length;
|
|
1291
|
+
if (length !== 0) if (Array.isArray(spec.config.argument)) {
|
|
1292
|
+
targetValue = "{ ";
|
|
1293
|
+
let i = 0;
|
|
1294
|
+
for (const aSpec of spec.arguments) {
|
|
1295
|
+
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
1296
|
+
else {}
|
|
1297
|
+
i++;
|
|
1298
|
+
}
|
|
1299
|
+
targetValue += "}";
|
|
1300
|
+
} else {
|
|
1301
|
+
const aSpec = spec.arguments[0];
|
|
1302
|
+
if (an.args[0]) targetValue = aSpec.type === "string" ? `"${escapeQuotes(an.args[0]?.text)}"` : an.args[0]?.text;
|
|
1303
|
+
else targetValue = "true";
|
|
1304
|
+
}
|
|
1305
|
+
} else {
|
|
1306
|
+
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1307
|
+
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1308
|
+
}
|
|
1309
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue}, true)`);
|
|
1310
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue})`);
|
|
1311
|
+
}
|
|
1312
|
+
constructor(doc, opts) {
|
|
1313
|
+
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
|
|
1317
|
+
//#endregion
|
|
1318
|
+
//#region packages/typescript/src/plugin.ts
|
|
1319
|
+
const tsPlugin = (opts) => {
|
|
1320
|
+
return {
|
|
1321
|
+
name: "typesccript",
|
|
1322
|
+
render(doc, format) {
|
|
1323
|
+
if (format === "dts") return [{
|
|
1324
|
+
fileName: `${doc.name}.d.ts`,
|
|
1325
|
+
content: new TypeRenderer(doc, opts).render()
|
|
1326
|
+
}];
|
|
1327
|
+
if (format === "js") return [{
|
|
1328
|
+
fileName: `${doc.name}.js`,
|
|
1329
|
+
content: new JsRenderer(doc, opts).render()
|
|
1330
|
+
}];
|
|
1331
|
+
},
|
|
1332
|
+
async buildEnd(output, format, repo) {
|
|
1333
|
+
if (format === "dts") {
|
|
1334
|
+
const annotations = await repo.getUsedAnnotations();
|
|
1335
|
+
const tags = await repo.getPrimitivesTags() || new Set();
|
|
1336
|
+
let rendered = [];
|
|
1337
|
+
for (const [key, val] of Object.entries(annotations)) {
|
|
1338
|
+
const multiple = val.multiple;
|
|
1339
|
+
let typeLine = Array.from(val.types).map((t) => {
|
|
1340
|
+
if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
|
|
1341
|
+
else return t.optional ? `${t.type} | true` : t.type;
|
|
1342
|
+
}).join(" | ");
|
|
1343
|
+
rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
|
|
1344
|
+
}
|
|
1345
|
+
let renderedTags = Array.from(tags).map((f) => `"${escapeQuotes(f)}"`).join(" | ");
|
|
1346
|
+
output.push({
|
|
1347
|
+
content: "// prettier-ignore-start\n/* eslint-disable */\n/**\n * 🪄 This file was generated by Atscript\n * It is generated based on annotations used in this project\n * Do not edit this file!\n *\n * Use `npx asc -f dts` command to re-generate this file\n */\nexport {}\n\ndeclare global {\n interface AtscriptMetadata {\n " + rendered.join("\n ") + "\n }\n" + " type AtscriptPrimitiveTags = " + renderedTags + "\n" + "}\n" + "// prettier-ignore-end",
|
|
1348
|
+
fileName: "atscript.d.ts",
|
|
1349
|
+
source: "",
|
|
1350
|
+
target: path.default.join(repo.root, "atscript.d.ts")
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
};
|
|
1356
|
+
|
|
1128
1357
|
//#endregion
|
|
1129
1358
|
//#region packages/typescript/src/index.ts
|
|
1130
1359
|
var src_default = tsPlugin;
|
|
@@ -1132,6 +1361,7 @@ var src_default = tsPlugin;
|
|
|
1132
1361
|
//#endregion
|
|
1133
1362
|
exports.Validator = Validator
|
|
1134
1363
|
exports.ValidatorError = ValidatorError
|
|
1364
|
+
exports.buildJsonSchema = buildJsonSchema
|
|
1135
1365
|
exports.default = src_default
|
|
1136
1366
|
exports.defineAnnotatedType = defineAnnotatedType
|
|
1137
1367
|
exports.isAnnotatedType = isAnnotatedType
|