@atscript/typescript 0.1.34 → 0.1.36

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 CHANGED
@@ -23,13 +23,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
 
24
24
  //#endregion
25
25
  const __moostjs_event_cli = __toESM(require("@moostjs/event-cli"));
26
- const fs = __toESM(require("fs"));
27
- const path = __toESM(require("path"));
28
26
  const __atscript_core = __toESM(require("@atscript/core"));
29
27
  const moost = __toESM(require("moost"));
28
+ const fs = __toESM(require("fs"));
29
+ const path = __toESM(require("path"));
30
+ const node_module = __toESM(require("node:module"));
31
+ const node_readline = __toESM(require("node:readline"));
32
+ const node_url = __toESM(require("node:url"));
30
33
 
31
34
  //#region packages/typescript/src/codegen/code-printer.ts
32
- function _define_property$5(obj, key, value) {
35
+ function _define_property$7(obj, key, value) {
33
36
  if (key in obj) Object.defineProperty(obj, key, {
34
37
  value,
35
38
  enumerable: true,
@@ -122,17 +125,17 @@ else this.write(closing);
122
125
  return " ".repeat(this.indentLevel * this.indentSize);
123
126
  }
124
127
  constructor() {
125
- _define_property$5(this, "lines", []);
126
- _define_property$5(this, "currentLine", "");
127
- _define_property$5(this, "indentLevel", 0);
128
- _define_property$5(this, "indentSize", 2);
129
- _define_property$5(this, "blockStack", []);
128
+ _define_property$7(this, "lines", []);
129
+ _define_property$7(this, "currentLine", "");
130
+ _define_property$7(this, "indentLevel", 0);
131
+ _define_property$7(this, "indentSize", 2);
132
+ _define_property$7(this, "blockStack", []);
130
133
  }
131
134
  };
132
135
 
133
136
  //#endregion
134
137
  //#region packages/typescript/src/codegen/base-renderer.ts
135
- function _define_property$4(obj, key, value) {
138
+ function _define_property$6(obj, key, value) {
136
139
  if (key in obj) Object.defineProperty(obj, key, {
137
140
  value,
138
141
  enumerable: true,
@@ -157,8 +160,8 @@ var BaseRenderer = class extends CodePrinter {
157
160
  renderInterface(node) {}
158
161
  renderType(node) {}
159
162
  renderAnnotate(node) {}
160
- transformFromPath(path$3) {
161
- return `${path$3}.as`;
163
+ transformFromPath(path$4) {
164
+ return `${path$4}.as`;
162
165
  }
163
166
  renderImport(node) {
164
167
  const def = node.getDefinition();
@@ -199,7 +202,7 @@ var BaseRenderer = class extends CodePrinter {
199
202
  }
200
203
  }
201
204
  constructor(doc) {
202
- super(), _define_property$4(this, "doc", void 0), _define_property$4(this, "_unused", void 0), this.doc = doc;
205
+ super(), _define_property$6(this, "doc", void 0), _define_property$6(this, "_unused", void 0), this.doc = doc;
203
206
  }
204
207
  };
205
208
 
@@ -216,7 +219,7 @@ function escapeQuotes(str) {
216
219
 
217
220
  //#endregion
218
221
  //#region packages/typescript/src/codegen/type-renderer.ts
219
- function _define_property$3(obj, key, value) {
222
+ function _define_property$5(obj, key, value) {
220
223
  if (key in obj) Object.defineProperty(obj, key, {
221
224
  value,
222
225
  enumerable: true,
@@ -341,8 +344,10 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
341
344
  this.writeln("static toJsonSchema: () => any");
342
345
  if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
343
346
  this.writeln("static toExampleData?: () => any");
344
- if (interfaceNode && this.hasDbTable(interfaceNode)) {
347
+ if (interfaceNode && this.hasDbEntity(interfaceNode)) {
345
348
  this.renderFlat(interfaceNode);
349
+ this.renderOwnProps(interfaceNode);
350
+ this.renderNavProps(interfaceNode);
346
351
  this.renderPk(interfaceNode);
347
352
  }
348
353
  }
@@ -433,14 +438,13 @@ else if ((0, __atscript_core.isPrimitive)(realDef)) typeDef = `TAtscriptTypeFina
433
438
  this.popln();
434
439
  }
435
440
  /**
436
- * Checks whether an interface has the `@db.table` annotation.
441
+ * Checks whether an interface is a DB entity (`@db.table` or `@db.view`).
437
442
  *
438
- * NOTE: Only `@db.table` interfaces get the `__flat` static property.
439
- * This is intentionally hardcoded `__flat` exists solely to improve
440
- * type-safety for filter expressions and `$select`/`$sort` operations
441
- * in the DB layer. Non-DB interfaces have no use for dot-notation path types.
442
- */ hasDbTable(node) {
443
- return !!node.annotations?.some((a) => a.name === "db.table");
443
+ * Only DB entities get `__flat`, `__pk`, `__ownProps`, and `__navProps` static properties.
444
+ * These exist solely to improve type-safety for filter expressions, `$select`/`$sort`,
445
+ * and `$with` operations in the DB layer.
446
+ */ hasDbEntity(node) {
447
+ return !!node.annotations?.some((a) => a.name === "db.table" || a.name === "db.view" || a.name === "db.view.for");
444
448
  }
445
449
  /**
446
450
  * Renders the `static __flat` property — a map of all dot-notation paths
@@ -457,12 +461,30 @@ else if ((0, __atscript_core.isPrimitive)(realDef)) typeDef = `TAtscriptTypeFina
457
461
  * not individually queryable)
458
462
  * - **Leaf fields** → their original TypeScript type
459
463
  */ renderFlat(node) {
460
- const flatMap = (0, __atscript_core.flattenInterfaceNode)(this.doc, node);
464
+ this.renderFlatMap("__flat", (0, __atscript_core.flattenInterfaceNode)(this.doc, node));
465
+ }
466
+ /**
467
+ * Renders the `static __ownProps` property — table-owned fields only (no nav props).
468
+ */ renderOwnProps(node) {
469
+ this.renderFlatMap("__ownProps", (0, __atscript_core.flattenInterfaceNode)(this.doc, node, { skipNavProps: true }), {
470
+ leadingNewline: true,
471
+ trailingNewline: true
472
+ });
473
+ }
474
+ /**
475
+ * Shared renderer for flat-map static properties (`__flat`, `__ownProps`).
476
+ *
477
+ * Special rendering rules:
478
+ * - **Intermediate paths** (structures, arrays of structures) → `never`
479
+ * - **`@db.json` fields** → `string` (stored as serialized JSON in DB)
480
+ * - **Leaf fields** → their original TypeScript type
481
+ */ renderFlatMap(propName, flatMap, opts) {
461
482
  if (flatMap.size === 0) return;
462
- this.write("static __flat: ");
483
+ if (opts?.leadingNewline) this.writeln();
484
+ this.write(`static ${propName}: `);
463
485
  this.blockln("{}");
464
- for (const [path$3, descriptor] of flatMap) {
465
- this.write(`"${escapeQuotes(path$3)}"`);
486
+ for (const [path$4, descriptor] of flatMap) {
487
+ this.write(`"${escapeQuotes(path$4)}"`);
466
488
  if (descriptor.optional) this.write("?");
467
489
  this.write(": ");
468
490
  if (descriptor.intermediate) this.writeln("never");
@@ -474,19 +496,46 @@ else {
474
496
  renderedDef.split("\n").forEach((l) => this.writeln(l));
475
497
  }
476
498
  }
477
- this.pop();
499
+ if (opts?.trailingNewline) this.popln();
500
+ else this.pop();
478
501
  }
479
502
  /**
480
- * Renders the `static __pk` property — the primary key type for type-safe
481
- * `deleteOne`/`findById` signatures on `AtscriptDbTable`.
503
+ * Renders the `static __navProps` property — a map of navigation property names
504
+ * to their declared TypeScript types.
482
505
  *
483
- * - **Single PK** (one `@meta.id`) `static __pk: <scalar type>`
484
- * - **Compound PK** (multiple `@meta.id`) `static __pk: { field1: Type1; field2: Type2 }`
485
- * - **No PK** → no `__pk` emitted (unless unique indexes exist)
486
- * - **Unique indexes** (`@db.index.unique`) → appended as union members
487
- * - **Mongo collection** → always includes `string` (ObjectId) in the union;
488
- * if no `@meta.id` fields, `__pk` is just `string`
489
- */ renderPk(node) {
506
+ * This enables type-safe `$with` in queries: `name` is constrained to known
507
+ * navigation property keys, and nested filter/controls are typed to the target entity.
508
+ */ renderNavProps(node) {
509
+ let struct;
510
+ if (node.hasExtends) struct = this.doc.resolveInterfaceExtends(node);
511
+ if (!struct) struct = node.getDefinition();
512
+ if (!struct || !(0, __atscript_core.isStructure)(struct)) return;
513
+ const structNode = struct;
514
+ const navProps = [];
515
+ for (const [name, prop] of structNode.props) {
516
+ if (prop.token("identifier")?.pattern) continue;
517
+ if ((0, __atscript_core.hasNavPropAnnotation)(prop)) navProps.push({
518
+ name,
519
+ prop
520
+ });
521
+ }
522
+ if (navProps.length === 0) return;
523
+ this.writeln();
524
+ this.write("static __navProps: ");
525
+ this.blockln("{}");
526
+ for (const { name, prop } of navProps) {
527
+ this.write(`"${escapeQuotes(name)}"`);
528
+ if (prop.token("optional")) this.write("?");
529
+ this.write(": ");
530
+ const propDef = prop.getDefinition();
531
+ if (propDef) {
532
+ const renderedDef = this.renderTypeDefString(propDef);
533
+ renderedDef.split("\n").forEach((l) => this.writeln(l));
534
+ } else this.writeln("unknown");
535
+ }
536
+ this.popln();
537
+ }
538
+ renderPk(node) {
490
539
  const isMongoCollection = !!node.annotations?.some((a) => a.name === "db.mongo.collection");
491
540
  let struct;
492
541
  if (node.hasExtends) struct = this.doc.resolveInterfaceExtends(node);
@@ -586,7 +635,7 @@ else if (pkProps.length === 1) {
586
635
  this.writeln(` */`);
587
636
  }
588
637
  constructor(doc, opts) {
589
- super(doc), _define_property$3(this, "opts", void 0), this.opts = opts;
638
+ super(doc), _define_property$5(this, "opts", void 0), this.opts = opts;
590
639
  }
591
640
  };
592
641
  function renderPrimitiveTypeDef(def) {
@@ -608,7 +657,7 @@ function renderPrimitiveTypeDef(def) {
608
657
 
609
658
  //#endregion
610
659
  //#region packages/typescript/src/validator.ts
611
- function _define_property$2(obj, key, value) {
660
+ function _define_property$4(obj, key, value) {
612
661
  if (key in obj) Object.defineProperty(obj, key, {
613
662
  value,
614
663
  enumerable: true,
@@ -642,14 +691,14 @@ var Validator = class {
642
691
  clear() {
643
692
  this.stackErrors[this.stackErrors.length - 1] = null;
644
693
  }
645
- error(message, path$3, details) {
694
+ error(message, path$4, details) {
646
695
  let errors = this.stackErrors[this.stackErrors.length - 1];
647
696
  if (!errors) if (this.stackErrors.length > 0) {
648
697
  errors = [];
649
698
  this.stackErrors[this.stackErrors.length - 1] = errors;
650
699
  } else errors = this.errors;
651
700
  const error = {
652
- path: path$3 || this.cachedPath,
701
+ path: path$4 || this.cachedPath,
653
702
  message
654
703
  };
655
704
  if (details?.length) error.details = details;
@@ -687,7 +736,7 @@ var Validator = class {
687
736
  if (this.isLimitExceeded()) return false;
688
737
  if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
689
738
  if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.cachedPath);
690
- if (def.optional && value === undefined) return true;
739
+ if (def.optional && (value === undefined || value === null)) return true;
691
740
  for (const plugin of this.opts.plugins) {
692
741
  const result = plugin(this, def, value);
693
742
  if (result === false || result === true) return result;
@@ -820,9 +869,9 @@ var Validator = class {
820
869
  const typeKeys = new Set();
821
870
  let skipList;
822
871
  if (this.opts.skipList) {
823
- const path$3 = this.stackPath.length > 1 ? `${this.cachedPath}.` : "";
824
- for (const item of this.opts.skipList) if (item.startsWith(path$3)) {
825
- const key = item.slice(path$3.length);
872
+ const path$4 = this.stackPath.length > 1 ? `${this.cachedPath}.` : "";
873
+ for (const item of this.opts.skipList) if (item.startsWith(path$4)) {
874
+ const key = item.slice(path$4.length);
826
875
  if (!skipList) skipList = new Set();
827
876
  skipList.add(key);
828
877
  valueKeys.delete(key);
@@ -1014,13 +1063,13 @@ else {
1014
1063
  return true;
1015
1064
  }
1016
1065
  constructor(def, opts) {
1017
- _define_property$2(this, "def", void 0);
1018
- _define_property$2(this, "opts", void 0);
1019
- /** Validation errors collected during the last {@link validate} call. */ _define_property$2(this, "errors", void 0);
1020
- _define_property$2(this, "stackErrors", void 0);
1021
- _define_property$2(this, "stackPath", void 0);
1022
- _define_property$2(this, "cachedPath", void 0);
1023
- _define_property$2(this, "context", void 0);
1066
+ _define_property$4(this, "def", void 0);
1067
+ _define_property$4(this, "opts", void 0);
1068
+ /** Validation errors collected during the last {@link validate} call. */ _define_property$4(this, "errors", void 0);
1069
+ _define_property$4(this, "stackErrors", void 0);
1070
+ _define_property$4(this, "stackPath", void 0);
1071
+ _define_property$4(this, "cachedPath", void 0);
1072
+ _define_property$4(this, "context", void 0);
1024
1073
  this.def = def;
1025
1074
  this.errors = [];
1026
1075
  this.stackErrors = [];
@@ -1037,7 +1086,7 @@ else {
1037
1086
  };
1038
1087
  var ValidatorError = class extends Error {
1039
1088
  constructor(errors) {
1040
- super(`${errors[0].path ? errors[0].path + ": " : ""}${errors[0].message}`), _define_property$2(this, "errors", void 0), _define_property$2(this, "name", void 0), this.errors = errors, this.name = "Validation Error";
1089
+ super(`${errors[0].path ? errors[0].path + ": " : ""}${errors[0].message}`), _define_property$4(this, "errors", void 0), _define_property$4(this, "name", void 0), this.errors = errors, this.name = "Validation Error";
1041
1090
  }
1042
1091
  };
1043
1092
 
@@ -1176,7 +1225,7 @@ else {
1176
1225
  let target = t;
1177
1226
  if (chain) for (const c of chain) if (target.type.kind === "object" && target.type.props.has(c)) target = target.type.props.get(c);
1178
1227
  else return t.type;
1179
- node.id = target.id || t.id;
1228
+ node.id = chain ? target.id : target.id || t.id;
1180
1229
  Object.defineProperty(node, "type", {
1181
1230
  value: target.type,
1182
1231
  writable: false,
@@ -1186,7 +1235,7 @@ else return t.type;
1186
1235
  },
1187
1236
  configurable: true
1188
1237
  });
1189
- } else throw new Error(`${type$1} is not annotated type`);
1238
+ } else throw new TypeError(`${type$1} is not annotated type`);
1190
1239
  return this;
1191
1240
  },
1192
1241
  annotate(key, value, asArray) {
@@ -1274,7 +1323,7 @@ function buildJsonSchema(type) {
1274
1323
  const required = [];
1275
1324
  for (const [key, val] of d.type.props.entries()) {
1276
1325
  if (isPhantomType(val)) continue;
1277
- properties[key] = build$1(val);
1326
+ properties[key] = build$2(val);
1278
1327
  if (!val.optional) required.push(key);
1279
1328
  }
1280
1329
  const schema$1 = {
@@ -1284,7 +1333,7 @@ function buildJsonSchema(type) {
1284
1333
  if (required.length > 0) schema$1.required = required;
1285
1334
  return schema$1;
1286
1335
  };
1287
- const build$1 = (def) => {
1336
+ const build$2 = (def) => {
1288
1337
  if (def.id && def.type.kind === "object" && def !== type) {
1289
1338
  const name = def.id;
1290
1339
  if (!defs[name]) {
@@ -1305,7 +1354,7 @@ function buildJsonSchema(type) {
1305
1354
  array(d) {
1306
1355
  const schema$1 = {
1307
1356
  type: "array",
1308
- items: build$1(d.type.of)
1357
+ items: build$2(d.type.of)
1309
1358
  };
1310
1359
  const minLength = meta.get("expect.minLength");
1311
1360
  if (minLength) schema$1.minItems = typeof minLength === "number" ? minLength : minLength.length;
@@ -1316,7 +1365,7 @@ function buildJsonSchema(type) {
1316
1365
  union(d) {
1317
1366
  const disc = detectDiscriminator(d.type.items);
1318
1367
  if (disc) {
1319
- const oneOf = d.type.items.map(build$1);
1368
+ const oneOf = d.type.items.map(build$2);
1320
1369
  const mapping = {};
1321
1370
  for (const [val, idx] of Object.entries(disc.indexMapping)) {
1322
1371
  const item = d.type.items[idx];
@@ -1330,15 +1379,15 @@ function buildJsonSchema(type) {
1330
1379
  }
1331
1380
  };
1332
1381
  }
1333
- return { anyOf: d.type.items.map(build$1) };
1382
+ return { anyOf: d.type.items.map(build$2) };
1334
1383
  },
1335
1384
  intersection(d) {
1336
- return { allOf: d.type.items.map(build$1) };
1385
+ return { allOf: d.type.items.map(build$2) };
1337
1386
  },
1338
1387
  tuple(d) {
1339
1388
  return {
1340
1389
  type: "array",
1341
- items: d.type.items.map(build$1),
1390
+ items: d.type.items.map(build$2),
1342
1391
  additionalItems: false
1343
1392
  };
1344
1393
  },
@@ -1369,7 +1418,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
1369
1418
  }
1370
1419
  });
1371
1420
  };
1372
- const schema = build$1(type);
1421
+ const schema = build$2(type);
1373
1422
  if (hasDefs) return {
1374
1423
  ...schema,
1375
1424
  $defs: defs
@@ -1379,7 +1428,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
1379
1428
 
1380
1429
  //#endregion
1381
1430
  //#region packages/typescript/src/codegen/js-renderer.ts
1382
- function _define_property$1(obj, key, value) {
1431
+ function _define_property$3(obj, key, value) {
1383
1432
  if (key in obj) Object.defineProperty(obj, key, {
1384
1433
  value,
1385
1434
  enumerable: true,
@@ -1389,6 +1438,19 @@ function _define_property$1(obj, key, value) {
1389
1438
  else obj[key] = value;
1390
1439
  return obj;
1391
1440
  }
1441
+ const QUERY_OP_MAP = {
1442
+ "=": "$eq",
1443
+ "!=": "$ne",
1444
+ ">": "$gt",
1445
+ ">=": "$gte",
1446
+ "<": "$lt",
1447
+ "<=": "$lte",
1448
+ "in": "$in",
1449
+ "not in": "$nin",
1450
+ "matches": "$regex",
1451
+ "exists": "$exists",
1452
+ "not exists": "$exists"
1453
+ };
1392
1454
  var JsRenderer = class extends BaseRenderer {
1393
1455
  pre() {
1394
1456
  this.writeln("// prettier-ignore-start");
@@ -1417,12 +1479,12 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
1417
1479
  buildAdHocMap(annotateNodes) {
1418
1480
  const map = new Map();
1419
1481
  for (const annotateNode of annotateNodes) for (const entry of annotateNode.entries) {
1420
- const path$3 = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)].join(".") : entry.id;
1482
+ const path$4 = entry.hasChain ? [entry.id, ...entry.chain.map((c) => c.text)].join(".") : entry.id;
1421
1483
  const anns = entry.annotations || [];
1422
1484
  if (anns.length > 0) {
1423
- const existing = map.get(path$3);
1485
+ const existing = map.get(path$4);
1424
1486
  if (existing) existing.push(...anns);
1425
- else map.set(path$3, [...anns]);
1487
+ else map.set(path$4, [...anns]);
1426
1488
  }
1427
1489
  }
1428
1490
  return map.size > 0 ? map : null;
@@ -1857,8 +1919,8 @@ else if (resolved && (0, __atscript_core.isPrimitive)(resolved)) {
1857
1919
  }
1858
1920
  if (annotations === undefined) annotations = this.doc.evalAnnotationsForNode(node);
1859
1921
  if (this._adHocAnnotations && this._propPath.length > 0) {
1860
- const path$3 = this._propPath.join(".");
1861
- const adHoc = this._adHocAnnotations.get(path$3);
1922
+ const path$4 = this._propPath.join(".");
1923
+ const adHoc = this._adHocAnnotations.get(path$4);
1862
1924
  if (adHoc) annotations = this.doc.mergeNodesAnnotations(annotations, adHoc);
1863
1925
  }
1864
1926
  annotations?.forEach((an) => {
@@ -1884,6 +1946,68 @@ else if (resolved && (0, __atscript_core.isPrimitive)(resolved)) {
1884
1946
  if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
1885
1947
  else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
1886
1948
  }
1949
+ emitRefValue(text) {
1950
+ const dotIdx = text.indexOf(".");
1951
+ if (dotIdx === -1) return `() => ${text}`;
1952
+ const typeName = text.slice(0, dotIdx);
1953
+ const field = text.slice(dotIdx + 1);
1954
+ return `{ type: () => ${typeName}, field: "${escapeQuotes(field)}" }`;
1955
+ }
1956
+ emitArgValue(aSpec, argToken) {
1957
+ if (aSpec.type === "ref") return this.emitRefValue(argToken.text);
1958
+ if (aSpec.type === "query" && argToken.queryNode) return this.emitQueryTree(argToken.queryNode);
1959
+ return aSpec.type === "string" ? `"${escapeQuotes(argToken.text)}"` : argToken.text;
1960
+ }
1961
+ emitQueryTree(queryNode) {
1962
+ return this.emitQueryExpr(queryNode.expression);
1963
+ }
1964
+ emitQueryExpr(node) {
1965
+ if ((0, __atscript_core.isQueryLogical)(node)) return this.emitQueryLogical(node);
1966
+ return this.emitQueryComparison(node);
1967
+ }
1968
+ emitQueryLogical(node) {
1969
+ if (node.operator === "not") return `{ "$not": ${this.emitQueryExpr(node.operands[0])} }`;
1970
+ const key = node.operator === "and" ? "$and" : "$or";
1971
+ const items = node.operands.map((op) => this.emitQueryExpr(op)).join(", ");
1972
+ return `{ "${key}": [${items}] }`;
1973
+ }
1974
+ emitQueryComparison(node) {
1975
+ const left = this.emitQueryFieldRef(node.left);
1976
+ const mappedOp = QUERY_OP_MAP[node.operator] || node.operator;
1977
+ const parts = [`left: ${left}`, `op: "${mappedOp}"`];
1978
+ if (node.right) {
1979
+ if ("fieldRef" in node.right && node.right.fieldRef) parts.push(`right: ${this.emitQueryFieldRef(node.right)}`);
1980
+ else if ("values" in node.right && node.right.values) {
1981
+ const values = node.right.values.map((v) => this.emitQueryLiteral(v)).join(", ");
1982
+ parts.push(`right: [${values}]`);
1983
+ } else if ("valueToken" in node.right) parts.push(`right: ${this.emitQueryLiteral(node.right)}`);
1984
+ } else if (node.operator === "exists") parts.push("right: true");
1985
+ else if (node.operator === "not exists") parts.push("right: false");
1986
+ return `{ ${parts.join(", ")} }`;
1987
+ }
1988
+ emitQueryFieldRef(node) {
1989
+ const parts = [];
1990
+ if (node.typeRef) parts.push(`type: () => ${node.typeRef.text}`);
1991
+ parts.push(`field: "${escapeQuotes(node.fieldRef.text)}"`);
1992
+ return `{ ${parts.join(", ")} }`;
1993
+ }
1994
+ emitQueryLiteral(node) {
1995
+ const token = node.valueToken;
1996
+ switch (token.type) {
1997
+ case "text": return `"${escapeQuotes(token.text)}"`;
1998
+ case "number": return token.text;
1999
+ case "regexp": {
2000
+ const match = /^\/(.*)\/[a-z]*$/.exec(token.text);
2001
+ return `"${escapeQuotes(match ? match[1] : token.text)}"`;
2002
+ }
2003
+ case "identifier": {
2004
+ if (token.text === "true" || token.text === "false") return token.text;
2005
+ if (token.text === "null" || token.text === "undefined") return "null";
2006
+ return token.text;
2007
+ }
2008
+ default: return token.text;
2009
+ }
2010
+ }
1887
2011
  computeAnnotationValue(node, an) {
1888
2012
  const spec = this.doc.resolveAnnotation(an.name);
1889
2013
  let targetValue = "true";
@@ -1895,13 +2019,13 @@ else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
1895
2019
  targetValue = "{ ";
1896
2020
  let i = 0;
1897
2021
  for (const aSpec of spec.arguments) {
1898
- if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${aSpec.type === "string" ? `"${escapeQuotes(an.args[i]?.text)}"` : an.args[i]?.text}${i === length - 1 ? "" : ", "} `;
2022
+ if (an.args[i]) targetValue += `${wrapProp(aSpec.name)}: ${this.emitArgValue(aSpec, an.args[i])}${i === length - 1 ? "" : ", "} `;
1899
2023
  i++;
1900
2024
  }
1901
2025
  targetValue += "}";
1902
2026
  } else {
1903
2027
  const aSpec = spec.arguments[0];
1904
- if (an.args[0]) targetValue = aSpec.type === "string" ? `"${escapeQuotes(an.args[0]?.text)}"` : an.args[0]?.text;
2028
+ if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
1905
2029
  else targetValue = "true";
1906
2030
  }
1907
2031
  } else {
@@ -2041,7 +2165,7 @@ else {
2041
2165
  return [];
2042
2166
  }
2043
2167
  constructor(doc, opts) {
2044
- super(doc), _define_property$1(this, "opts", void 0), _define_property$1(this, "postAnnotate", void 0), _define_property$1(this, "_adHocAnnotations", void 0), _define_property$1(this, "_propPath", void 0), _define_property$1(this, "typeIds", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map();
2168
+ super(doc), _define_property$3(this, "opts", void 0), _define_property$3(this, "postAnnotate", void 0), _define_property$3(this, "_adHocAnnotations", void 0), _define_property$3(this, "_propPath", void 0), _define_property$3(this, "typeIds", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map();
2045
2169
  }
2046
2170
  };
2047
2171
 
@@ -2072,8 +2196,8 @@ const tsPlugin = (opts) => {
2072
2196
  for (const [key, val] of Object.entries(annotations)) {
2073
2197
  const multiple = val.multiple;
2074
2198
  const typeLine = Array.from(val.types).map((t) => {
2075
- if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
2076
- else return t.optional ? `${t.type} | true` : t.type;
2199
+ if (t.type === "object" && "props" in t) return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
2200
+ else return "optional" in t && t.optional ? `${t.type} | true` : t.type;
2077
2201
  }).join(" | ");
2078
2202
  rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
2079
2203
  }
@@ -2089,9 +2213,35 @@ else return t.optional ? `${t.type} | true` : t.type;
2089
2213
  };
2090
2214
  };
2091
2215
 
2216
+ //#endregion
2217
+ //#region packages/typescript/src/cli/config.ts
2218
+ async function getConfig(configFile, logger) {
2219
+ const root = process.cwd();
2220
+ if (configFile) {
2221
+ const c = path.default.join(root, configFile);
2222
+ if (!(0, fs.existsSync)(c)) {
2223
+ logger.error(`Config file ${"\x1B[4m"}${configFile}${"\x1B[24m"} not found`);
2224
+ process.exit(1);
2225
+ }
2226
+ logger.log(`Using config file ${"\x1B[36m"}${configFile}${"\x1B[39m"}`);
2227
+ return (0, __atscript_core.loadConfig)(c);
2228
+ } else {
2229
+ const resolved = await (0, __atscript_core.resolveConfigFile)(root);
2230
+ if (resolved) {
2231
+ logger.log(`Using config file ${"\x1B[36m"}${resolved}${"\x1B[39m"}`);
2232
+ return (0, __atscript_core.loadConfig)(resolved);
2233
+ }
2234
+ logger.log(`No atscript config file found`);
2235
+ return {
2236
+ format: __atscript_core.DEFAULT_FORMAT,
2237
+ plugins: [tsPlugin()]
2238
+ };
2239
+ }
2240
+ }
2241
+
2092
2242
  //#endregion
2093
2243
  //#region packages/typescript/src/cli/commands.controller.ts
2094
- function _define_property(obj, key, value) {
2244
+ function _define_property$2(obj, key, value) {
2095
2245
  if (key in obj) Object.defineProperty(obj, key, {
2096
2246
  value,
2097
2247
  enumerable: true,
@@ -2101,23 +2251,23 @@ function _define_property(obj, key, value) {
2101
2251
  else obj[key] = value;
2102
2252
  return obj;
2103
2253
  }
2104
- function _ts_decorate(decorators, target, key, desc) {
2254
+ function _ts_decorate$1(decorators, target, key, desc) {
2105
2255
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2106
2256
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2107
2257
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2108
2258
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2109
2259
  }
2110
- function _ts_metadata(k, v) {
2260
+ function _ts_metadata$1(k, v) {
2111
2261
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2112
2262
  }
2113
- function _ts_param(paramIndex, decorator) {
2263
+ function _ts_param$1(paramIndex, decorator) {
2114
2264
  return function(target, key) {
2115
2265
  decorator(target, key, paramIndex);
2116
2266
  };
2117
2267
  }
2118
2268
  var Commands = class {
2119
2269
  async default(configFile, format, noEmit, skipDiag) {
2120
- const config = await this.getConfig(configFile);
2270
+ const config = await getConfig(configFile, this.logger);
2121
2271
  config.format = format || __atscript_core.DEFAULT_FORMAT;
2122
2272
  this.logger.log(`Format: ${"\x1B[36m"}${config.format}${"\x1B[39m"}`);
2123
2273
  const builder = await (0, __atscript_core.build)(config);
@@ -2146,72 +2296,361 @@ else if (m.severity === 2) warningCount++;
2146
2296
  }
2147
2297
  if (errorCount > 0) process.exit(1);
2148
2298
  }
2149
- async getConfig(configFile) {
2150
- const root = process.cwd();
2151
- if (configFile) {
2152
- const c = path.default.join(root, configFile);
2153
- if (!(0, fs.existsSync)(c)) {
2154
- this.logger.error(`Config file ${"\x1B[4m"}${configFile}${"\x1B[24m"} not found`);
2155
- process.exit(1);
2156
- }
2157
- this.logger.log(`Using config file ${"\x1B[36m"}${configFile}${"\x1B[39m"}`);
2158
- return (0, __atscript_core.loadConfig)(c);
2159
- } else {
2160
- const resolved = await (0, __atscript_core.resolveConfigFile)(root);
2161
- if (resolved) {
2162
- this.logger.log(`Using config file ${"\x1B[36m"}${resolved}${"\x1B[39m"}`);
2163
- return (0, __atscript_core.loadConfig)(resolved);
2164
- }
2165
- this.logger.log(`No atscript config file found`);
2166
- return {
2167
- format: __atscript_core.DEFAULT_FORMAT,
2168
- plugins: [tsPlugin()]
2169
- };
2170
- }
2171
- }
2172
2299
  constructor(logger) {
2173
- _define_property(this, "logger", void 0);
2300
+ _define_property$2(this, "logger", void 0);
2174
2301
  this.logger = logger;
2175
2302
  }
2176
2303
  };
2177
- _ts_decorate([
2304
+ _ts_decorate$1([
2178
2305
  (0, __moostjs_event_cli.Cli)(""),
2179
2306
  (0, moost.Description)("Builds .as files using --config and --format"),
2180
2307
  (0, __moostjs_event_cli.CliExample)("-c atscript.config.js", "Build .as files using atscript.config.js"),
2181
2308
  (0, __moostjs_event_cli.CliExample)("-f dts", "Build \"d.ts\" files for \".as\" files"),
2182
2309
  (0, __moostjs_event_cli.CliExample)("--noEmit", "Only check for errors, do not emit files"),
2183
2310
  (0, __moostjs_event_cli.CliExample)("--skipDiag", "Emit files without running diagnostics"),
2311
+ _ts_param$1(0, (0, __moostjs_event_cli.CliOption)("c", "config")),
2312
+ _ts_param$1(0, (0, moost.Optional)()),
2313
+ _ts_param$1(0, (0, moost.Description)("Path to config file")),
2314
+ _ts_param$1(1, (0, __moostjs_event_cli.CliOption)("f", "format")),
2315
+ _ts_param$1(1, (0, moost.Optional)()),
2316
+ _ts_param$1(1, (0, moost.Description)("Output format (e.g. js, dts). Omit to run all plugins with their default output.")),
2317
+ _ts_param$1(2, (0, __moostjs_event_cli.CliOption)("noEmit")),
2318
+ _ts_param$1(2, (0, moost.Optional)()),
2319
+ _ts_param$1(2, (0, moost.Description)("Only run diagnostics without emitting files")),
2320
+ _ts_param$1(3, (0, __moostjs_event_cli.CliOption)("skipDiag")),
2321
+ _ts_param$1(3, (0, moost.Optional)()),
2322
+ _ts_param$1(3, (0, moost.Description)("Skip diagnostics and always emit files")),
2323
+ _ts_metadata$1("design:type", Function),
2324
+ _ts_metadata$1("design:paramtypes", [
2325
+ String,
2326
+ String,
2327
+ Boolean,
2328
+ Boolean
2329
+ ]),
2330
+ _ts_metadata$1("design:returntype", Promise)
2331
+ ], Commands.prototype, "default", null);
2332
+ Commands = _ts_decorate$1([
2333
+ (0, moost.Controller)(),
2334
+ _ts_param$1(0, (0, moost.InjectMoostLogger)("asc")),
2335
+ _ts_metadata$1("design:type", Function),
2336
+ _ts_metadata$1("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
2337
+ ], Commands);
2338
+
2339
+ //#endregion
2340
+ //#region packages/typescript/src/cli/db-sync-printer.ts
2341
+ function _define_property$1(obj, key, value) {
2342
+ if (key in obj) Object.defineProperty(obj, key, {
2343
+ value,
2344
+ enumerable: true,
2345
+ configurable: true,
2346
+ writable: true
2347
+ });
2348
+ else obj[key] = value;
2349
+ return obj;
2350
+ }
2351
+ const DYE_COLORS = {
2352
+ green: (s) => `${"\x1B[32m"}${s}${"\x1B[39m"}`,
2353
+ red: (s) => `${"\x1B[31m"}${s}${"\x1B[39m"}`,
2354
+ cyan: (s) => `${"\x1B[36m"}${s}${"\x1B[39m"}`,
2355
+ yellow: (s) => `${"\x1B[33m"}${s}${"\x1B[39m"}`,
2356
+ bold: (s) => `${"\x1B[1m"}${s}${"\x1B[22m"}`,
2357
+ dim: (s) => `${"\x1B[2m"}${s}${"\x1B[22m"}`,
2358
+ underline: (s) => `${"\x1B[4m"}${s}${"\x1B[24m"}`
2359
+ };
2360
+ const BANNER = DYE_COLORS.cyan(`
2361
+
2362
+ #############
2363
+ #################
2364
+ %# #####
2365
+ ####
2366
+ ########## #### #######
2367
+ ############ #### ###########
2368
+ #### #### #### #### ###
2369
+ #### #### #### ######
2370
+ #### #### #### #########
2371
+ #### #### #### ######
2372
+ #### #### #### ### ####
2373
+ ############ #### ###########
2374
+ ############ #### #########
2375
+ #########
2376
+ #####
2377
+
2378
+ `);
2379
+ const PLAN_HEADER = [
2380
+ "",
2381
+ DYE_COLORS.bold("╔══════════════════════════════════════╗"),
2382
+ DYE_COLORS.bold("║ Schema Sync Plan ║"),
2383
+ DYE_COLORS.bold("╚══════════════════════════════════════╝"),
2384
+ ""
2385
+ ];
2386
+ var DbSyncPrinter = class {
2387
+ log(...args) {
2388
+ console.log(...args);
2389
+ }
2390
+ banner() {
2391
+ this.log(BANNER);
2392
+ }
2393
+ typeCount(count) {
2394
+ this.log(`Found ${this.colors.cyan(String(count))} type(s)`);
2395
+ }
2396
+ planUpToDate(plan) {
2397
+ this.log(`${this.colors.green(this.colors.bold("Schema is up to date."))}\n`);
2398
+ this.printGrouped(plan.entries, "plan");
2399
+ this.log("");
2400
+ }
2401
+ plan(plan) {
2402
+ for (const line of PLAN_HEADER) this.log(line);
2403
+ this.printGrouped(plan.entries, "plan");
2404
+ this.log("");
2405
+ }
2406
+ result(result) {
2407
+ this.log("");
2408
+ this.log(`${this.colors.green(this.colors.bold("Schema synced successfully."))} Hash: ${result.schemaHash}`);
2409
+ this.log("");
2410
+ this.printGrouped(result.entries, "result");
2411
+ this.log("");
2412
+ }
2413
+ printGrouped(entries, mode) {
2414
+ const tables = entries.filter((e) => !e.viewType);
2415
+ const views = entries.filter((e) => e.viewType);
2416
+ if (tables.length > 0) {
2417
+ this.log(this.colors.bold("Tables:"));
2418
+ for (const e of tables) for (const line of e.print(mode, this.colors)) this.log(line);
2419
+ }
2420
+ if (views.length > 0) {
2421
+ if (tables.length > 0) this.log("");
2422
+ this.log(this.colors.bold("Views:"));
2423
+ for (const e of views) for (const line of e.print(mode, this.colors)) this.log(line);
2424
+ }
2425
+ }
2426
+ constructor() {
2427
+ _define_property$1(this, "colors", DYE_COLORS);
2428
+ }
2429
+ };
2430
+
2431
+ //#endregion
2432
+ //#region packages/typescript/src/cli/db-sync.controller.ts
2433
+ function _define_property(obj, key, value) {
2434
+ if (key in obj) Object.defineProperty(obj, key, {
2435
+ value,
2436
+ enumerable: true,
2437
+ configurable: true,
2438
+ writable: true
2439
+ });
2440
+ else obj[key] = value;
2441
+ return obj;
2442
+ }
2443
+ function _ts_decorate(decorators, target, key, desc) {
2444
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2445
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2446
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2447
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2448
+ }
2449
+ function _ts_metadata(k, v) {
2450
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2451
+ }
2452
+ function _ts_param(paramIndex, decorator) {
2453
+ return function(target, key) {
2454
+ decorator(target, key, paramIndex);
2455
+ };
2456
+ }
2457
+ var DbSyncController = class {
2458
+ async dbSync(configFile, dryRun, yes, force, safe) {
2459
+ const config = await getConfig(configFile, this.logger);
2460
+ if (!config.db) {
2461
+ this.logger.error(`${"\x1B[31m"}No "db" field in atscript config. ` + `Add a db configuration to use schema sync.${"\x1B[39m"}`);
2462
+ process.exit(1);
2463
+ }
2464
+ const [dbSpace, dbTypes] = await Promise.all([this.resolveDbSpace(config.db), this.compileAndLoadTypes(config)]);
2465
+ if (dbTypes.length === 0) {
2466
+ this.logger.log(`No types with @db.table or @db.view found. Nothing to sync.`);
2467
+ return;
2468
+ }
2469
+ this.printer.typeCount(dbTypes.length);
2470
+ this.printer.banner();
2471
+ const { SchemaSync } = await this.importFromCwd("@atscript/utils-db/sync", true);
2472
+ const sync = new SchemaSync(dbSpace);
2473
+ const plan = await sync.plan(dbTypes, {
2474
+ force,
2475
+ safe
2476
+ });
2477
+ if (plan.status === "up-to-date") {
2478
+ this.printer.planUpToDate(plan);
2479
+ return;
2480
+ }
2481
+ const hasDestructive = plan.entries.some((e) => e.destructive);
2482
+ const hasChanges = plan.entries.some((e) => e.hasChanges);
2483
+ const hasErrors = plan.entries.some((e) => e.hasErrors);
2484
+ this.printer.plan(plan);
2485
+ if (hasErrors) {
2486
+ this.logger.error(`Schema has errors. Fix the issues above before syncing.`);
2487
+ process.exit(1);
2488
+ }
2489
+ if (!hasChanges) {
2490
+ if (!dryRun) await sync.run(dbTypes, {
2491
+ force: true,
2492
+ safe
2493
+ });
2494
+ return;
2495
+ }
2496
+ if (dryRun) {
2497
+ this.logger.log(`Dry run — no changes applied.`);
2498
+ return;
2499
+ }
2500
+ if (hasDestructive) {
2501
+ if (!yes) {
2502
+ const confirmed = await this.confirm("Apply these changes? (includes destructive operations)");
2503
+ if (!confirmed) {
2504
+ this.logger.log("Aborted.");
2505
+ return;
2506
+ }
2507
+ }
2508
+ } else this.logger.log(`No destructive changes, proceeding to sync...`);
2509
+ const result = await sync.run(dbTypes, {
2510
+ force: true,
2511
+ safe
2512
+ });
2513
+ this.printer.result(result);
2514
+ }
2515
+ async compileAndLoadTypes(config) {
2516
+ const buildConfig = { ...config };
2517
+ if (typeof config.db === "object" && "adapter" in config.db) {
2518
+ const dbConfig = config.db;
2519
+ if (dbConfig.include) buildConfig.include = dbConfig.include;
2520
+ if (dbConfig.exclude) buildConfig.exclude = dbConfig.exclude;
2521
+ }
2522
+ buildConfig.format = "js";
2523
+ this.logger.log(`Compiling .as files...`);
2524
+ const builder = await (0, __atscript_core.build)(buildConfig);
2525
+ const outputs = await builder.generate(buildConfig);
2526
+ const jsOutputs = outputs.filter((o) => o.fileName.endsWith(".js"));
2527
+ const tmpDir = path.default.join(process.cwd(), `.atscript-db-sync-${Date.now()}`);
2528
+ const writtenFiles = [];
2529
+ for (const o of jsOutputs) {
2530
+ const target = path.default.join(tmpDir, o.fileName.replace(/\.js$/, ".mjs"));
2531
+ (0, fs.mkdirSync)(path.default.dirname(target), { recursive: true });
2532
+ (0, fs.writeFileSync)(target, patchAsImports(o.content));
2533
+ writtenFiles.push(target);
2534
+ }
2535
+ const dbTypes = [];
2536
+ try {
2537
+ for (const file of writtenFiles) {
2538
+ const mod = await import(
2539
+ /* @vite-ignore */
2540
+ (0, node_url.pathToFileURL)(file).href
2541
+ );
2542
+ for (const exp of Object.values(mod)) if (isAnnotatedType(exp) && (exp.metadata?.has("db.table") || exp.metadata?.has("db.view"))) dbTypes.push(exp);
2543
+ }
2544
+ } catch (error) {
2545
+ this.logger.warn?.(`Could not import compiled types: ${error}`);
2546
+ } finally {
2547
+ try {
2548
+ (0, fs.rmSync)(tmpDir, {
2549
+ recursive: true,
2550
+ force: true
2551
+ });
2552
+ } catch {}
2553
+ }
2554
+ return dbTypes;
2555
+ }
2556
+ async resolveDbSpace(dbConfig) {
2557
+ if (typeof dbConfig === "function") {
2558
+ this.logger.log(`Resolving database space from callback...`);
2559
+ return await dbConfig();
2560
+ }
2561
+ const { adapter, connection, options } = dbConfig;
2562
+ this.logger.log(`Using adapter: ${"\x1B[36m"}${adapter}${"\x1B[39m"}`);
2563
+ let mod;
2564
+ try {
2565
+ mod = await this.importFromCwd(adapter);
2566
+ } catch {
2567
+ this.logger.error(`${"\x1B[31m"}Could not import adapter package "${adapter}". Is it installed?${"\x1B[39m"}`);
2568
+ process.exit(1);
2569
+ }
2570
+ if (typeof mod.createAdapter !== "function") {
2571
+ this.logger.error(`${"\x1B[31m"}Adapter package "${adapter}" does not export a createAdapter function.${"\x1B[39m"}`);
2572
+ process.exit(1);
2573
+ }
2574
+ const resolvedConnection = typeof connection === "function" ? await connection() : connection;
2575
+ return mod.createAdapter(resolvedConnection, options);
2576
+ }
2577
+ async importFromCwd(specifier, preferEsm = false) {
2578
+ const require$1 = (0, node_module.createRequire)(path.default.join(process.cwd(), "__synthetic.cjs"));
2579
+ let resolved = require$1.resolve(specifier);
2580
+ if (preferEsm) {
2581
+ const mjsPath = resolved.replace(/\.cjs$/, ".mjs");
2582
+ if ((0, fs.existsSync)(mjsPath)) resolved = mjsPath;
2583
+ }
2584
+ return import(
2585
+ /* @vite-ignore */
2586
+ (0, node_url.pathToFileURL)(resolved).href
2587
+ );
2588
+ }
2589
+ async confirm(message) {
2590
+ const rl = (0, node_readline.createInterface)({
2591
+ input: process.stdin,
2592
+ output: process.stdout
2593
+ });
2594
+ return new Promise((resolve) => {
2595
+ rl.question(`${message} [y/N] `, (answer) => {
2596
+ rl.close();
2597
+ resolve(answer.trim().toLowerCase() === "y");
2598
+ });
2599
+ });
2600
+ }
2601
+ constructor(logger) {
2602
+ _define_property(this, "logger", void 0);
2603
+ _define_property(this, "printer", void 0);
2604
+ this.logger = logger;
2605
+ this.printer = new DbSyncPrinter();
2606
+ }
2607
+ };
2608
+ _ts_decorate([
2609
+ (0, __moostjs_event_cli.Cli)("db sync"),
2610
+ (0, moost.Description)("Synchronize database schema with .as type definitions"),
2611
+ (0, __moostjs_event_cli.CliExample)("db sync", "Interactive sync — shows plan, prompts, then applies"),
2612
+ (0, __moostjs_event_cli.CliExample)("db sync --dry-run", "Show what would change without applying"),
2613
+ (0, __moostjs_event_cli.CliExample)("db sync --yes", "Skip confirmation prompt (CI mode)"),
2614
+ (0, __moostjs_event_cli.CliExample)("db sync --force", "Re-sync even if schema hash matches"),
2615
+ (0, __moostjs_event_cli.CliExample)("db sync --safe", "Skip destructive operations (column/table drops)"),
2184
2616
  _ts_param(0, (0, __moostjs_event_cli.CliOption)("c", "config")),
2185
2617
  _ts_param(0, (0, moost.Optional)()),
2186
2618
  _ts_param(0, (0, moost.Description)("Path to config file")),
2187
- _ts_param(1, (0, __moostjs_event_cli.CliOption)("f", "format")),
2619
+ _ts_param(1, (0, __moostjs_event_cli.CliOption)("dry-run")),
2188
2620
  _ts_param(1, (0, moost.Optional)()),
2189
- _ts_param(1, (0, moost.Description)("Output format (e.g. js, dts). Omit to run all plugins with their default output.")),
2190
- _ts_param(2, (0, __moostjs_event_cli.CliOption)("noEmit")),
2621
+ _ts_param(1, (0, moost.Description)("Show plan only, do not apply changes")),
2622
+ _ts_param(2, (0, __moostjs_event_cli.CliOption)("yes")),
2191
2623
  _ts_param(2, (0, moost.Optional)()),
2192
- _ts_param(2, (0, moost.Description)("Only run diagnostics without emitting files")),
2193
- _ts_param(3, (0, __moostjs_event_cli.CliOption)("skipDiag")),
2624
+ _ts_param(2, (0, moost.Description)("Skip confirmation prompt (CI mode)")),
2625
+ _ts_param(3, (0, __moostjs_event_cli.CliOption)("force")),
2194
2626
  _ts_param(3, (0, moost.Optional)()),
2195
- _ts_param(3, (0, moost.Description)("Skip diagnostics and always emit files")),
2627
+ _ts_param(3, (0, moost.Description)("Ignore schema hash, re-sync even if up-to-date")),
2628
+ _ts_param(4, (0, __moostjs_event_cli.CliOption)("safe")),
2629
+ _ts_param(4, (0, moost.Optional)()),
2630
+ _ts_param(4, (0, moost.Description)("Skip destructive operations (column/table drops)")),
2196
2631
  _ts_metadata("design:type", Function),
2197
2632
  _ts_metadata("design:paramtypes", [
2198
2633
  String,
2199
- String,
2634
+ Boolean,
2635
+ Boolean,
2200
2636
  Boolean,
2201
2637
  Boolean
2202
2638
  ]),
2203
2639
  _ts_metadata("design:returntype", Promise)
2204
- ], Commands.prototype, "default", null);
2205
- Commands = _ts_decorate([
2640
+ ], DbSyncController.prototype, "dbSync", null);
2641
+ DbSyncController = _ts_decorate([
2206
2642
  (0, moost.Controller)(),
2207
2643
  _ts_param(0, (0, moost.InjectMoostLogger)("asc")),
2208
2644
  _ts_metadata("design:type", Function),
2209
2645
  _ts_metadata("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
2210
- ], Commands);
2646
+ ], DbSyncController);
2647
+ function patchAsImports(content) {
2648
+ return content.replace(/(from\s+["'][^"']+)\.as(["'])/g, "$1.as.mjs$2");
2649
+ }
2211
2650
 
2212
2651
  //#endregion
2213
2652
  //#region packages/typescript/src/cli/cli.ts
2214
- new __moostjs_event_cli.CliApp().controllers(Commands).useHelp({ name: "asc" }).useOptions([{
2653
+ new __moostjs_event_cli.CliApp().controllers(Commands, DbSyncController).useHelp({ name: "asc" }).useOptions([{
2215
2654
  keys: ["help"],
2216
2655
  description: "Display instructions for the command."
2217
2656
  }]).start();