@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.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,
|
|
@@ -127,7 +127,7 @@ var BaseRenderer = class extends CodePrinter {
|
|
|
127
127
|
renderInterface(node) {}
|
|
128
128
|
renderType(node) {}
|
|
129
129
|
transformFromPath(path$1) {
|
|
130
|
-
return path$1
|
|
130
|
+
return `${path$1}.as`;
|
|
131
131
|
}
|
|
132
132
|
renderImport(node) {
|
|
133
133
|
const def = node.getDefinition();
|
|
@@ -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,7 +182,17 @@ function escapeQuotes(str) {
|
|
|
182
182
|
|
|
183
183
|
//#endregion
|
|
184
184
|
//#region packages/typescript/src/codegen/type-renderer.ts
|
|
185
|
-
|
|
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
|
+
}
|
|
195
|
+
var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
186
196
|
pre() {
|
|
187
197
|
this.writeln("// prettier-ignore-start");
|
|
188
198
|
this.writeln("/* eslint-disable */");
|
|
@@ -197,6 +207,11 @@ var TypeRenderer = class extends BaseRenderer {
|
|
|
197
207
|
post() {
|
|
198
208
|
this.writeln("// prettier-ignore-end");
|
|
199
209
|
}
|
|
210
|
+
renderTypeDefString(def) {
|
|
211
|
+
const newThis = new TypeRenderer(this.doc, this.opts);
|
|
212
|
+
newThis.renderTypeDef(def);
|
|
213
|
+
return newThis.toString();
|
|
214
|
+
}
|
|
200
215
|
renderTypeDef(def) {
|
|
201
216
|
if (!def) {
|
|
202
217
|
this.write("unknown");
|
|
@@ -245,33 +260,33 @@ var TypeRenderer = class extends BaseRenderer {
|
|
|
245
260
|
renderStructure(struct, asClass) {
|
|
246
261
|
this.blockln("{}");
|
|
247
262
|
const patterns = [];
|
|
248
|
-
|
|
263
|
+
const propsDefs = new Set();
|
|
249
264
|
for (const prop of Array.from(struct.props.values())) {
|
|
250
265
|
if (prop.token("identifier")?.pattern) {
|
|
251
266
|
patterns.push(prop);
|
|
252
267
|
continue;
|
|
253
268
|
}
|
|
254
|
-
hasProp = true;
|
|
255
269
|
const optional = !!prop.token("optional");
|
|
256
270
|
this.write(wrapProp(prop.id), optional ? "?" : "", ": ");
|
|
257
|
-
this.
|
|
258
|
-
|
|
271
|
+
const renderedDef = this.renderTypeDefString(prop.getDefinition());
|
|
272
|
+
propsDefs.add(renderedDef);
|
|
273
|
+
renderedDef.split("\n").forEach((l) => this.writeln(l));
|
|
259
274
|
}
|
|
260
275
|
if (patterns.length) {
|
|
261
276
|
this.write(`[key: string]: `);
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
277
|
+
if (patterns.length > 0) {
|
|
278
|
+
for (const prop of patterns) propsDefs.add(this.renderTypeDefString(prop.getDefinition()));
|
|
279
|
+
const defs = Array.from(propsDefs);
|
|
280
|
+
if (defs.length > 1) {
|
|
281
|
+
this.indent();
|
|
282
|
+
for (const def of defs) {
|
|
283
|
+
this.writeln();
|
|
284
|
+
this.write("| ");
|
|
285
|
+
def.split("\n").forEach((l) => this.write(l.trim()));
|
|
286
|
+
}
|
|
287
|
+
this.unindent();
|
|
269
288
|
this.writeln();
|
|
270
|
-
|
|
271
|
-
this.renderTypeDef(prop.getDefinition());
|
|
272
|
-
}
|
|
273
|
-
this.unindent();
|
|
274
|
-
this.writeln();
|
|
289
|
+
} else defs[0].split("\n").forEach((l) => this.writeln(l));
|
|
275
290
|
}
|
|
276
291
|
}
|
|
277
292
|
if (asClass) {
|
|
@@ -279,6 +294,7 @@ else if (patterns.length === 1) {
|
|
|
279
294
|
this.writeln(`static type: TAtscriptTypeObject<keyof ${asClass}>`);
|
|
280
295
|
this.writeln(`static metadata: TMetadataMap<AtscriptMetadata>`);
|
|
281
296
|
this.writeln(`static validator: <TT extends TAtscriptAnnotatedTypeConstructor = ${asClass}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
|
|
297
|
+
this.writeln("static toJsonSchema: () => any");
|
|
282
298
|
}
|
|
283
299
|
this.pop();
|
|
284
300
|
}
|
|
@@ -321,6 +337,7 @@ else if (isPrimitive(realDef)) typeDef = "TAtscriptTypeFinal";
|
|
|
321
337
|
this.writeln(`const type: ${typeDef}`);
|
|
322
338
|
this.writeln(`const metadata: TMetadataMap<AtscriptMetadata>`);
|
|
323
339
|
this.writeln(`const validator: <TT extends TAtscriptAnnotatedTypeConstructor = ${node.id}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
|
|
340
|
+
this.writeln("const toJsonSchema: () => any");
|
|
324
341
|
this.popln();
|
|
325
342
|
}
|
|
326
343
|
renderJsDoc(node) {
|
|
@@ -331,6 +348,9 @@ else if (isPrimitive(realDef)) typeDef = "TAtscriptTypeFinal";
|
|
|
331
348
|
this.writeln(` * @see {@link ./${this.doc.name}${rangeStr}}`);
|
|
332
349
|
this.writeln(` */`);
|
|
333
350
|
}
|
|
351
|
+
constructor(doc, opts) {
|
|
352
|
+
super(doc), _define_property$2(this, "opts", void 0), this.opts = opts;
|
|
353
|
+
}
|
|
334
354
|
};
|
|
335
355
|
function renderPrimitiveTypeDef(def) {
|
|
336
356
|
if (!def) return "unknown";
|
|
@@ -350,7 +370,7 @@ function renderPrimitiveTypeDef(def) {
|
|
|
350
370
|
}
|
|
351
371
|
|
|
352
372
|
//#endregion
|
|
353
|
-
//#region packages/typescript/src/
|
|
373
|
+
//#region packages/typescript/src/validator.ts
|
|
354
374
|
function _define_property$1(obj, key, value) {
|
|
355
375
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
356
376
|
value,
|
|
@@ -361,352 +381,64 @@ function _define_property$1(obj, key, value) {
|
|
|
361
381
|
else obj[key] = value;
|
|
362
382
|
return obj;
|
|
363
383
|
}
|
|
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();
|
|
384
|
+
const regexCache = new Map();
|
|
385
|
+
var Validator = class {
|
|
386
|
+
isLimitExceeded() {
|
|
387
|
+
if (this.stackErrors.length > 0) return this.stackErrors[this.stackErrors.length - 1].length >= this.opts.errorLimit;
|
|
388
|
+
return this.errors.length >= this.opts.errorLimit;
|
|
378
389
|
}
|
|
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();
|
|
390
|
+
push(name) {
|
|
391
|
+
this.stackPath.push(name);
|
|
392
|
+
this.stackErrors.push([]);
|
|
391
393
|
}
|
|
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();
|
|
394
|
+
pop(saveErrors) {
|
|
395
|
+
this.stackPath.pop();
|
|
396
|
+
const popped = this.stackErrors.pop();
|
|
397
|
+
if (saveErrors && popped?.length) popped.forEach((error) => {
|
|
398
|
+
this.error(error.message, error.path, error.details);
|
|
399
|
+
});
|
|
400
|
+
return popped;
|
|
404
401
|
}
|
|
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
|
-
}
|
|
402
|
+
clear() {
|
|
403
|
+
this.stackErrors[this.stackErrors.length - 1] = [];
|
|
451
404
|
}
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
405
|
+
error(message, path$1, details) {
|
|
406
|
+
const errors = this.stackErrors[this.stackErrors.length - 1] || this.errors;
|
|
407
|
+
const error = {
|
|
408
|
+
path: path$1 || this.path,
|
|
409
|
+
message
|
|
410
|
+
};
|
|
411
|
+
if (details?.length) error.details = details;
|
|
412
|
+
errors.push(error);
|
|
459
413
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
this.writeln(` .tags(${Array.from(node.tags).map((f) => `"${escapeQuotes(f)}"`).join(", ")})`);
|
|
463
|
-
return this;
|
|
414
|
+
throw() {
|
|
415
|
+
throw new ValidatorError(this.errors);
|
|
464
416
|
}
|
|
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")`);
|
|
417
|
+
validate(value, safe) {
|
|
418
|
+
this.push("");
|
|
419
|
+
this.errors = [];
|
|
420
|
+
this.stackErrors = [];
|
|
421
|
+
const passed = this.validateSafe(this.def, value);
|
|
422
|
+
this.pop(!passed);
|
|
423
|
+
if (!passed) {
|
|
424
|
+
if (safe) return false;
|
|
425
|
+
this.throw();
|
|
525
426
|
}
|
|
427
|
+
return true;
|
|
526
428
|
}
|
|
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(`)`);
|
|
429
|
+
validateSafe(def, value) {
|
|
430
|
+
if (this.isLimitExceeded()) return false;
|
|
431
|
+
if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
|
|
432
|
+
if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.path);
|
|
433
|
+
if (def.optional && value === undefined) return true;
|
|
434
|
+
for (const plugin of this.opts.plugins) {
|
|
435
|
+
const result = plugin(this, def, value);
|
|
436
|
+
if (result === false || result === true) return result;
|
|
547
437
|
}
|
|
548
|
-
this.
|
|
549
|
-
return this;
|
|
550
|
-
}
|
|
551
|
-
defineGroup(node) {
|
|
552
|
-
const items = node.unwrap();
|
|
553
|
-
for (const item of items) this.write(".item(").indent().annotateType(item).write(" .$type").writeln(`)`).unindent();
|
|
554
|
-
return this;
|
|
438
|
+
return this.validateAnnotatedType(def, value);
|
|
555
439
|
}
|
|
556
|
-
|
|
557
|
-
this.
|
|
558
|
-
return this;
|
|
559
|
-
}
|
|
560
|
-
defineMetadata(node) {
|
|
561
|
-
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
562
|
-
annotations?.forEach((an) => {
|
|
563
|
-
this.resolveAnnotationValue(node, an);
|
|
564
|
-
});
|
|
565
|
-
return this;
|
|
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(".");
|
|
440
|
+
get path() {
|
|
441
|
+
return this.stackPath.slice(1).join(".");
|
|
710
442
|
}
|
|
711
443
|
validateAnnotatedType(def, value) {
|
|
712
444
|
switch (def.type.kind) {
|
|
@@ -947,11 +679,11 @@ else {
|
|
|
947
679
|
return true;
|
|
948
680
|
}
|
|
949
681
|
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);
|
|
682
|
+
_define_property$1(this, "def", void 0);
|
|
683
|
+
_define_property$1(this, "opts", void 0);
|
|
684
|
+
_define_property$1(this, "errors", void 0);
|
|
685
|
+
_define_property$1(this, "stackErrors", void 0);
|
|
686
|
+
_define_property$1(this, "stackPath", void 0);
|
|
955
687
|
this.def = def;
|
|
956
688
|
this.errors = [];
|
|
957
689
|
this.stackErrors = [];
|
|
@@ -967,7 +699,7 @@ else {
|
|
|
967
699
|
};
|
|
968
700
|
var ValidatorError = class extends Error {
|
|
969
701
|
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";
|
|
702
|
+
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
703
|
}
|
|
972
704
|
};
|
|
973
705
|
|
|
@@ -1100,9 +832,506 @@ function isAnnotatedTypeOfPrimitive(t) {
|
|
|
1100
832
|
return false;
|
|
1101
833
|
}
|
|
1102
834
|
|
|
835
|
+
//#endregion
|
|
836
|
+
//#region packages/typescript/src/json-schema.ts
|
|
837
|
+
function buildJsonSchema(type) {
|
|
838
|
+
const build = (def) => {
|
|
839
|
+
const t = def.type;
|
|
840
|
+
const meta = def.metadata;
|
|
841
|
+
switch (t.kind) {
|
|
842
|
+
case "object": {
|
|
843
|
+
const obj = t;
|
|
844
|
+
const properties = {};
|
|
845
|
+
const required = [];
|
|
846
|
+
for (const [key, val] of obj.props.entries()) {
|
|
847
|
+
properties[key] = build(val);
|
|
848
|
+
if (!val.optional) required.push(key);
|
|
849
|
+
}
|
|
850
|
+
const schema = {
|
|
851
|
+
type: "object",
|
|
852
|
+
properties
|
|
853
|
+
};
|
|
854
|
+
if (required.length) schema.required = required;
|
|
855
|
+
return schema;
|
|
856
|
+
}
|
|
857
|
+
case "array": {
|
|
858
|
+
const arr = t;
|
|
859
|
+
const schema = {
|
|
860
|
+
type: "array",
|
|
861
|
+
items: build(arr.of)
|
|
862
|
+
};
|
|
863
|
+
const minLength = meta.get("expect.minLength");
|
|
864
|
+
if (typeof minLength === "number") schema.minItems = minLength;
|
|
865
|
+
const maxLength = meta.get("expect.maxLength");
|
|
866
|
+
if (typeof maxLength === "number") schema.maxItems = maxLength;
|
|
867
|
+
return schema;
|
|
868
|
+
}
|
|
869
|
+
case "union": {
|
|
870
|
+
const grp = t;
|
|
871
|
+
return { anyOf: grp.items.map(build) };
|
|
872
|
+
}
|
|
873
|
+
case "intersection": {
|
|
874
|
+
const grp = t;
|
|
875
|
+
return { allOf: grp.items.map(build) };
|
|
876
|
+
}
|
|
877
|
+
case "tuple": {
|
|
878
|
+
const grp = t;
|
|
879
|
+
return {
|
|
880
|
+
type: "array",
|
|
881
|
+
items: grp.items.map(build),
|
|
882
|
+
additionalItems: false
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
case "": {
|
|
886
|
+
const fin = t;
|
|
887
|
+
const schema = {};
|
|
888
|
+
if (fin.value !== undefined) schema.const = fin.value;
|
|
889
|
+
if (fin.designType && fin.designType !== "any") {
|
|
890
|
+
schema.type = fin.designType === "undefined" ? "null" : fin.designType;
|
|
891
|
+
if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
|
|
892
|
+
}
|
|
893
|
+
if (schema.type === "string") {
|
|
894
|
+
const minLength = meta.get("expect.minLength");
|
|
895
|
+
if (typeof minLength === "number") schema.minLength = minLength;
|
|
896
|
+
const maxLength = meta.get("expect.maxLength");
|
|
897
|
+
if (typeof maxLength === "number") schema.maxLength = maxLength;
|
|
898
|
+
const patterns = meta.get("expect.pattern");
|
|
899
|
+
if (patterns?.length) if (patterns.length === 1) schema.pattern = patterns[0].pattern;
|
|
900
|
+
else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
|
|
901
|
+
}
|
|
902
|
+
if (schema.type === "number" || schema.type === "integer") {
|
|
903
|
+
const min = meta.get("expect.min");
|
|
904
|
+
if (typeof min === "number") schema.minimum = min;
|
|
905
|
+
const max = meta.get("expect.max");
|
|
906
|
+
if (typeof max === "number") schema.maximum = max;
|
|
907
|
+
}
|
|
908
|
+
return schema;
|
|
909
|
+
}
|
|
910
|
+
default: return {};
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
return build(type);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
//#endregion
|
|
917
|
+
//#region packages/typescript/src/codegen/js-renderer.ts
|
|
918
|
+
function _define_property(obj, key, value) {
|
|
919
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
920
|
+
value,
|
|
921
|
+
enumerable: true,
|
|
922
|
+
configurable: true,
|
|
923
|
+
writable: true
|
|
924
|
+
});
|
|
925
|
+
else obj[key] = value;
|
|
926
|
+
return obj;
|
|
927
|
+
}
|
|
928
|
+
var JsRenderer = class extends BaseRenderer {
|
|
929
|
+
pre() {
|
|
930
|
+
this.writeln("// prettier-ignore-start");
|
|
931
|
+
this.writeln("/* eslint-disable */");
|
|
932
|
+
const imports = ["defineAnnotatedType as $"];
|
|
933
|
+
if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
|
|
934
|
+
this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript"`);
|
|
935
|
+
}
|
|
936
|
+
post() {
|
|
937
|
+
for (const node of this.postAnnotate) {
|
|
938
|
+
this.annotateType(node.getDefinition(), node.id);
|
|
939
|
+
this.indent().defineMetadata(node).unindent();
|
|
940
|
+
this.writeln();
|
|
941
|
+
}
|
|
942
|
+
this.writeln("// prettier-ignore-end");
|
|
943
|
+
super.post();
|
|
944
|
+
}
|
|
945
|
+
renderInterface(node) {
|
|
946
|
+
this.writeln();
|
|
947
|
+
const exported = node.token("export")?.text === "export";
|
|
948
|
+
this.write(exported ? "export " : "");
|
|
949
|
+
this.write(`class ${node.id} `);
|
|
950
|
+
this.blockln("{}");
|
|
951
|
+
this.writeln("static __is_atscript_annotated_type = true");
|
|
952
|
+
this.writeln("static type = {}");
|
|
953
|
+
this.writeln("static metadata = new Map()");
|
|
954
|
+
if (this.opts?.preRenderJsonSchema) {
|
|
955
|
+
const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
|
|
956
|
+
this.writeln(`static _jsonSchema = ${schema}`);
|
|
957
|
+
this.writeln("static toJsonSchema() {");
|
|
958
|
+
this.indent().writeln("return this._jsonSchema").unindent();
|
|
959
|
+
this.writeln("}");
|
|
960
|
+
} else {
|
|
961
|
+
this.writeln("static _jsonSchema");
|
|
962
|
+
this.writeln("static toJsonSchema() {");
|
|
963
|
+
this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
|
|
964
|
+
this.writeln("}");
|
|
965
|
+
}
|
|
966
|
+
this.popln();
|
|
967
|
+
this.postAnnotate.push(node);
|
|
968
|
+
this.writeln();
|
|
969
|
+
}
|
|
970
|
+
renderType(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?.jsonSchema) if (typeof this.opts.jsonSchema === "object" && this.opts.jsonSchema.preRender) {
|
|
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
|
+
toAnnotatedType(node) {
|
|
996
|
+
return this.toAnnotatedHandle(node).$type;
|
|
997
|
+
}
|
|
998
|
+
toAnnotatedHandle(node, skipAnnotations = false) {
|
|
999
|
+
if (!node) return defineAnnotatedType();
|
|
1000
|
+
switch (node.entity) {
|
|
1001
|
+
case "interface":
|
|
1002
|
+
case "type": {
|
|
1003
|
+
const def = node.getDefinition();
|
|
1004
|
+
const handle = this.toAnnotatedHandle(def, true);
|
|
1005
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1006
|
+
}
|
|
1007
|
+
case "prop": {
|
|
1008
|
+
const prop = node;
|
|
1009
|
+
const def = prop.getDefinition();
|
|
1010
|
+
const handle = this.toAnnotatedHandle(def, true);
|
|
1011
|
+
if (!skipAnnotations) {
|
|
1012
|
+
this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(prop));
|
|
1013
|
+
if (prop.token("optional")) handle.optional();
|
|
1014
|
+
}
|
|
1015
|
+
return handle;
|
|
1016
|
+
}
|
|
1017
|
+
case "ref": {
|
|
1018
|
+
const ref = node;
|
|
1019
|
+
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1020
|
+
const handle = this.toAnnotatedHandle(decl, true);
|
|
1021
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1022
|
+
}
|
|
1023
|
+
case "primitive": {
|
|
1024
|
+
const prim = node;
|
|
1025
|
+
const handle = defineAnnotatedType();
|
|
1026
|
+
handle.designType(prim.id === "never" ? "never" : prim.config.type);
|
|
1027
|
+
if (!skipAnnotations) this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1028
|
+
return handle;
|
|
1029
|
+
}
|
|
1030
|
+
case "const": {
|
|
1031
|
+
const c = node;
|
|
1032
|
+
const handle = defineAnnotatedType();
|
|
1033
|
+
const t = c.token("identifier")?.type;
|
|
1034
|
+
handle.designType(t === "number" ? "number" : "string");
|
|
1035
|
+
handle.value(t === "number" ? Number(c.id) : c.id);
|
|
1036
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1037
|
+
}
|
|
1038
|
+
case "structure": {
|
|
1039
|
+
const struct = node;
|
|
1040
|
+
const handle = defineAnnotatedType("object");
|
|
1041
|
+
for (const prop of Array.from(struct.props.values())) {
|
|
1042
|
+
const propHandle = this.toAnnotatedHandle(prop);
|
|
1043
|
+
const pattern = prop.token("identifier")?.pattern;
|
|
1044
|
+
if (pattern) handle.propPattern(pattern, propHandle.$type);
|
|
1045
|
+
else handle.prop(prop.id, propHandle.$type);
|
|
1046
|
+
}
|
|
1047
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1048
|
+
}
|
|
1049
|
+
case "group": {
|
|
1050
|
+
const group = node;
|
|
1051
|
+
const kind = group.op === "|" ? "union" : "intersection";
|
|
1052
|
+
const handle = defineAnnotatedType(kind);
|
|
1053
|
+
for (const item of group.unwrap()) handle.item(this.toAnnotatedHandle(item).$type);
|
|
1054
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1055
|
+
}
|
|
1056
|
+
case "tuple": {
|
|
1057
|
+
const group = node;
|
|
1058
|
+
const handle = defineAnnotatedType("tuple");
|
|
1059
|
+
for (const item of group.unwrap()) handle.item(this.toAnnotatedHandle(item).$type);
|
|
1060
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1061
|
+
}
|
|
1062
|
+
case "array": {
|
|
1063
|
+
const arr = node;
|
|
1064
|
+
const handle = defineAnnotatedType("array");
|
|
1065
|
+
handle.of(this.toAnnotatedHandle(arr.getDefinition()).$type);
|
|
1066
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1067
|
+
}
|
|
1068
|
+
default: {
|
|
1069
|
+
const handle = defineAnnotatedType();
|
|
1070
|
+
return skipAnnotations ? handle : this.applyExpectAnnotations(handle, this.doc.evalAnnotationsForNode(node));
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
applyExpectAnnotations(handle, annotations) {
|
|
1075
|
+
annotations?.forEach((a) => {
|
|
1076
|
+
switch (a.name) {
|
|
1077
|
+
case "expect.minLength":
|
|
1078
|
+
case "expect.maxLength":
|
|
1079
|
+
case "expect.min":
|
|
1080
|
+
case "expect.max":
|
|
1081
|
+
if (a.args[0]) handle.annotate(a.name, Number(a.args[0].text));
|
|
1082
|
+
break;
|
|
1083
|
+
case "expect.pattern":
|
|
1084
|
+
handle.annotate(a.name, {
|
|
1085
|
+
pattern: a.args[0]?.text || "",
|
|
1086
|
+
flags: a.args[1]?.text,
|
|
1087
|
+
message: a.args[2]?.text
|
|
1088
|
+
}, true);
|
|
1089
|
+
break;
|
|
1090
|
+
case "expect.int":
|
|
1091
|
+
handle.annotate(a.name, true);
|
|
1092
|
+
break;
|
|
1093
|
+
default:
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
return handle;
|
|
1097
|
+
}
|
|
1098
|
+
annotateType(_node, name) {
|
|
1099
|
+
if (!_node) return this;
|
|
1100
|
+
const node = this.doc.mergeIntersection(_node);
|
|
1101
|
+
let kind = node.entity;
|
|
1102
|
+
switch (node.entity) {
|
|
1103
|
+
case "ref": {
|
|
1104
|
+
const ref = node;
|
|
1105
|
+
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1106
|
+
if (isPrimitive(decl)) {
|
|
1107
|
+
this.annotateType(decl, name);
|
|
1108
|
+
return this;
|
|
1109
|
+
}
|
|
1110
|
+
const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
|
|
1111
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`).unindent();
|
|
1112
|
+
return this;
|
|
1113
|
+
}
|
|
1114
|
+
case "primitive": {
|
|
1115
|
+
this.definePrimitive(node, name);
|
|
1116
|
+
return this;
|
|
1117
|
+
}
|
|
1118
|
+
case "const": {
|
|
1119
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().defineConst(node).unindent();
|
|
1120
|
+
return this;
|
|
1121
|
+
}
|
|
1122
|
+
case "structure": {
|
|
1123
|
+
this.writeln(`$("object"${name ? `, ${name}` : ""})`).indent().defineObject(node).unindent();
|
|
1124
|
+
return this;
|
|
1125
|
+
}
|
|
1126
|
+
case "group": {
|
|
1127
|
+
kind = node.op === "|" ? "union" : "intersection";
|
|
1128
|
+
this.writeln(`$("${kind}"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
1129
|
+
return this;
|
|
1130
|
+
}
|
|
1131
|
+
case "tuple": {
|
|
1132
|
+
this.writeln(`$("tuple"${name ? `, ${name}` : ""})`).indent().defineGroup(node).unindent();
|
|
1133
|
+
return this;
|
|
1134
|
+
}
|
|
1135
|
+
case "array": {
|
|
1136
|
+
this.writeln(`$("array"${name ? `, ${name}` : ""})`).indent().defineArray(node).unindent();
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
default: {
|
|
1140
|
+
console.log("!!!!!!! UNKNOWN ", node.entity);
|
|
1141
|
+
return this;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
defineConst(node) {
|
|
1146
|
+
const t = node.token("identifier")?.type;
|
|
1147
|
+
const designType = t === "text" ? "string" : t === "number" ? "number" : "unknown";
|
|
1148
|
+
this.writeln(`.designType("${escapeQuotes(designType)}")`);
|
|
1149
|
+
this.writeln(`.value(${t === "text" ? `"${escapeQuotes(node.id)}"` : node.id})`);
|
|
1150
|
+
return this;
|
|
1151
|
+
}
|
|
1152
|
+
definePrimitive(node, name) {
|
|
1153
|
+
this.renderPrimitiveDef(node.id === "never" ? "never" : node.config.type, name);
|
|
1154
|
+
this.writeln(` .tags(${Array.from(node.tags).map((f) => `"${escapeQuotes(f)}"`).join(", ")})`);
|
|
1155
|
+
return this;
|
|
1156
|
+
}
|
|
1157
|
+
renderPrimitiveDef(def, name) {
|
|
1158
|
+
const d = (t) => [`"${t || ""}"`, name].filter(Boolean).join(", ").replace(/^""$/, "");
|
|
1159
|
+
if (!def) return this.writeln(`$(${d()}).designType("any")`);
|
|
1160
|
+
if (typeof def === "string") return this.writeln(`$(${d()}).designType("${def === "void" ? "undefined" : def}")`);
|
|
1161
|
+
switch (def.kind) {
|
|
1162
|
+
case "final": return this.writeln(`$(${d()}).designType("${def.value === "void" ? "undefined" : def.value}")`);
|
|
1163
|
+
case "union":
|
|
1164
|
+
case "intersection":
|
|
1165
|
+
case "tuple":
|
|
1166
|
+
this.writeln(`$(${d(def.kind)})`);
|
|
1167
|
+
this.indent();
|
|
1168
|
+
for (const itemDef of def.items) {
|
|
1169
|
+
this.write(`.item(`);
|
|
1170
|
+
this.indent();
|
|
1171
|
+
this.renderPrimitiveDef(itemDef);
|
|
1172
|
+
this.writeln(".$type");
|
|
1173
|
+
this.unindent();
|
|
1174
|
+
this.write(`)`);
|
|
1175
|
+
}
|
|
1176
|
+
this.unindent();
|
|
1177
|
+
return;
|
|
1178
|
+
case "array":
|
|
1179
|
+
this.writeln(`$(${d("array")})`);
|
|
1180
|
+
this.indent();
|
|
1181
|
+
this.write(".of(");
|
|
1182
|
+
this.indent();
|
|
1183
|
+
this.renderPrimitiveDef(def.of);
|
|
1184
|
+
this.writeln(`.$type`);
|
|
1185
|
+
this.unindent();
|
|
1186
|
+
this.writeln(`)`);
|
|
1187
|
+
this.unindent();
|
|
1188
|
+
return;
|
|
1189
|
+
case "object":
|
|
1190
|
+
this.writeln(`$(${d("object")})`);
|
|
1191
|
+
this.indent();
|
|
1192
|
+
for (const [key, propDef] of Object.entries(def.props)) {
|
|
1193
|
+
const optional = typeof propDef === "object" && propDef.optional;
|
|
1194
|
+
this.writeln(`.prop(`);
|
|
1195
|
+
this.indent();
|
|
1196
|
+
this.writeln(`"${escapeQuotes(key)}",`);
|
|
1197
|
+
this.renderPrimitiveDef(propDef);
|
|
1198
|
+
if (optional) this.writeln(".optional()");
|
|
1199
|
+
this.writeln(".$type");
|
|
1200
|
+
this.unindent();
|
|
1201
|
+
this.write(`)`);
|
|
1202
|
+
}
|
|
1203
|
+
for (const [key, propDef] of Object.entries(def.propsPatterns)) {
|
|
1204
|
+
const optional = typeof propDef === "object" && propDef.optional;
|
|
1205
|
+
this.writeln(`.propPattern(`);
|
|
1206
|
+
this.indent();
|
|
1207
|
+
this.writeln(`${key},`);
|
|
1208
|
+
this.renderPrimitiveDef(propDef);
|
|
1209
|
+
if (optional) this.writeln(".optional()");
|
|
1210
|
+
this.writeln(".$type");
|
|
1211
|
+
this.unindent();
|
|
1212
|
+
this.write(`)`);
|
|
1213
|
+
}
|
|
1214
|
+
this.unindent();
|
|
1215
|
+
return;
|
|
1216
|
+
default: return this.writeln(`$(${d()}).designType("any")`);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
defineObject(node) {
|
|
1220
|
+
const props = Array.from(node.props.values());
|
|
1221
|
+
for (const prop of props) {
|
|
1222
|
+
const pattern = prop.token("identifier")?.pattern;
|
|
1223
|
+
const optional = !!prop.token("optional");
|
|
1224
|
+
if (pattern) {
|
|
1225
|
+
this.writeln(`.propPattern(`);
|
|
1226
|
+
this.indent();
|
|
1227
|
+
this.writeln(`/${pattern.source}/${pattern.flags},`);
|
|
1228
|
+
} else {
|
|
1229
|
+
this.writeln(`.prop(`);
|
|
1230
|
+
this.indent();
|
|
1231
|
+
this.writeln(`"${escapeQuotes(prop.id)}",`);
|
|
1232
|
+
}
|
|
1233
|
+
this.annotateType(prop.getDefinition());
|
|
1234
|
+
this.indent().defineMetadata(prop).unindent();
|
|
1235
|
+
if (optional) this.writeln(" .optional()");
|
|
1236
|
+
this.writeln(" .$type");
|
|
1237
|
+
this.unindent();
|
|
1238
|
+
this.write(`)`);
|
|
1239
|
+
}
|
|
1240
|
+
this.writeln();
|
|
1241
|
+
return this;
|
|
1242
|
+
}
|
|
1243
|
+
defineGroup(node) {
|
|
1244
|
+
const items = node.unwrap();
|
|
1245
|
+
for (const item of items) this.write(".item(").indent().annotateType(item).write(" .$type").writeln(`)`).unindent();
|
|
1246
|
+
return this;
|
|
1247
|
+
}
|
|
1248
|
+
defineArray(node) {
|
|
1249
|
+
this.write(".of(").indent().annotateType(node.getDefinition()).write(" .$type").writeln(`)`).unindent();
|
|
1250
|
+
return this;
|
|
1251
|
+
}
|
|
1252
|
+
defineMetadata(node) {
|
|
1253
|
+
const annotations = this.doc.evalAnnotationsForNode(node);
|
|
1254
|
+
annotations?.forEach((an) => {
|
|
1255
|
+
this.resolveAnnotationValue(node, an);
|
|
1256
|
+
});
|
|
1257
|
+
return this;
|
|
1258
|
+
}
|
|
1259
|
+
resolveAnnotationValue(node, an) {
|
|
1260
|
+
const spec = this.doc.resolveAnnotation(an.name);
|
|
1261
|
+
let targetValue = "true";
|
|
1262
|
+
let multiple = false;
|
|
1263
|
+
if (spec) {
|
|
1264
|
+
multiple = spec.config.multiple;
|
|
1265
|
+
const length = spec.arguments.length;
|
|
1266
|
+
if (length !== 0) if (Array.isArray(spec.config.argument)) {
|
|
1267
|
+
targetValue = "{ ";
|
|
1268
|
+
let i = 0;
|
|
1269
|
+
for (const aSpec of spec.arguments) {
|
|
1270
|
+
if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
|
|
1271
|
+
else {}
|
|
1272
|
+
i++;
|
|
1273
|
+
}
|
|
1274
|
+
targetValue += "}";
|
|
1275
|
+
} else {
|
|
1276
|
+
const aSpec = spec.arguments[0];
|
|
1277
|
+
if (an.args[0]) targetValue = aSpec.type === "string" ? `"${escapeQuotes(an.args[0]?.text)}"` : an.args[0]?.text;
|
|
1278
|
+
else targetValue = "true";
|
|
1279
|
+
}
|
|
1280
|
+
} else {
|
|
1281
|
+
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1282
|
+
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1283
|
+
}
|
|
1284
|
+
if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue}, true)`);
|
|
1285
|
+
else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${targetValue})`);
|
|
1286
|
+
}
|
|
1287
|
+
constructor(doc, opts) {
|
|
1288
|
+
super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), this.opts = opts, this.postAnnotate = [];
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1292
|
+
//#endregion
|
|
1293
|
+
//#region packages/typescript/src/plugin.ts
|
|
1294
|
+
const tsPlugin = (opts) => {
|
|
1295
|
+
return {
|
|
1296
|
+
name: "typesccript",
|
|
1297
|
+
render(doc, format) {
|
|
1298
|
+
if (format === "dts") return [{
|
|
1299
|
+
fileName: `${doc.name}.d.ts`,
|
|
1300
|
+
content: new TypeRenderer(doc, opts).render()
|
|
1301
|
+
}];
|
|
1302
|
+
if (format === "js") return [{
|
|
1303
|
+
fileName: `${doc.name}.js`,
|
|
1304
|
+
content: new JsRenderer(doc, opts).render()
|
|
1305
|
+
}];
|
|
1306
|
+
},
|
|
1307
|
+
async buildEnd(output, format, repo) {
|
|
1308
|
+
if (format === "dts") {
|
|
1309
|
+
const annotations = await repo.getUsedAnnotations();
|
|
1310
|
+
const tags = await repo.getPrimitivesTags() || new Set();
|
|
1311
|
+
let rendered = [];
|
|
1312
|
+
for (const [key, val] of Object.entries(annotations)) {
|
|
1313
|
+
const multiple = val.multiple;
|
|
1314
|
+
let typeLine = Array.from(val.types).map((t) => {
|
|
1315
|
+
if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
|
|
1316
|
+
else return t.optional ? `${t.type} | true` : t.type;
|
|
1317
|
+
}).join(" | ");
|
|
1318
|
+
rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
|
|
1319
|
+
}
|
|
1320
|
+
let renderedTags = Array.from(tags).map((f) => `"${escapeQuotes(f)}"`).join(" | ");
|
|
1321
|
+
output.push({
|
|
1322
|
+
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",
|
|
1323
|
+
fileName: "atscript.d.ts",
|
|
1324
|
+
source: "",
|
|
1325
|
+
target: path.join(repo.root, "atscript.d.ts")
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1103
1332
|
//#endregion
|
|
1104
1333
|
//#region packages/typescript/src/index.ts
|
|
1105
1334
|
var src_default = tsPlugin;
|
|
1106
1335
|
|
|
1107
1336
|
//#endregion
|
|
1108
|
-
export { Validator, ValidatorError, src_default as default, defineAnnotatedType, isAnnotatedType, isAnnotatedTypeOfPrimitive };
|
|
1337
|
+
export { Validator, ValidatorError, buildJsonSchema, src_default as default, defineAnnotatedType, isAnnotatedType, isAnnotatedTypeOfPrimitive };
|