@atscript/typescript 0.0.27 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +689 -15
- package/dist/index.cjs +586 -361
- package/dist/index.d.ts +11 -2
- package/dist/index.mjs +586 -362
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { isArray, isConst, isGroup, isInterface, isPrimitive, isRef, isStructure
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
4
|
//#region packages/typescript/src/codegen/code-printer.ts
|
|
5
|
-
function _define_property$
|
|
5
|
+
function _define_property$4(obj, key, value) {
|
|
6
6
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
7
7
|
value,
|
|
8
8
|
enumerable: true,
|
|
@@ -95,17 +95,17 @@ else this.write(closing);
|
|
|
95
95
|
return " ".repeat(this.indentLevel * this.indentSize);
|
|
96
96
|
}
|
|
97
97
|
constructor() {
|
|
98
|
-
_define_property$
|
|
99
|
-
_define_property$
|
|
100
|
-
_define_property$
|
|
101
|
-
_define_property$
|
|
102
|
-
_define_property$
|
|
98
|
+
_define_property$4(this, "lines", []);
|
|
99
|
+
_define_property$4(this, "currentLine", "");
|
|
100
|
+
_define_property$4(this, "indentLevel", 0);
|
|
101
|
+
_define_property$4(this, "indentSize", 2);
|
|
102
|
+
_define_property$4(this, "blockStack", []);
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
//#endregion
|
|
107
107
|
//#region packages/typescript/src/codegen/base-renderer.ts
|
|
108
|
-
function _define_property$
|
|
108
|
+
function _define_property$3(obj, key, value) {
|
|
109
109
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
110
110
|
value,
|
|
111
111
|
enumerable: true,
|
|
@@ -164,7 +164,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
constructor(doc) {
|
|
167
|
-
super(), _define_property$
|
|
167
|
+
super(), _define_property$3(this, "doc", void 0), _define_property$3(this, "unused", void 0), this.doc = doc;
|
|
168
168
|
this.unused = new Set(this.doc.getUnusedTokens().map((t) => t.text));
|
|
169
169
|
}
|
|
170
170
|
};
|
|
@@ -182,6 +182,16 @@ function escapeQuotes(str) {
|
|
|
182
182
|
|
|
183
183
|
//#endregion
|
|
184
184
|
//#region packages/typescript/src/codegen/type-renderer.ts
|
|
185
|
+
function _define_property$2(obj, key, value) {
|
|
186
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
187
|
+
value,
|
|
188
|
+
enumerable: true,
|
|
189
|
+
configurable: true,
|
|
190
|
+
writable: true
|
|
191
|
+
});
|
|
192
|
+
else obj[key] = value;
|
|
193
|
+
return obj;
|
|
194
|
+
}
|
|
185
195
|
var TypeRenderer = class extends BaseRenderer {
|
|
186
196
|
pre() {
|
|
187
197
|
this.writeln("// prettier-ignore-start");
|
|
@@ -279,6 +289,7 @@ else if (patterns.length === 1) {
|
|
|
279
289
|
this.writeln(`static type: TAtscriptTypeObject<keyof ${asClass}>`);
|
|
280
290
|
this.writeln(`static metadata: TMetadataMap<AtscriptMetadata>`);
|
|
281
291
|
this.writeln(`static validator: <TT extends TAtscriptAnnotatedTypeConstructor = ${asClass}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
|
|
292
|
+
this.writeln("static toJsonSchema: () => any");
|
|
282
293
|
}
|
|
283
294
|
this.pop();
|
|
284
295
|
}
|
|
@@ -321,6 +332,7 @@ else if (isPrimitive(realDef)) typeDef = "TAtscriptTypeFinal";
|
|
|
321
332
|
this.writeln(`const type: ${typeDef}`);
|
|
322
333
|
this.writeln(`const metadata: TMetadataMap<AtscriptMetadata>`);
|
|
323
334
|
this.writeln(`const validator: <TT extends TAtscriptAnnotatedTypeConstructor = ${node.id}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
|
|
335
|
+
if (this.opts?.jsonSchema) this.writeln("const toJsonSchema: () => any");
|
|
324
336
|
this.popln();
|
|
325
337
|
}
|
|
326
338
|
renderJsDoc(node) {
|
|
@@ -331,6 +343,9 @@ else if (isPrimitive(realDef)) typeDef = "TAtscriptTypeFinal";
|
|
|
331
343
|
this.writeln(` * @see {@link ./${this.doc.name}${rangeStr}}`);
|
|
332
344
|
this.writeln(` */`);
|
|
333
345
|
}
|
|
346
|
+
constructor(doc, opts) {
|
|
347
|
+
super(doc), _define_property$2(this, "opts", void 0), this.opts = opts;
|
|
348
|
+
}
|
|
334
349
|
};
|
|
335
350
|
function renderPrimitiveTypeDef(def) {
|
|
336
351
|
if (!def) return "unknown";
|
|
@@ -350,7 +365,7 @@ function renderPrimitiveTypeDef(def) {
|
|
|
350
365
|
}
|
|
351
366
|
|
|
352
367
|
//#endregion
|
|
353
|
-
//#region packages/typescript/src/
|
|
368
|
+
//#region packages/typescript/src/validator.ts
|
|
354
369
|
function _define_property$1(obj, key, value) {
|
|
355
370
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
356
371
|
value,
|
|
@@ -361,363 +376,75 @@ function _define_property$1(obj, key, value) {
|
|
|
361
376
|
else obj[key] = value;
|
|
362
377
|
return obj;
|
|
363
378
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
this.
|
|
368
|
-
this.
|
|
369
|
-
}
|
|
370
|
-
post() {
|
|
371
|
-
for (const node of this.postAnnotate) {
|
|
372
|
-
this.annotateType(node.getDefinition(), node.id);
|
|
373
|
-
this.indent().defineMetadata(node).unindent();
|
|
374
|
-
this.writeln();
|
|
375
|
-
}
|
|
376
|
-
this.writeln("// prettier-ignore-end");
|
|
377
|
-
super.post();
|
|
379
|
+
const regexCache = new Map();
|
|
380
|
+
var Validator = class {
|
|
381
|
+
isLimitExceeded() {
|
|
382
|
+
if (this.stackErrors.length > 0) return this.stackErrors[this.stackErrors.length - 1].length >= this.opts.errorLimit;
|
|
383
|
+
return this.errors.length >= this.opts.errorLimit;
|
|
378
384
|
}
|
|
379
|
-
|
|
380
|
-
this.
|
|
381
|
-
|
|
382
|
-
this.write(exported ? "export " : "");
|
|
383
|
-
this.write(`class ${node.id} `);
|
|
384
|
-
this.blockln("{}");
|
|
385
|
-
this.writeln("static __is_atscript_annotated_type = true");
|
|
386
|
-
this.writeln("static type = {}");
|
|
387
|
-
this.writeln("static metadata = new Map()");
|
|
388
|
-
this.popln();
|
|
389
|
-
this.postAnnotate.push(node);
|
|
390
|
-
this.writeln();
|
|
385
|
+
push(name) {
|
|
386
|
+
this.stackPath.push(name);
|
|
387
|
+
this.stackErrors.push([]);
|
|
391
388
|
}
|
|
392
|
-
|
|
393
|
-
this.
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
this.writeln("static type = {}");
|
|
400
|
-
this.writeln("static metadata = new Map()");
|
|
401
|
-
this.popln();
|
|
402
|
-
this.postAnnotate.push(node);
|
|
403
|
-
this.writeln();
|
|
389
|
+
pop(saveErrors) {
|
|
390
|
+
this.stackPath.pop();
|
|
391
|
+
const popped = this.stackErrors.pop();
|
|
392
|
+
if (saveErrors && popped?.length) popped.forEach((error) => {
|
|
393
|
+
this.error(error.message, error.path, error.details);
|
|
394
|
+
});
|
|
395
|
+
return popped;
|
|
404
396
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const node = this.doc.mergeIntersection(_node);
|
|
408
|
-
let kind = node.entity;
|
|
409
|
-
switch (node.entity) {
|
|
410
|
-
case "ref": {
|
|
411
|
-
const ref = node;
|
|
412
|
-
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
413
|
-
if (isPrimitive(decl)) {
|
|
414
|
-
this.annotateType(decl, name);
|
|
415
|
-
return this;
|
|
416
|
-
}
|
|
417
|
-
const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
|
|
418
|
-
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`).unindent();
|
|
419
|
-
return this;
|
|
420
|
-
}
|
|
421
|
-
case "primitive": {
|
|
422
|
-
this.definePrimitive(node, name);
|
|
423
|
-
return this;
|
|
424
|
-
}
|
|
425
|
-
case "const": {
|
|
426
|
-
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().defineConst(node).unindent();
|
|
427
|
-
return this;
|
|
428
|
-
}
|
|
429
|
-
case "structure": {
|
|
430
|
-
this.writeln(`$("object"${name ? `, ${name}` : ""})`).indent().defineObject(node).unindent();
|
|
431
|
-
return this;
|
|
432
|
-
}
|
|
433
|
-
case "group": {
|
|
434
|
-
kind = node.op === "|" ? "union" : "intersection";
|
|
435
|
-
this.writeln(`$("${kind}"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
436
|
-
return this;
|
|
437
|
-
}
|
|
438
|
-
case "tuple": {
|
|
439
|
-
this.writeln(`$("tuple"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
440
|
-
return this;
|
|
441
|
-
}
|
|
442
|
-
case "array": {
|
|
443
|
-
this.writeln(`$("array"${name ? `, ${name}` : ""})`).indent().defineArray(node).unindent();
|
|
444
|
-
return this;
|
|
445
|
-
}
|
|
446
|
-
default: {
|
|
447
|
-
console.log("!!!!!!! UNKNOWN ", node.entity);
|
|
448
|
-
return this;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
397
|
+
clear() {
|
|
398
|
+
this.stackErrors[this.stackErrors.length - 1] = [];
|
|
451
399
|
}
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
400
|
+
error(message, path$1, details) {
|
|
401
|
+
const errors = this.stackErrors[this.stackErrors.length - 1] || this.errors;
|
|
402
|
+
const error = {
|
|
403
|
+
path: path$1 || this.path,
|
|
404
|
+
message
|
|
405
|
+
};
|
|
406
|
+
if (details?.length) error.details = details;
|
|
407
|
+
errors.push(error);
|
|
459
408
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
this.writeln(` .tags(${Array.from(node.tags).map((f) => `"${escapeQuotes(f)}"`).join(", ")})`);
|
|
463
|
-
return this;
|
|
409
|
+
throw() {
|
|
410
|
+
throw new ValidatorError(this.errors);
|
|
464
411
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
this.writeln(`$(${d(def.kind)})`);
|
|
475
|
-
this.indent();
|
|
476
|
-
for (const itemDef of def.items) {
|
|
477
|
-
this.write(`.item(`);
|
|
478
|
-
this.indent();
|
|
479
|
-
this.renderPrimitiveDef(itemDef);
|
|
480
|
-
this.writeln(".$type");
|
|
481
|
-
this.unindent();
|
|
482
|
-
this.write(`)`);
|
|
483
|
-
}
|
|
484
|
-
this.unindent();
|
|
485
|
-
return;
|
|
486
|
-
case "array":
|
|
487
|
-
this.writeln(`$(${d("array")})`);
|
|
488
|
-
this.indent();
|
|
489
|
-
this.write(".of(");
|
|
490
|
-
this.indent();
|
|
491
|
-
this.renderPrimitiveDef(def.of);
|
|
492
|
-
this.writeln(`.$type`);
|
|
493
|
-
this.unindent();
|
|
494
|
-
this.writeln(`)`);
|
|
495
|
-
this.unindent();
|
|
496
|
-
return;
|
|
497
|
-
case "object":
|
|
498
|
-
this.writeln(`$(${d("object")})`);
|
|
499
|
-
this.indent();
|
|
500
|
-
for (const [key, propDef] of Object.entries(def.props)) {
|
|
501
|
-
const optional = typeof propDef === "object" && propDef.optional;
|
|
502
|
-
this.writeln(`.prop(`);
|
|
503
|
-
this.indent();
|
|
504
|
-
this.writeln(`"${escapeQuotes(key)}",`);
|
|
505
|
-
this.renderPrimitiveDef(propDef);
|
|
506
|
-
if (optional) this.writeln(".optional()");
|
|
507
|
-
this.writeln(".$type");
|
|
508
|
-
this.unindent();
|
|
509
|
-
this.write(`)`);
|
|
510
|
-
}
|
|
511
|
-
for (const [key, propDef] of Object.entries(def.propsPatterns)) {
|
|
512
|
-
const optional = typeof propDef === "object" && propDef.optional;
|
|
513
|
-
this.writeln(`.propPattern(`);
|
|
514
|
-
this.indent();
|
|
515
|
-
this.writeln(`${key},`);
|
|
516
|
-
this.renderPrimitiveDef(propDef);
|
|
517
|
-
if (optional) this.writeln(".optional()");
|
|
518
|
-
this.writeln(".$type");
|
|
519
|
-
this.unindent();
|
|
520
|
-
this.write(`)`);
|
|
521
|
-
}
|
|
522
|
-
this.unindent();
|
|
523
|
-
return;
|
|
524
|
-
default: return this.writeln(`$(${d()}).designType("any")`);
|
|
412
|
+
validate(value, safe) {
|
|
413
|
+
this.push("");
|
|
414
|
+
this.errors = [];
|
|
415
|
+
this.stackErrors = [];
|
|
416
|
+
const passed = this.validateSafe(this.def, value);
|
|
417
|
+
this.pop(!passed);
|
|
418
|
+
if (!passed) {
|
|
419
|
+
if (safe) return false;
|
|
420
|
+
this.throw();
|
|
525
421
|
}
|
|
422
|
+
return true;
|
|
526
423
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
this.writeln(`/${pattern.source}/${pattern.flags},`);
|
|
536
|
-
} else {
|
|
537
|
-
this.writeln(`.prop(`);
|
|
538
|
-
this.indent();
|
|
539
|
-
this.writeln(`"${escapeQuotes(prop.id)}",`);
|
|
540
|
-
}
|
|
541
|
-
this.annotateType(prop.getDefinition());
|
|
542
|
-
this.indent().defineMetadata(prop).unindent();
|
|
543
|
-
if (optional) this.writeln(" .optional()");
|
|
544
|
-
this.writeln(" .$type");
|
|
545
|
-
this.unindent();
|
|
546
|
-
this.write(`)`);
|
|
424
|
+
validateSafe(def, value) {
|
|
425
|
+
if (this.isLimitExceeded()) return false;
|
|
426
|
+
if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
|
|
427
|
+
if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.path);
|
|
428
|
+
if (def.optional && value === undefined) return true;
|
|
429
|
+
for (const plugin of this.opts.plugins) {
|
|
430
|
+
const result = plugin(this, def, value);
|
|
431
|
+
if (result === false || result === true) return result;
|
|
547
432
|
}
|
|
548
|
-
this.
|
|
549
|
-
return this;
|
|
433
|
+
return this.validateAnnotatedType(def, value);
|
|
550
434
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
for (const item of items) this.write(".item(").indent().annotateType(item).write(" .$type").writeln(`)`).unindent();
|
|
554
|
-
return this;
|
|
435
|
+
get path() {
|
|
436
|
+
return this.stackPath.slice(1).join(".");
|
|
555
437
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
this.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
resolveAnnotationValue(node, an) {
|
|
568
|
-
const spec = this.doc.resolveAnnotation(an.name);
|
|
569
|
-
let targetValue = "true";
|
|
570
|
-
let multiple = false;
|
|
571
|
-
if (spec) {
|
|
572
|
-
multiple = spec.config.multiple;
|
|
573
|
-
const length = spec.arguments.length;
|
|
574
|
-
if (length !== 0) if (Array.isArray(spec.config.argument)) {
|
|
575
|
-
targetValue = "{ ";
|
|
576
|
-
let i = 0;
|
|
577
|
-
for (const aSpec of spec.arguments) {
|
|
578
|
-
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
579
|
-
else {}
|
|
580
|
-
i++;
|
|
581
|
-
}
|
|
582
|
-
targetValue += "}";
|
|
583
|
-
} else {
|
|
584
|
-
const aSpec = spec.arguments[0];
|
|
585
|
-
if (an.args[0]) targetValue = aSpec.type === "string" ? `"${escapeQuotes(an.args[0]?.text)}"` : an.args[0]?.text;
|
|
586
|
-
else targetValue = "true";
|
|
587
|
-
}
|
|
588
|
-
} else {
|
|
589
|
-
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
590
|
-
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
591
|
-
}
|
|
592
|
-
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue}, true)`);
|
|
593
|
-
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue})`);
|
|
594
|
-
}
|
|
595
|
-
constructor(...args) {
|
|
596
|
-
super(...args), _define_property$1(this, "postAnnotate", []);
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
//#endregion
|
|
601
|
-
//#region packages/typescript/src/plugin.ts
|
|
602
|
-
const tsPlugin = () => {
|
|
603
|
-
return {
|
|
604
|
-
name: "typesccript",
|
|
605
|
-
render(doc, format) {
|
|
606
|
-
if (format === "dts") return [{
|
|
607
|
-
fileName: `${doc.name}.d.ts`,
|
|
608
|
-
content: new TypeRenderer(doc).render()
|
|
609
|
-
}];
|
|
610
|
-
if (format === "js") return [{
|
|
611
|
-
fileName: `${doc.name}.js`,
|
|
612
|
-
content: new JsRenderer(doc).render()
|
|
613
|
-
}];
|
|
614
|
-
},
|
|
615
|
-
async buildEnd(output, format, repo) {
|
|
616
|
-
if (format === "dts") {
|
|
617
|
-
const annotations = await repo.getUsedAnnotations();
|
|
618
|
-
const tags = await repo.getPrimitivesTags() || new Set();
|
|
619
|
-
let rendered = [];
|
|
620
|
-
for (const [key, val] of Object.entries(annotations)) {
|
|
621
|
-
const multiple = val.multiple;
|
|
622
|
-
let typeLine = Array.from(val.types).map((t) => {
|
|
623
|
-
if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
|
|
624
|
-
else return t.optional ? `${t.type} | true` : t.type;
|
|
625
|
-
}).join(" | ");
|
|
626
|
-
rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
|
|
627
|
-
}
|
|
628
|
-
let renderedTags = Array.from(tags).map((f) => `"${escapeQuotes(f)}"`).join(" | ");
|
|
629
|
-
output.push({
|
|
630
|
-
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",
|
|
631
|
-
fileName: "atscript.d.ts",
|
|
632
|
-
source: "",
|
|
633
|
-
target: path.join(repo.root, "atscript.d.ts")
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
};
|
|
638
|
-
};
|
|
639
|
-
|
|
640
|
-
//#endregion
|
|
641
|
-
//#region packages/typescript/src/validator.ts
|
|
642
|
-
function _define_property(obj, key, value) {
|
|
643
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
644
|
-
value,
|
|
645
|
-
enumerable: true,
|
|
646
|
-
configurable: true,
|
|
647
|
-
writable: true
|
|
648
|
-
});
|
|
649
|
-
else obj[key] = value;
|
|
650
|
-
return obj;
|
|
651
|
-
}
|
|
652
|
-
const regexCache = new Map();
|
|
653
|
-
var Validator = class {
|
|
654
|
-
isLimitExceeded() {
|
|
655
|
-
if (this.stackErrors.length > 0) return this.stackErrors[this.stackErrors.length - 1].length >= this.opts.errorLimit;
|
|
656
|
-
return this.errors.length >= this.opts.errorLimit;
|
|
657
|
-
}
|
|
658
|
-
push(name) {
|
|
659
|
-
this.stackPath.push(name);
|
|
660
|
-
this.stackErrors.push([]);
|
|
661
|
-
}
|
|
662
|
-
pop(saveErrors) {
|
|
663
|
-
this.stackPath.pop();
|
|
664
|
-
const popped = this.stackErrors.pop();
|
|
665
|
-
if (saveErrors && popped?.length) popped.forEach((error) => {
|
|
666
|
-
this.error(error.message, error.path, error.details);
|
|
667
|
-
});
|
|
668
|
-
return popped;
|
|
669
|
-
}
|
|
670
|
-
clear() {
|
|
671
|
-
this.stackErrors[this.stackErrors.length - 1] = [];
|
|
672
|
-
}
|
|
673
|
-
error(message, path$1, details) {
|
|
674
|
-
const errors = this.stackErrors[this.stackErrors.length - 1] || this.errors;
|
|
675
|
-
const error = {
|
|
676
|
-
path: path$1 || this.path,
|
|
677
|
-
message
|
|
678
|
-
};
|
|
679
|
-
if (details?.length) error.details = details;
|
|
680
|
-
errors.push(error);
|
|
681
|
-
}
|
|
682
|
-
throw() {
|
|
683
|
-
throw new ValidatorError(this.errors);
|
|
684
|
-
}
|
|
685
|
-
validate(value, safe) {
|
|
686
|
-
this.push("");
|
|
687
|
-
this.errors = [];
|
|
688
|
-
this.stackErrors = [];
|
|
689
|
-
const passed = this.validateSafe(this.def, value);
|
|
690
|
-
this.pop(!passed);
|
|
691
|
-
if (!passed) {
|
|
692
|
-
if (safe) return false;
|
|
693
|
-
this.throw();
|
|
694
|
-
}
|
|
695
|
-
return true;
|
|
696
|
-
}
|
|
697
|
-
validateSafe(def, value) {
|
|
698
|
-
if (this.isLimitExceeded()) return false;
|
|
699
|
-
if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
|
|
700
|
-
if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.path);
|
|
701
|
-
if (def.optional && value === undefined) return true;
|
|
702
|
-
for (const plugin of this.opts.plugins) {
|
|
703
|
-
const result = plugin(this, def, value);
|
|
704
|
-
if (result === false || result === true) return result;
|
|
705
|
-
}
|
|
706
|
-
return this.validateAnnotatedType(def, value);
|
|
707
|
-
}
|
|
708
|
-
get path() {
|
|
709
|
-
return this.stackPath.slice(1).join(".");
|
|
710
|
-
}
|
|
711
|
-
validateAnnotatedType(def, value) {
|
|
712
|
-
switch (def.type.kind) {
|
|
713
|
-
case "object": return this.validateObject(def, value);
|
|
714
|
-
case "union": return this.validateUnion(def, value);
|
|
715
|
-
case "intersection": return this.validateIntersection(def, value);
|
|
716
|
-
case "tuple": return this.validateTuple(def, value);
|
|
717
|
-
case "array": return this.validateArray(def, value);
|
|
718
|
-
case "": return this.validatePrimitive(def, value);
|
|
719
|
-
default: throw new Error(`Unknown type "${def.type.kind}"`);
|
|
720
|
-
}
|
|
438
|
+
validateAnnotatedType(def, value) {
|
|
439
|
+
switch (def.type.kind) {
|
|
440
|
+
case "object": return this.validateObject(def, value);
|
|
441
|
+
case "union": return this.validateUnion(def, value);
|
|
442
|
+
case "intersection": return this.validateIntersection(def, value);
|
|
443
|
+
case "tuple": return this.validateTuple(def, value);
|
|
444
|
+
case "array": return this.validateArray(def, value);
|
|
445
|
+
case "": return this.validatePrimitive(def, value);
|
|
446
|
+
default: throw new Error(`Unknown type "${def.type.kind}"`);
|
|
447
|
+
}
|
|
721
448
|
}
|
|
722
449
|
validateUnion(def, value) {
|
|
723
450
|
let i = 0;
|
|
@@ -947,11 +674,11 @@ else {
|
|
|
947
674
|
return true;
|
|
948
675
|
}
|
|
949
676
|
constructor(def, opts) {
|
|
950
|
-
_define_property(this, "def", void 0);
|
|
951
|
-
_define_property(this, "opts", void 0);
|
|
952
|
-
_define_property(this, "errors", void 0);
|
|
953
|
-
_define_property(this, "stackErrors", void 0);
|
|
954
|
-
_define_property(this, "stackPath", void 0);
|
|
677
|
+
_define_property$1(this, "def", void 0);
|
|
678
|
+
_define_property$1(this, "opts", void 0);
|
|
679
|
+
_define_property$1(this, "errors", void 0);
|
|
680
|
+
_define_property$1(this, "stackErrors", void 0);
|
|
681
|
+
_define_property$1(this, "stackPath", void 0);
|
|
955
682
|
this.def = def;
|
|
956
683
|
this.errors = [];
|
|
957
684
|
this.stackErrors = [];
|
|
@@ -967,7 +694,7 @@ else {
|
|
|
967
694
|
};
|
|
968
695
|
var ValidatorError = class extends Error {
|
|
969
696
|
constructor(errors) {
|
|
970
|
-
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";
|
|
697
|
+
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";
|
|
971
698
|
}
|
|
972
699
|
};
|
|
973
700
|
|
|
@@ -1100,9 +827,506 @@ function isAnnotatedTypeOfPrimitive(t) {
|
|
|
1100
827
|
return false;
|
|
1101
828
|
}
|
|
1102
829
|
|
|
830
|
+
//#endregion
|
|
831
|
+
//#region packages/typescript/src/json-schema.ts
|
|
832
|
+
function buildJsonSchema(type) {
|
|
833
|
+
const build = (def) => {
|
|
834
|
+
const t = def.type;
|
|
835
|
+
const meta = def.metadata;
|
|
836
|
+
switch (t.kind) {
|
|
837
|
+
case "object": {
|
|
838
|
+
const obj = t;
|
|
839
|
+
const properties = {};
|
|
840
|
+
const required = [];
|
|
841
|
+
for (const [key, val] of obj.props.entries()) {
|
|
842
|
+
properties[key] = build(val);
|
|
843
|
+
if (!val.optional) required.push(key);
|
|
844
|
+
}
|
|
845
|
+
const schema = {
|
|
846
|
+
type: "object",
|
|
847
|
+
properties
|
|
848
|
+
};
|
|
849
|
+
if (required.length) schema.required = required;
|
|
850
|
+
return schema;
|
|
851
|
+
}
|
|
852
|
+
case "array": {
|
|
853
|
+
const arr = t;
|
|
854
|
+
const schema = {
|
|
855
|
+
type: "array",
|
|
856
|
+
items: build(arr.of)
|
|
857
|
+
};
|
|
858
|
+
const minLength = meta.get("expect.minLength");
|
|
859
|
+
if (typeof minLength === "number") schema.minItems = minLength;
|
|
860
|
+
const maxLength = meta.get("expect.maxLength");
|
|
861
|
+
if (typeof maxLength === "number") schema.maxItems = maxLength;
|
|
862
|
+
return schema;
|
|
863
|
+
}
|
|
864
|
+
case "union": {
|
|
865
|
+
const grp = t;
|
|
866
|
+
return { anyOf: grp.items.map(build) };
|
|
867
|
+
}
|
|
868
|
+
case "intersection": {
|
|
869
|
+
const grp = t;
|
|
870
|
+
return { allOf: grp.items.map(build) };
|
|
871
|
+
}
|
|
872
|
+
case "tuple": {
|
|
873
|
+
const grp = t;
|
|
874
|
+
return {
|
|
875
|
+
type: "array",
|
|
876
|
+
items: grp.items.map(build),
|
|
877
|
+
additionalItems: false
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
case "": {
|
|
881
|
+
const fin = t;
|
|
882
|
+
const schema = {};
|
|
883
|
+
if (fin.value !== undefined) schema.const = fin.value;
|
|
884
|
+
if (fin.designType && fin.designType !== "any") {
|
|
885
|
+
schema.type = fin.designType === "undefined" ? "null" : fin.designType;
|
|
886
|
+
if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
|
|
887
|
+
}
|
|
888
|
+
if (schema.type === "string") {
|
|
889
|
+
const minLength = meta.get("expect.minLength");
|
|
890
|
+
if (typeof minLength === "number") schema.minLength = minLength;
|
|
891
|
+
const maxLength = meta.get("expect.maxLength");
|
|
892
|
+
if (typeof maxLength === "number") schema.maxLength = maxLength;
|
|
893
|
+
const patterns = meta.get("expect.pattern");
|
|
894
|
+
if (patterns?.length) if (patterns.length === 1) schema.pattern = patterns[0].pattern;
|
|
895
|
+
else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
|
|
896
|
+
}
|
|
897
|
+
if (schema.type === "number" || schema.type === "integer") {
|
|
898
|
+
const min = meta.get("expect.min");
|
|
899
|
+
if (typeof min === "number") schema.minimum = min;
|
|
900
|
+
const max = meta.get("expect.max");
|
|
901
|
+
if (typeof max === "number") schema.maximum = max;
|
|
902
|
+
}
|
|
903
|
+
return schema;
|
|
904
|
+
}
|
|
905
|
+
default: return {};
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
return build(type);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
//#endregion
|
|
912
|
+
//#region packages/typescript/src/codegen/js-renderer.ts
|
|
913
|
+
function _define_property(obj, key, value) {
|
|
914
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
915
|
+
value,
|
|
916
|
+
enumerable: true,
|
|
917
|
+
configurable: true,
|
|
918
|
+
writable: true
|
|
919
|
+
});
|
|
920
|
+
else obj[key] = value;
|
|
921
|
+
return obj;
|
|
922
|
+
}
|
|
923
|
+
var JsRenderer = class extends BaseRenderer {
|
|
924
|
+
pre() {
|
|
925
|
+
this.writeln("// prettier-ignore-start");
|
|
926
|
+
this.writeln("/* eslint-disable */");
|
|
927
|
+
const imports = ["defineAnnotatedType as $"];
|
|
928
|
+
if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
|
|
929
|
+
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript"`);
|
|
930
|
+
}
|
|
931
|
+
post() {
|
|
932
|
+
for (const node of this.postAnnotate) {
|
|
933
|
+
this.annotateType(node.getDefinition(), node.id);
|
|
934
|
+
this.indent().defineMetadata(node).unindent();
|
|
935
|
+
this.writeln();
|
|
936
|
+
}
|
|
937
|
+
this.writeln("// prettier-ignore-end");
|
|
938
|
+
super.post();
|
|
939
|
+
}
|
|
940
|
+
renderInterface(node) {
|
|
941
|
+
this.writeln();
|
|
942
|
+
const exported = node.token("export")?.text === "export";
|
|
943
|
+
this.write(exported ? "export " : "");
|
|
944
|
+
this.write(`class ${node.id} `);
|
|
945
|
+
this.blockln("{}");
|
|
946
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
947
|
+
this.writeln("static type = {}");
|
|
948
|
+
this.writeln("static metadata = new Map()");
|
|
949
|
+
if (this.opts?.preRenderJsonSchema) {
|
|
950
|
+
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
951
|
+
this.writeln(`static _jsonSchema = ${schema}`);
|
|
952
|
+
this.writeln("static toJsonSchema() {");
|
|
953
|
+
this.indent().writeln("return this._jsonSchema").unindent();
|
|
954
|
+
this.writeln("}");
|
|
955
|
+
} else {
|
|
956
|
+
this.writeln("static _jsonSchema");
|
|
957
|
+
this.writeln("static toJsonSchema() {");
|
|
958
|
+
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
959
|
+
this.writeln("}");
|
|
960
|
+
}
|
|
961
|
+
this.popln();
|
|
962
|
+
this.postAnnotate.push(node);
|
|
963
|
+
this.writeln();
|
|
964
|
+
}
|
|
965
|
+
renderType(node) {
|
|
966
|
+
this.writeln();
|
|
967
|
+
const exported = node.token("export")?.text === "export";
|
|
968
|
+
this.write(exported ? "export " : "");
|
|
969
|
+
this.write(`class ${node.id} `);
|
|
970
|
+
this.blockln("{}");
|
|
971
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
972
|
+
this.writeln("static type = {}");
|
|
973
|
+
this.writeln("static metadata = new Map()");
|
|
974
|
+
if (this.opts?.jsonSchema) if (typeof this.opts.jsonSchema === "object" && this.opts.jsonSchema.preRender) {
|
|
975
|
+
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
976
|
+
this.writeln(`static _jsonSchema = ${schema}`);
|
|
977
|
+
this.writeln("static toJsonSchema() {");
|
|
978
|
+
this.indent().writeln("return this._jsonSchema").unindent();
|
|
979
|
+
this.writeln("}");
|
|
980
|
+
} else {
|
|
981
|
+
this.writeln("static _jsonSchema");
|
|
982
|
+
this.writeln("static toJsonSchema() {");
|
|
983
|
+
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
984
|
+
this.writeln("}");
|
|
985
|
+
}
|
|
986
|
+
this.popln();
|
|
987
|
+
this.postAnnotate.push(node);
|
|
988
|
+
this.writeln();
|
|
989
|
+
}
|
|
990
|
+
toAnnotatedType(node) {
|
|
991
|
+
return this.toAnnotatedHandle(node).$type;
|
|
992
|
+
}
|
|
993
|
+
toAnnotatedHandle(node, skipAnnotations = false) {
|
|
994
|
+
if (!node) return defineAnnotatedType();
|
|
995
|
+
switch (node.entity) {
|
|
996
|
+
case "interface":
|
|
997
|
+
case "type": {
|
|
998
|
+
const def = node.getDefinition();
|
|
999
|
+
const handle = this.toAnnotatedHandle(def, true);
|
|
1000
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1001
|
+
}
|
|
1002
|
+
case "prop": {
|
|
1003
|
+
const prop = node;
|
|
1004
|
+
const def = prop.getDefinition();
|
|
1005
|
+
const handle = this.toAnnotatedHandle(def, true);
|
|
1006
|
+
if (!skipAnnotations) {
|
|
1007
|
+
this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(prop));
|
|
1008
|
+
if (prop.token("optional")) handle.optional();
|
|
1009
|
+
}
|
|
1010
|
+
return handle;
|
|
1011
|
+
}
|
|
1012
|
+
case "ref": {
|
|
1013
|
+
const ref = node;
|
|
1014
|
+
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1015
|
+
const handle = this.toAnnotatedHandle(decl, true);
|
|
1016
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1017
|
+
}
|
|
1018
|
+
case "primitive": {
|
|
1019
|
+
const prim = node;
|
|
1020
|
+
const handle = defineAnnotatedType();
|
|
1021
|
+
handle.designType(prim.id === "never" ? "never" : prim.config.type);
|
|
1022
|
+
if (!skipAnnotations) this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1023
|
+
return handle;
|
|
1024
|
+
}
|
|
1025
|
+
case "const": {
|
|
1026
|
+
const c = node;
|
|
1027
|
+
const handle = defineAnnotatedType();
|
|
1028
|
+
const t = c.token("identifier")?.type;
|
|
1029
|
+
handle.designType(t === "number" ? "number" : "string");
|
|
1030
|
+
handle.value(t === "number" ? Number(c.id) : c.id);
|
|
1031
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1032
|
+
}
|
|
1033
|
+
case "structure": {
|
|
1034
|
+
const struct = node;
|
|
1035
|
+
const handle = defineAnnotatedType("object");
|
|
1036
|
+
for (const prop of Array.from(struct.props.values())) {
|
|
1037
|
+
const propHandle = this.toAnnotatedHandle(prop);
|
|
1038
|
+
const pattern = prop.token("identifier")?.pattern;
|
|
1039
|
+
if (pattern) handle.propPattern(pattern, propHandle.$type);
|
|
1040
|
+
else handle.prop(prop.id, propHandle.$type);
|
|
1041
|
+
}
|
|
1042
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1043
|
+
}
|
|
1044
|
+
case "group": {
|
|
1045
|
+
const group = node;
|
|
1046
|
+
const kind = group.op === "|" ? "union" : "intersection";
|
|
1047
|
+
const handle = defineAnnotatedType(kind);
|
|
1048
|
+
for (const item of group.unwrap()) handle.item(this.toAnnotatedHandle(item).$type);
|
|
1049
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1050
|
+
}
|
|
1051
|
+
case "tuple": {
|
|
1052
|
+
const group = node;
|
|
1053
|
+
const handle = defineAnnotatedType("tuple");
|
|
1054
|
+
for (const item of group.unwrap()) handle.item(this.toAnnotatedHandle(item).$type);
|
|
1055
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1056
|
+
}
|
|
1057
|
+
case "array": {
|
|
1058
|
+
const arr = node;
|
|
1059
|
+
const handle = defineAnnotatedType("array");
|
|
1060
|
+
handle.of(this.toAnnotatedHandle(arr.getDefinition()).$type);
|
|
1061
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1062
|
+
}
|
|
1063
|
+
default: {
|
|
1064
|
+
const handle = defineAnnotatedType();
|
|
1065
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
applyExpectAnnotations(handle, annotations) {
|
|
1070
|
+
annotations?.forEach((a) => {
|
|
1071
|
+
switch (a.name) {
|
|
1072
|
+
case "expect.minLength":
|
|
1073
|
+
case "expect.maxLength":
|
|
1074
|
+
case "expect.min":
|
|
1075
|
+
case "expect.max":
|
|
1076
|
+
if (a.args[0]) handle.annotate(a.name, Number(a.args[0].text));
|
|
1077
|
+
break;
|
|
1078
|
+
case "expect.pattern":
|
|
1079
|
+
handle.annotate(a.name, {
|
|
1080
|
+
pattern: a.args[0]?.text || "",
|
|
1081
|
+
flags: a.args[1]?.text,
|
|
1082
|
+
message: a.args[2]?.text
|
|
1083
|
+
}, true);
|
|
1084
|
+
break;
|
|
1085
|
+
case "expect.int":
|
|
1086
|
+
handle.annotate(a.name, true);
|
|
1087
|
+
break;
|
|
1088
|
+
default:
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
return handle;
|
|
1092
|
+
}
|
|
1093
|
+
annotateType(_node, name) {
|
|
1094
|
+
if (!_node) return this;
|
|
1095
|
+
const node = this.doc.mergeIntersection(_node);
|
|
1096
|
+
let kind = node.entity;
|
|
1097
|
+
switch (node.entity) {
|
|
1098
|
+
case "ref": {
|
|
1099
|
+
const ref = node;
|
|
1100
|
+
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1101
|
+
if (isPrimitive(decl)) {
|
|
1102
|
+
this.annotateType(decl, name);
|
|
1103
|
+
return this;
|
|
1104
|
+
}
|
|
1105
|
+
const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
|
|
1106
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`).unindent();
|
|
1107
|
+
return this;
|
|
1108
|
+
}
|
|
1109
|
+
case "primitive": {
|
|
1110
|
+
this.definePrimitive(node, name);
|
|
1111
|
+
return this;
|
|
1112
|
+
}
|
|
1113
|
+
case "const": {
|
|
1114
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().defineConst(node).unindent();
|
|
1115
|
+
return this;
|
|
1116
|
+
}
|
|
1117
|
+
case "structure": {
|
|
1118
|
+
this.writeln(`$("object"${name ? `, ${name}` : ""})`).indent().defineObject(node).unindent();
|
|
1119
|
+
return this;
|
|
1120
|
+
}
|
|
1121
|
+
case "group": {
|
|
1122
|
+
kind = node.op === "|" ? "union" : "intersection";
|
|
1123
|
+
this.writeln(`$("${kind}"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
1124
|
+
return this;
|
|
1125
|
+
}
|
|
1126
|
+
case "tuple": {
|
|
1127
|
+
this.writeln(`$("tuple"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
1128
|
+
return this;
|
|
1129
|
+
}
|
|
1130
|
+
case "array": {
|
|
1131
|
+
this.writeln(`$("array"${name ? `, ${name}` : ""})`).indent().defineArray(node).unindent();
|
|
1132
|
+
return this;
|
|
1133
|
+
}
|
|
1134
|
+
default: {
|
|
1135
|
+
console.log("!!!!!!! UNKNOWN ", node.entity);
|
|
1136
|
+
return this;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
defineConst(node) {
|
|
1141
|
+
const t = node.token("identifier")?.type;
|
|
1142
|
+
const designType = t === "text" ? "string" : t === "number" ? "number" : "unknown";
|
|
1143
|
+
this.writeln(`.designType("${escapeQuotes(designType)}")`);
|
|
1144
|
+
this.writeln(`.value(${t === "text" ? `"${escapeQuotes(node.id)}"` : node.id})`);
|
|
1145
|
+
return this;
|
|
1146
|
+
}
|
|
1147
|
+
definePrimitive(node, name) {
|
|
1148
|
+
this.renderPrimitiveDef(node.id === "never" ? "never" : node.config.type, name);
|
|
1149
|
+
this.writeln(` .tags(${Array.from(node.tags).map((f) => `"${escapeQuotes(f)}"`).join(", ")})`);
|
|
1150
|
+
return this;
|
|
1151
|
+
}
|
|
1152
|
+
renderPrimitiveDef(def, name) {
|
|
1153
|
+
const d = (t) => [`"${t || ""}"`, name].filter(Boolean).join(", ").replace(/^""$/, "");
|
|
1154
|
+
if (!def) return this.writeln(`$(${d()}).designType("any")`);
|
|
1155
|
+
if (typeof def === "string") return this.writeln(`$(${d()}).designType("${def === "void" ? "undefined" : def}")`);
|
|
1156
|
+
switch (def.kind) {
|
|
1157
|
+
case "final": return this.writeln(`$(${d()}).designType("${def.value === "void" ? "undefined" : def.value}")`);
|
|
1158
|
+
case "union":
|
|
1159
|
+
case "intersection":
|
|
1160
|
+
case "tuple":
|
|
1161
|
+
this.writeln(`$(${d(def.kind)})`);
|
|
1162
|
+
this.indent();
|
|
1163
|
+
for (const itemDef of def.items) {
|
|
1164
|
+
this.write(`.item(`);
|
|
1165
|
+
this.indent();
|
|
1166
|
+
this.renderPrimitiveDef(itemDef);
|
|
1167
|
+
this.writeln(".$type");
|
|
1168
|
+
this.unindent();
|
|
1169
|
+
this.write(`)`);
|
|
1170
|
+
}
|
|
1171
|
+
this.unindent();
|
|
1172
|
+
return;
|
|
1173
|
+
case "array":
|
|
1174
|
+
this.writeln(`$(${d("array")})`);
|
|
1175
|
+
this.indent();
|
|
1176
|
+
this.write(".of(");
|
|
1177
|
+
this.indent();
|
|
1178
|
+
this.renderPrimitiveDef(def.of);
|
|
1179
|
+
this.writeln(`.$type`);
|
|
1180
|
+
this.unindent();
|
|
1181
|
+
this.writeln(`)`);
|
|
1182
|
+
this.unindent();
|
|
1183
|
+
return;
|
|
1184
|
+
case "object":
|
|
1185
|
+
this.writeln(`$(${d("object")})`);
|
|
1186
|
+
this.indent();
|
|
1187
|
+
for (const [key, propDef] of Object.entries(def.props)) {
|
|
1188
|
+
const optional = typeof propDef === "object" && propDef.optional;
|
|
1189
|
+
this.writeln(`.prop(`);
|
|
1190
|
+
this.indent();
|
|
1191
|
+
this.writeln(`"${escapeQuotes(key)}",`);
|
|
1192
|
+
this.renderPrimitiveDef(propDef);
|
|
1193
|
+
if (optional) this.writeln(".optional()");
|
|
1194
|
+
this.writeln(".$type");
|
|
1195
|
+
this.unindent();
|
|
1196
|
+
this.write(`)`);
|
|
1197
|
+
}
|
|
1198
|
+
for (const [key, propDef] of Object.entries(def.propsPatterns)) {
|
|
1199
|
+
const optional = typeof propDef === "object" && propDef.optional;
|
|
1200
|
+
this.writeln(`.propPattern(`);
|
|
1201
|
+
this.indent();
|
|
1202
|
+
this.writeln(`${key},`);
|
|
1203
|
+
this.renderPrimitiveDef(propDef);
|
|
1204
|
+
if (optional) this.writeln(".optional()");
|
|
1205
|
+
this.writeln(".$type");
|
|
1206
|
+
this.unindent();
|
|
1207
|
+
this.write(`)`);
|
|
1208
|
+
}
|
|
1209
|
+
this.unindent();
|
|
1210
|
+
return;
|
|
1211
|
+
default: return this.writeln(`$(${d()}).designType("any")`);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
defineObject(node) {
|
|
1215
|
+
const props = Array.from(node.props.values());
|
|
1216
|
+
for (const prop of props) {
|
|
1217
|
+
const pattern = prop.token("identifier")?.pattern;
|
|
1218
|
+
const optional = !!prop.token("optional");
|
|
1219
|
+
if (pattern) {
|
|
1220
|
+
this.writeln(`.propPattern(`);
|
|
1221
|
+
this.indent();
|
|
1222
|
+
this.writeln(`/${pattern.source}/${pattern.flags},`);
|
|
1223
|
+
} else {
|
|
1224
|
+
this.writeln(`.prop(`);
|
|
1225
|
+
this.indent();
|
|
1226
|
+
this.writeln(`"${escapeQuotes(prop.id)}",`);
|
|
1227
|
+
}
|
|
1228
|
+
this.annotateType(prop.getDefinition());
|
|
1229
|
+
this.indent().defineMetadata(prop).unindent();
|
|
1230
|
+
if (optional) this.writeln(" .optional()");
|
|
1231
|
+
this.writeln(" .$type");
|
|
1232
|
+
this.unindent();
|
|
1233
|
+
this.write(`)`);
|
|
1234
|
+
}
|
|
1235
|
+
this.writeln();
|
|
1236
|
+
return this;
|
|
1237
|
+
}
|
|
1238
|
+
defineGroup(node) {
|
|
1239
|
+
const items = node.unwrap();
|
|
1240
|
+
for (const item of items) this.write(".item(").indent().annotateType(item).write(" .$type").writeln(`)`).unindent();
|
|
1241
|
+
return this;
|
|
1242
|
+
}
|
|
1243
|
+
defineArray(node) {
|
|
1244
|
+
this.write(".of(").indent().annotateType(node.getDefinition()).write(" .$type").writeln(`)`).unindent();
|
|
1245
|
+
return this;
|
|
1246
|
+
}
|
|
1247
|
+
defineMetadata(node) {
|
|
1248
|
+
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1249
|
+
annotations?.forEach((an) => {
|
|
1250
|
+
this.resolveAnnotationValue(node, an);
|
|
1251
|
+
});
|
|
1252
|
+
return this;
|
|
1253
|
+
}
|
|
1254
|
+
resolveAnnotationValue(node, an) {
|
|
1255
|
+
const spec = this.doc.resolveAnnotation(an.name);
|
|
1256
|
+
let targetValue = "true";
|
|
1257
|
+
let multiple = false;
|
|
1258
|
+
if (spec) {
|
|
1259
|
+
multiple = spec.config.multiple;
|
|
1260
|
+
const length = spec.arguments.length;
|
|
1261
|
+
if (length !== 0) if (Array.isArray(spec.config.argument)) {
|
|
1262
|
+
targetValue = "{ ";
|
|
1263
|
+
let i = 0;
|
|
1264
|
+
for (const aSpec of spec.arguments) {
|
|
1265
|
+
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
1266
|
+
else {}
|
|
1267
|
+
i++;
|
|
1268
|
+
}
|
|
1269
|
+
targetValue += "}";
|
|
1270
|
+
} else {
|
|
1271
|
+
const aSpec = spec.arguments[0];
|
|
1272
|
+
if (an.args[0]) targetValue = aSpec.type === "string" ? `"${escapeQuotes(an.args[0]?.text)}"` : an.args[0]?.text;
|
|
1273
|
+
else targetValue = "true";
|
|
1274
|
+
}
|
|
1275
|
+
} else {
|
|
1276
|
+
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1277
|
+
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1278
|
+
}
|
|
1279
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue}, true)`);
|
|
1280
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue})`);
|
|
1281
|
+
}
|
|
1282
|
+
constructor(doc, opts) {
|
|
1283
|
+
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1284
|
+
}
|
|
1285
|
+
};
|
|
1286
|
+
|
|
1287
|
+
//#endregion
|
|
1288
|
+
//#region packages/typescript/src/plugin.ts
|
|
1289
|
+
const tsPlugin = (opts) => {
|
|
1290
|
+
return {
|
|
1291
|
+
name: "typesccript",
|
|
1292
|
+
render(doc, format) {
|
|
1293
|
+
if (format === "dts") return [{
|
|
1294
|
+
fileName: `${doc.name}.d.ts`,
|
|
1295
|
+
content: new TypeRenderer(doc, opts).render()
|
|
1296
|
+
}];
|
|
1297
|
+
if (format === "js") return [{
|
|
1298
|
+
fileName: `${doc.name}.js`,
|
|
1299
|
+
content: new JsRenderer(doc, opts).render()
|
|
1300
|
+
}];
|
|
1301
|
+
},
|
|
1302
|
+
async buildEnd(output, format, repo) {
|
|
1303
|
+
if (format === "dts") {
|
|
1304
|
+
const annotations = await repo.getUsedAnnotations();
|
|
1305
|
+
const tags = await repo.getPrimitivesTags() || new Set();
|
|
1306
|
+
let rendered = [];
|
|
1307
|
+
for (const [key, val] of Object.entries(annotations)) {
|
|
1308
|
+
const multiple = val.multiple;
|
|
1309
|
+
let typeLine = Array.from(val.types).map((t) => {
|
|
1310
|
+
if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
|
|
1311
|
+
else return t.optional ? `${t.type} | true` : t.type;
|
|
1312
|
+
}).join(" | ");
|
|
1313
|
+
rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
|
|
1314
|
+
}
|
|
1315
|
+
let renderedTags = Array.from(tags).map((f) => `"${escapeQuotes(f)}"`).join(" | ");
|
|
1316
|
+
output.push({
|
|
1317
|
+
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",
|
|
1318
|
+
fileName: "atscript.d.ts",
|
|
1319
|
+
source: "",
|
|
1320
|
+
target: path.join(repo.root, "atscript.d.ts")
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
};
|
|
1326
|
+
|
|
1103
1327
|
//#endregion
|
|
1104
1328
|
//#region packages/typescript/src/index.ts
|
|
1105
1329
|
var src_default = tsPlugin;
|
|
1106
1330
|
|
|
1107
1331
|
//#endregion
|
|
1108
|
-
export { Validator, ValidatorError, src_default as default, defineAnnotatedType, isAnnotatedType, isAnnotatedTypeOfPrimitive };
|
|
1332
|
+
export { Validator, ValidatorError, buildJsonSchema, src_default as default, defineAnnotatedType, isAnnotatedType, isAnnotatedTypeOfPrimitive };
|