@atscript/typescript 0.1.33 → 0.1.35

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
 
@@ -1058,7 +1107,8 @@ function createAnnotatedTypeNode(type, metadata, opts) {
1058
1107
  metadata,
1059
1108
  validator: validatorMethod,
1060
1109
  id: opts?.id,
1061
- optional: opts?.optional
1110
+ optional: opts?.optional,
1111
+ ref: opts?.ref
1062
1112
  };
1063
1113
  }
1064
1114
  function isAnnotatedType(type) {
@@ -1135,18 +1185,57 @@ function defineAnnotatedType(_kind, base) {
1135
1185
  return this;
1136
1186
  },
1137
1187
  refTo(type$1, chain) {
1138
- if (!isAnnotatedType(type$1)) throw new Error(`${type$1} is not annotated type`);
1139
- let newBase = type$1;
1140
- const typeName = type$1.name || "Unknown";
1141
- if (chain) for (let i = 0; i < chain.length; i++) {
1142
- const c = chain[i];
1143
- if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
1188
+ if (isAnnotatedType(type$1)) {
1189
+ let newBase = type$1;
1190
+ const typeName = type$1.name || "Unknown";
1191
+ if (chain) for (let i = 0; i < chain.length; i++) {
1192
+ const c = chain[i];
1193
+ if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
1144
1194
  else {
1145
- const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
1146
- throw new Error(`Can't find prop ${typeName}${keys}`);
1195
+ const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
1196
+ throw new Error(`Can't find prop ${typeName}${keys}`);
1197
+ }
1147
1198
  }
1148
- }
1149
- this.$type = createAnnotatedTypeNode(newBase.type, metadata, { id: newBase.id });
1199
+ this.$type = createAnnotatedTypeNode(newBase.type, metadata, {
1200
+ id: newBase.id,
1201
+ ref: chain && chain.length > 0 ? {
1202
+ type: () => type$1,
1203
+ field: chain.join(".")
1204
+ } : undefined
1205
+ });
1206
+ } else if (typeof type$1 === "function") {
1207
+ const lazyType = type$1;
1208
+ this.$type = createAnnotatedTypeNode({ kind: "" }, metadata, { ref: {
1209
+ type: lazyType,
1210
+ field: chain ? chain.join(".") : ""
1211
+ } });
1212
+ const node = this.$type;
1213
+ const placeholder = node.type;
1214
+ Object.defineProperty(node, "type", {
1215
+ get() {
1216
+ const t = lazyType();
1217
+ if (!isAnnotatedType(t)) {
1218
+ Object.defineProperty(node, "type", {
1219
+ value: placeholder,
1220
+ writable: false,
1221
+ configurable: true
1222
+ });
1223
+ return placeholder;
1224
+ }
1225
+ let target = t;
1226
+ if (chain) for (const c of chain) if (target.type.kind === "object" && target.type.props.has(c)) target = target.type.props.get(c);
1227
+ else return t.type;
1228
+ node.id = chain ? target.id : target.id || t.id;
1229
+ Object.defineProperty(node, "type", {
1230
+ value: target.type,
1231
+ writable: false,
1232
+ configurable: true
1233
+ });
1234
+ return target.type;
1235
+ },
1236
+ configurable: true
1237
+ });
1238
+ } else throw new TypeError(`${type$1} is not annotated type`);
1150
1239
  return this;
1151
1240
  },
1152
1241
  annotate(key, value, asArray) {
@@ -1234,7 +1323,7 @@ function buildJsonSchema(type) {
1234
1323
  const required = [];
1235
1324
  for (const [key, val] of d.type.props.entries()) {
1236
1325
  if (isPhantomType(val)) continue;
1237
- properties[key] = build$1(val);
1326
+ properties[key] = build$2(val);
1238
1327
  if (!val.optional) required.push(key);
1239
1328
  }
1240
1329
  const schema$1 = {
@@ -1244,7 +1333,7 @@ function buildJsonSchema(type) {
1244
1333
  if (required.length > 0) schema$1.required = required;
1245
1334
  return schema$1;
1246
1335
  };
1247
- const build$1 = (def) => {
1336
+ const build$2 = (def) => {
1248
1337
  if (def.id && def.type.kind === "object" && def !== type) {
1249
1338
  const name = def.id;
1250
1339
  if (!defs[name]) {
@@ -1265,7 +1354,7 @@ function buildJsonSchema(type) {
1265
1354
  array(d) {
1266
1355
  const schema$1 = {
1267
1356
  type: "array",
1268
- items: build$1(d.type.of)
1357
+ items: build$2(d.type.of)
1269
1358
  };
1270
1359
  const minLength = meta.get("expect.minLength");
1271
1360
  if (minLength) schema$1.minItems = typeof minLength === "number" ? minLength : minLength.length;
@@ -1276,7 +1365,7 @@ function buildJsonSchema(type) {
1276
1365
  union(d) {
1277
1366
  const disc = detectDiscriminator(d.type.items);
1278
1367
  if (disc) {
1279
- const oneOf = d.type.items.map(build$1);
1368
+ const oneOf = d.type.items.map(build$2);
1280
1369
  const mapping = {};
1281
1370
  for (const [val, idx] of Object.entries(disc.indexMapping)) {
1282
1371
  const item = d.type.items[idx];
@@ -1290,15 +1379,15 @@ function buildJsonSchema(type) {
1290
1379
  }
1291
1380
  };
1292
1381
  }
1293
- return { anyOf: d.type.items.map(build$1) };
1382
+ return { anyOf: d.type.items.map(build$2) };
1294
1383
  },
1295
1384
  intersection(d) {
1296
- return { allOf: d.type.items.map(build$1) };
1385
+ return { allOf: d.type.items.map(build$2) };
1297
1386
  },
1298
1387
  tuple(d) {
1299
1388
  return {
1300
1389
  type: "array",
1301
- items: d.type.items.map(build$1),
1390
+ items: d.type.items.map(build$2),
1302
1391
  additionalItems: false
1303
1392
  };
1304
1393
  },
@@ -1329,7 +1418,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
1329
1418
  }
1330
1419
  });
1331
1420
  };
1332
- const schema = build$1(type);
1421
+ const schema = build$2(type);
1333
1422
  if (hasDefs) return {
1334
1423
  ...schema,
1335
1424
  $defs: defs
@@ -1339,7 +1428,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
1339
1428
 
1340
1429
  //#endregion
1341
1430
  //#region packages/typescript/src/codegen/js-renderer.ts
1342
- function _define_property$1(obj, key, value) {
1431
+ function _define_property$3(obj, key, value) {
1343
1432
  if (key in obj) Object.defineProperty(obj, key, {
1344
1433
  value,
1345
1434
  enumerable: true,
@@ -1349,6 +1438,19 @@ function _define_property$1(obj, key, value) {
1349
1438
  else obj[key] = value;
1350
1439
  return obj;
1351
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
+ };
1352
1454
  var JsRenderer = class extends BaseRenderer {
1353
1455
  pre() {
1354
1456
  this.writeln("// prettier-ignore-start");
@@ -1377,12 +1479,12 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
1377
1479
  buildAdHocMap(annotateNodes) {
1378
1480
  const map = new Map();
1379
1481
  for (const annotateNode of annotateNodes) for (const entry of annotateNode.entries) {
1380
- 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;
1381
1483
  const anns = entry.annotations || [];
1382
1484
  if (anns.length > 0) {
1383
- const existing = map.get(path$3);
1485
+ const existing = map.get(path$4);
1384
1486
  if (existing) existing.push(...anns);
1385
- else map.set(path$3, [...anns]);
1487
+ else map.set(path$4, [...anns]);
1386
1488
  }
1387
1489
  }
1388
1490
  return map.size > 0 ? map : null;
@@ -1631,8 +1733,8 @@ else handle.prop(prop.id, propHandle.$type);
1631
1733
  const ref = node;
1632
1734
  const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
1633
1735
  if ((0, __atscript_core.isPrimitive)(decl)) {
1634
- const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
1635
- if (!ownerDecl?.node || ownerDecl.node.entity !== "type" && ownerDecl.node.entity !== "interface") {
1736
+ const ownerDecl$1 = this.doc.getDeclarationOwnerNode(ref.id);
1737
+ if (!ownerDecl$1?.node || ownerDecl$1.node.entity !== "type" && ownerDecl$1.node.entity !== "interface") {
1636
1738
  this.annotateType(decl, name);
1637
1739
  return this;
1638
1740
  }
@@ -1646,9 +1748,11 @@ else handle.prop(prop.id, propHandle.$type);
1646
1748
  }
1647
1749
  }
1648
1750
  const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
1649
- this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`);
1751
+ const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
1752
+ const isImported = ownerDecl ? ownerDecl.doc !== this.doc : false;
1753
+ const refExpr = isImported ? `() => ${ref.id}` : ref.id;
1754
+ this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${refExpr}${chain})`);
1650
1755
  if (!ref.hasChain) {
1651
- const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
1652
1756
  if (ownerDecl?.node) {
1653
1757
  const typeAnnotations = ownerDecl.doc.evalAnnotationsForNode(ownerDecl.node);
1654
1758
  typeAnnotations?.forEach((an) => {
@@ -1815,8 +1919,8 @@ else if (resolved && (0, __atscript_core.isPrimitive)(resolved)) {
1815
1919
  }
1816
1920
  if (annotations === undefined) annotations = this.doc.evalAnnotationsForNode(node);
1817
1921
  if (this._adHocAnnotations && this._propPath.length > 0) {
1818
- const path$3 = this._propPath.join(".");
1819
- const adHoc = this._adHocAnnotations.get(path$3);
1922
+ const path$4 = this._propPath.join(".");
1923
+ const adHoc = this._adHocAnnotations.get(path$4);
1820
1924
  if (adHoc) annotations = this.doc.mergeNodesAnnotations(annotations, adHoc);
1821
1925
  }
1822
1926
  annotations?.forEach((an) => {
@@ -1842,6 +1946,68 @@ else if (resolved && (0, __atscript_core.isPrimitive)(resolved)) {
1842
1946
  if (multiple) this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value}, true)`);
1843
1947
  else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
1844
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
+ }
1845
2011
  computeAnnotationValue(node, an) {
1846
2012
  const spec = this.doc.resolveAnnotation(an.name);
1847
2013
  let targetValue = "true";
@@ -1853,13 +2019,13 @@ else this.writeln(`.annotate("${escapeQuotes(an.name)}", ${value})`);
1853
2019
  targetValue = "{ ";
1854
2020
  let i = 0;
1855
2021
  for (const aSpec of spec.arguments) {
1856
- 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 ? "" : ", "} `;
1857
2023
  i++;
1858
2024
  }
1859
2025
  targetValue += "}";
1860
2026
  } else {
1861
2027
  const aSpec = spec.arguments[0];
1862
- 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]);
1863
2029
  else targetValue = "true";
1864
2030
  }
1865
2031
  } else {
@@ -1999,7 +2165,7 @@ else {
1999
2165
  return [];
2000
2166
  }
2001
2167
  constructor(doc, opts) {
2002
- 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();
2003
2169
  }
2004
2170
  };
2005
2171
 
@@ -2030,8 +2196,8 @@ const tsPlugin = (opts) => {
2030
2196
  for (const [key, val] of Object.entries(annotations)) {
2031
2197
  const multiple = val.multiple;
2032
2198
  const typeLine = Array.from(val.types).map((t) => {
2033
- if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
2034
- 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;
2035
2201
  }).join(" | ");
2036
2202
  rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
2037
2203
  }
@@ -2047,9 +2213,35 @@ else return t.optional ? `${t.type} | true` : t.type;
2047
2213
  };
2048
2214
  };
2049
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
+
2050
2242
  //#endregion
2051
2243
  //#region packages/typescript/src/cli/commands.controller.ts
2052
- function _define_property(obj, key, value) {
2244
+ function _define_property$2(obj, key, value) {
2053
2245
  if (key in obj) Object.defineProperty(obj, key, {
2054
2246
  value,
2055
2247
  enumerable: true,
@@ -2059,23 +2251,23 @@ function _define_property(obj, key, value) {
2059
2251
  else obj[key] = value;
2060
2252
  return obj;
2061
2253
  }
2062
- function _ts_decorate(decorators, target, key, desc) {
2254
+ function _ts_decorate$1(decorators, target, key, desc) {
2063
2255
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2064
2256
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2065
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;
2066
2258
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2067
2259
  }
2068
- function _ts_metadata(k, v) {
2260
+ function _ts_metadata$1(k, v) {
2069
2261
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2070
2262
  }
2071
- function _ts_param(paramIndex, decorator) {
2263
+ function _ts_param$1(paramIndex, decorator) {
2072
2264
  return function(target, key) {
2073
2265
  decorator(target, key, paramIndex);
2074
2266
  };
2075
2267
  }
2076
2268
  var Commands = class {
2077
2269
  async default(configFile, format, noEmit, skipDiag) {
2078
- const config = await this.getConfig(configFile);
2270
+ const config = await getConfig(configFile, this.logger);
2079
2271
  config.format = format || __atscript_core.DEFAULT_FORMAT;
2080
2272
  this.logger.log(`Format: ${"\x1B[36m"}${config.format}${"\x1B[39m"}`);
2081
2273
  const builder = await (0, __atscript_core.build)(config);
@@ -2104,72 +2296,361 @@ else if (m.severity === 2) warningCount++;
2104
2296
  }
2105
2297
  if (errorCount > 0) process.exit(1);
2106
2298
  }
2107
- async getConfig(configFile) {
2108
- const root = process.cwd();
2109
- if (configFile) {
2110
- const c = path.default.join(root, configFile);
2111
- if (!(0, fs.existsSync)(c)) {
2112
- this.logger.error(`Config file ${"\x1B[4m"}${configFile}${"\x1B[24m"} not found`);
2113
- process.exit(1);
2114
- }
2115
- this.logger.log(`Using config file ${"\x1B[36m"}${configFile}${"\x1B[39m"}`);
2116
- return (0, __atscript_core.loadConfig)(c);
2117
- } else {
2118
- const resolved = await (0, __atscript_core.resolveConfigFile)(root);
2119
- if (resolved) {
2120
- this.logger.log(`Using config file ${"\x1B[36m"}${resolved}${"\x1B[39m"}`);
2121
- return (0, __atscript_core.loadConfig)(resolved);
2122
- }
2123
- this.logger.log(`No atscript config file found`);
2124
- return {
2125
- format: __atscript_core.DEFAULT_FORMAT,
2126
- plugins: [tsPlugin()]
2127
- };
2128
- }
2129
- }
2130
2299
  constructor(logger) {
2131
- _define_property(this, "logger", void 0);
2300
+ _define_property$2(this, "logger", void 0);
2132
2301
  this.logger = logger;
2133
2302
  }
2134
2303
  };
2135
- _ts_decorate([
2304
+ _ts_decorate$1([
2136
2305
  (0, __moostjs_event_cli.Cli)(""),
2137
2306
  (0, moost.Description)("Builds .as files using --config and --format"),
2138
2307
  (0, __moostjs_event_cli.CliExample)("-c atscript.config.js", "Build .as files using atscript.config.js"),
2139
2308
  (0, __moostjs_event_cli.CliExample)("-f dts", "Build \"d.ts\" files for \".as\" files"),
2140
2309
  (0, __moostjs_event_cli.CliExample)("--noEmit", "Only check for errors, do not emit files"),
2141
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)"),
2142
2616
  _ts_param(0, (0, __moostjs_event_cli.CliOption)("c", "config")),
2143
2617
  _ts_param(0, (0, moost.Optional)()),
2144
2618
  _ts_param(0, (0, moost.Description)("Path to config file")),
2145
- _ts_param(1, (0, __moostjs_event_cli.CliOption)("f", "format")),
2619
+ _ts_param(1, (0, __moostjs_event_cli.CliOption)("dry-run")),
2146
2620
  _ts_param(1, (0, moost.Optional)()),
2147
- _ts_param(1, (0, moost.Description)("Output format (e.g. js, dts). Omit to run all plugins with their default output.")),
2148
- _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")),
2149
2623
  _ts_param(2, (0, moost.Optional)()),
2150
- _ts_param(2, (0, moost.Description)("Only run diagnostics without emitting files")),
2151
- _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")),
2152
2626
  _ts_param(3, (0, moost.Optional)()),
2153
- _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)")),
2154
2631
  _ts_metadata("design:type", Function),
2155
2632
  _ts_metadata("design:paramtypes", [
2156
2633
  String,
2157
- String,
2634
+ Boolean,
2635
+ Boolean,
2158
2636
  Boolean,
2159
2637
  Boolean
2160
2638
  ]),
2161
2639
  _ts_metadata("design:returntype", Promise)
2162
- ], Commands.prototype, "default", null);
2163
- Commands = _ts_decorate([
2640
+ ], DbSyncController.prototype, "dbSync", null);
2641
+ DbSyncController = _ts_decorate([
2164
2642
  (0, moost.Controller)(),
2165
2643
  _ts_param(0, (0, moost.InjectMoostLogger)("asc")),
2166
2644
  _ts_metadata("design:type", Function),
2167
2645
  _ts_metadata("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
2168
- ], Commands);
2646
+ ], DbSyncController);
2647
+ function patchAsImports(content) {
2648
+ return content.replace(/(from\s+["'][^"']+)\.as(["'])/g, "$1.as.mjs$2");
2649
+ }
2169
2650
 
2170
2651
  //#endregion
2171
2652
  //#region packages/typescript/src/cli/cli.ts
2172
- new __moostjs_event_cli.CliApp().controllers(Commands).useHelp({ name: "asc" }).useOptions([{
2653
+ new __moostjs_event_cli.CliApp().controllers(Commands, DbSyncController).useHelp({ name: "asc" }).useOptions([{
2173
2654
  keys: ["help"],
2174
2655
  description: "Display instructions for the command."
2175
2656
  }]).start();