@atscript/typescript 0.1.89 → 0.1.90

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
@@ -1790,11 +1790,8 @@ var JsRenderer = class extends BaseRenderer {
1790
1790
  const unwound = this.doc.unwindType(annotateNode.targetName);
1791
1791
  if (unwound?.def) {
1792
1792
  let def = this.doc.mergeIntersection(unwound.def);
1793
- if ((0, _atscript_core.isInterface)(def)) if (def.hasExtends) {
1794
- const resolved = unwound.doc.resolveInterfaceExtends(def);
1795
- if (resolved) def = resolved;
1796
- else def = def.getDefinition() || def;
1797
- } else def = def.getDefinition() || def;
1793
+ if ((0, _atscript_core.isInterface)(def)) if (def.hasExtends) def = unwound.doc.resolveInterfaceExtends(def) || def.getDefinition() || def;
1794
+ else def = def.getDefinition() || def;
1798
1795
  this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
1799
1796
  this.annotateType(def, node.id);
1800
1797
  this._adHocAnnotations = null;
@@ -2307,8 +2304,7 @@ var JsRenderer = class extends BaseRenderer {
2307
2304
  targetValue += "}";
2308
2305
  } else {
2309
2306
  const aSpec = spec.arguments[0];
2310
- if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
2311
- else targetValue = "true";
2307
+ targetValue = an.args[0] ? this.emitArgValue(aSpec, an.args[0]) : "true";
2312
2308
  }
2313
2309
  } else {
2314
2310
  multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
@@ -2522,6 +2518,25 @@ async function getConfig(configFile, logger) {
2522
2518
  }
2523
2519
  }
2524
2520
 
2521
+ //#endregion
2522
+ //#region packages/typescript/src/cli/emit-policy.ts
2523
+ /**
2524
+ * Printed when diagnostics found errors and the emit was suppressed, so the
2525
+ * user knows the previous outputs are still the last known-good ones.
2526
+ */ const NOTHING_EMITTED_MESSAGE = "Nothing emitted — previous outputs were left untouched. Fix the errors above, or pass --skipDiag to emit anyway.";
2527
+ /**
2528
+ * Decides whether `asc` may write its outputs.
2529
+ *
2530
+ * A failing compile must never replace valid artifacts: half of the outputs
2531
+ * would be stale and aggregate manifests produced in `buildEnd` would be
2532
+ * regenerated from an incomplete document set. Errors therefore block the
2533
+ * write entirely — `--skipDiag` is the explicit opt-out.
2534
+ */ function shouldEmit(input) {
2535
+ if (input.noEmit) return false;
2536
+ if (input.skipDiag) return true;
2537
+ return input.errorCount === 0;
2538
+ }
2539
+
2525
2540
  //#endregion
2526
2541
  //#region packages/typescript/src/cli/commands.controller.ts
2527
2542
  function _define_property$2(obj, key, value) {
@@ -2567,7 +2582,12 @@ var Commands = class {
2567
2582
  }
2568
2583
  }
2569
2584
  }
2570
- if (!noEmit) {
2585
+ const emit = shouldEmit({
2586
+ noEmit,
2587
+ skipDiag,
2588
+ errorCount
2589
+ });
2590
+ if (emit) {
2571
2591
  const out = await builder.write(config);
2572
2592
  for (const { target } of out) this.logger.log(`✅ created ${target}`);
2573
2593
  }
@@ -2577,7 +2597,10 @@ var Commands = class {
2577
2597
  if (warningCount > 0) parts.push(`${warningCount} warning${warningCount > 1 ? "s" : ""}`);
2578
2598
  this.logger.log(`\nFound ${parts.join(" and ")}`);
2579
2599
  }
2580
- if (errorCount > 0) process.exit(1);
2600
+ if (errorCount > 0) {
2601
+ if (!emit && !noEmit) this.logger.log(`${NOTHING_EMITTED_MESSAGE}`);
2602
+ process.exit(1);
2603
+ }
2581
2604
  }
2582
2605
  constructor(logger) {
2583
2606
  _define_property$2(this, "logger", void 0);
@@ -2619,6 +2642,188 @@ Commands = _ts_decorate$1([
2619
2642
  _ts_metadata$1("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
2620
2643
  ], Commands);
2621
2644
 
2645
+ //#endregion
2646
+ //#region packages/typescript/src/cli/db-sync-models.ts
2647
+ /** Depth cap for `config.models` — deep enough for nested arrays and namespaces. */ const MAX_MODELS_DEPTH = 6;
2648
+ /** Keeps two runs in the same process (and the same millisecond) apart. */ let runSeq = 0;
2649
+ /**
2650
+ * Compiles the project's `.as` files and loads every `@db.table` / `@db.view`
2651
+ * model, plus the models contributed by `config.models`.
2652
+ *
2653
+ * The result is only a complete inventory when `diagnostics.errors` is 0 and
2654
+ * both `failures` and `modelsError` are empty — a caller that plans a sync
2655
+ * from a partial inventory would propose dropping the tables it failed to see.
2656
+ */ async function loadDbModels(options) {
2657
+ const { config, cwd = process.cwd(), logger } = options;
2658
+ const buildConfig = toBuildConfig(config);
2659
+ logger?.log(`Compiling .as files...`);
2660
+ const builder = await (0, _atscript_core.build)(buildConfig);
2661
+ const diagnostics = await collectDiagnostics(builder);
2662
+ if (diagnostics.errors > 0) return {
2663
+ types: [],
2664
+ failures: [],
2665
+ diagnostics,
2666
+ packaged: 0
2667
+ };
2668
+ const { types, failures } = await importGeneratedModules(await builder.generate(buildConfig), buildConfig.rootDir || cwd, cwd);
2669
+ const result = {
2670
+ types,
2671
+ failures,
2672
+ diagnostics,
2673
+ packaged: 0
2674
+ };
2675
+ if (failures.length > 0 || !config.models) return result;
2676
+ try {
2677
+ const seen = new Set(types);
2678
+ for (const model of flattenModels(await config.models())) if (!seen.has(model)) {
2679
+ seen.add(model);
2680
+ types.push(model);
2681
+ result.packaged++;
2682
+ }
2683
+ } catch (error) {
2684
+ result.modelsError = error;
2685
+ }
2686
+ return result;
2687
+ }
2688
+ /** Abort message printed when some generated modules could not be imported. */ function partialInventoryMessage(count) {
2689
+ return `Could not load ${count} compiled model module(s); aborting before planning — a partial inventory would propose dropping tables.`;
2690
+ }
2691
+ function errorMessage(error) {
2692
+ return error instanceof Error ? error.message : String(error);
2693
+ }
2694
+ /**
2695
+ * Collects every `@db.table` / `@db.view` model out of whatever `config.models`
2696
+ * returned — an annotated type, an array, a module namespace object, or any
2697
+ * nesting of those. Deduplicated by identity.
2698
+ */ function flattenModels(value) {
2699
+ const out = [];
2700
+ walkModels(value, out, /* @__PURE__ */ new Set(), 0);
2701
+ return out;
2702
+ }
2703
+ /** Rewrites the emitted `.as` specifiers to the `.mjs` files we just wrote. */ function patchAsImports(content) {
2704
+ return content.replace(/(from\s+["'][^"']+)\.as(["'])/g, "$1.as.mjs$2");
2705
+ }
2706
+ function toBuildConfig(config) {
2707
+ const buildConfig = { ...config };
2708
+ if (typeof config.db === "object" && "adapter" in config.db) {
2709
+ const dbConfig = config.db;
2710
+ if (dbConfig.include) buildConfig.include = dbConfig.include;
2711
+ if (dbConfig.exclude) buildConfig.exclude = dbConfig.exclude;
2712
+ }
2713
+ buildConfig.format = "js";
2714
+ return buildConfig;
2715
+ }
2716
+ async function collectDiagnostics(builder) {
2717
+ const diagnostics = {
2718
+ errors: 0,
2719
+ warnings: 0,
2720
+ messages: []
2721
+ };
2722
+ const diagMap = await builder.diagnostics();
2723
+ for (const [docId, messages] of diagMap) {
2724
+ const doc = builder.getDoc(docId);
2725
+ for (const m of messages) {
2726
+ if (m.severity === 1) diagnostics.errors++;
2727
+ else if (m.severity === 2) diagnostics.warnings++;
2728
+ if (doc) diagnostics.messages.push(doc.renderDiagMessage(m, true, true));
2729
+ }
2730
+ }
2731
+ return diagnostics;
2732
+ }
2733
+ async function importGeneratedModules(outputs, rootDir, cwd) {
2734
+ const jsOutputs = [];
2735
+ for (const o of outputs) if (o.fileName.endsWith(".js") && o.source) jsOutputs.push({
2736
+ fileName: o.fileName,
2737
+ content: o.content,
2738
+ source: o.source
2739
+ });
2740
+ const base = resolveLayoutBase(rootDir, jsOutputs.map((o) => path.default.dirname((0, _atscript_core.fileUriToPath)(o.source))));
2741
+ const tmpDir = path.default.join(cwd, `.atscript-db-sync-${process.pid}-${Date.now()}-${runSeq++}`);
2742
+ const cleanup = () => {
2743
+ try {
2744
+ (0, fs.rmSync)(tmpDir, {
2745
+ recursive: true,
2746
+ force: true
2747
+ });
2748
+ } catch {}
2749
+ };
2750
+ process.on("exit", cleanup);
2751
+ try {
2752
+ const files = [];
2753
+ for (const o of jsOutputs) {
2754
+ const srcDir = path.default.dirname((0, _atscript_core.fileUriToPath)(o.source));
2755
+ const rel = path.default.join(path.default.relative(base, srcDir), o.fileName.replace(/\.js$/, ".mjs"));
2756
+ const abs = path.default.join(tmpDir, rel);
2757
+ (0, fs.mkdirSync)(path.default.dirname(abs), { recursive: true });
2758
+ (0, fs.writeFileSync)(abs, patchAsImports(o.content));
2759
+ files.push({
2760
+ abs,
2761
+ rel
2762
+ });
2763
+ }
2764
+ const types = [];
2765
+ const failures = [];
2766
+ const seen = /* @__PURE__ */ new Set();
2767
+ for (const file of files) try {
2768
+ collectFromModule(await import(
2769
+ /* @vite-ignore */
2770
+ (0, node_url.pathToFileURL)(file.abs).href
2771
+ ), types, seen);
2772
+ } catch (error) {
2773
+ failures.push({
2774
+ file: file.rel,
2775
+ error
2776
+ });
2777
+ }
2778
+ return {
2779
+ types,
2780
+ failures
2781
+ };
2782
+ } finally {
2783
+ cleanup();
2784
+ process.off("exit", cleanup);
2785
+ }
2786
+ }
2787
+ function collectFromModule(mod, types, seen) {
2788
+ for (const exp of Object.values(mod)) if (isDbModel(exp) && !seen.has(exp)) {
2789
+ seen.add(exp);
2790
+ types.push(exp);
2791
+ }
2792
+ }
2793
+ /**
2794
+ * Directory the temp layout mirrors. Normally `rootDir`; when a source lives
2795
+ * outside it, the common ancestor of `rootDir` and every source, so that no
2796
+ * `..` segment ever escapes the temp directory.
2797
+ */ function resolveLayoutBase(rootDir, sourceDirs) {
2798
+ const root = path.default.resolve(rootDir);
2799
+ return sourceDirs.some((dir) => {
2800
+ const rel = path.default.relative(root, path.default.resolve(dir));
2801
+ return rel === ".." || rel.startsWith(`..${path.default.sep}`);
2802
+ }) ? commonAncestor([root, ...sourceDirs]) : root;
2803
+ }
2804
+ function commonAncestor(dirs) {
2805
+ const parts = dirs.map((d) => path.default.resolve(d).split(path.default.sep));
2806
+ const first = parts[0];
2807
+ let i = 0;
2808
+ while (i < first.length && parts.every((p) => p[i] === first[i])) i++;
2809
+ return first.slice(0, i).join(path.default.sep) || path.default.sep;
2810
+ }
2811
+ function isDbModel(value) {
2812
+ return isAnnotatedType(value) && Boolean(value.metadata?.has("db.table") || value.metadata?.has("db.view"));
2813
+ }
2814
+ function walkModels(value, out, seen, depth) {
2815
+ if (!value || typeof value !== "object" && typeof value !== "function") return;
2816
+ if (seen.has(value)) return;
2817
+ seen.add(value);
2818
+ if (isAnnotatedType(value)) {
2819
+ if (isDbModel(value)) out.push(value);
2820
+ return;
2821
+ }
2822
+ if (depth >= MAX_MODELS_DEPTH) return;
2823
+ const items = Array.isArray(value) ? value : Object.values(value);
2824
+ for (const item of items) walkModels(item, out, seen, depth + 1);
2825
+ }
2826
+
2622
2827
  //#endregion
2623
2828
  //#region packages/typescript/src/cli/db-sync-printer.ts
2624
2829
  function _define_property$1(obj, key, value) {
@@ -2815,13 +3020,14 @@ var DbSyncController = class {
2815
3020
  this.logger.error("\x1B[31mNo \"db\" field in atscript config. Add a db configuration to use schema sync.\x1B[39m");
2816
3021
  process.exit(1);
2817
3022
  }
2818
- const [dbSpace, dbTypes] = await Promise.all([this.resolveDbSpace(config.db), this.compileAndLoadTypes(config)]);
3023
+ const dbTypes = await this.loadTypes(config);
2819
3024
  if (dbTypes.length === 0) {
2820
3025
  this.info(`No types with @db.table or @db.view found. Nothing to sync.`);
2821
3026
  return;
2822
3027
  }
2823
3028
  this.printer.typeCount(dbTypes.length);
2824
3029
  this.printer.banner();
3030
+ const dbSpace = await this.resolveDbSpace(config.db);
2825
3031
  const { SchemaSync } = await this.importFromCwd("@atscript/db/sync", true);
2826
3032
  const sync = new SchemaSync(dbSpace);
2827
3033
  const plan = await sync.plan(dbTypes, {
@@ -2877,44 +3083,33 @@ var DbSyncController = class {
2877
3083
  });
2878
3084
  this.printer.result(result);
2879
3085
  }
2880
- async compileAndLoadTypes(config) {
2881
- const buildConfig = { ...config };
2882
- if (typeof config.db === "object" && "adapter" in config.db) {
2883
- const dbConfig = config.db;
2884
- if (dbConfig.include) buildConfig.include = dbConfig.include;
2885
- if (dbConfig.exclude) buildConfig.exclude = dbConfig.exclude;
2886
- }
2887
- buildConfig.format = "js";
2888
- this.info(`Compiling .as files...`);
2889
- const jsOutputs = (await (await (0, _atscript_core.build)(buildConfig)).generate(buildConfig)).filter((o) => o.fileName.endsWith(".js"));
2890
- const tmpDir = path.default.join(process.cwd(), `.atscript-db-sync-${Date.now()}`);
2891
- const writtenFiles = [];
2892
- for (const o of jsOutputs) {
2893
- const target = path.default.join(tmpDir, o.fileName.replace(/\.js$/, ".mjs"));
2894
- (0, fs.mkdirSync)(path.default.dirname(target), { recursive: true });
2895
- (0, fs.writeFileSync)(target, patchAsImports(o.content));
2896
- writtenFiles.push(target);
3086
+ /**
3087
+ * Loads the full model inventory or aborts. Diagnostics run first, every
3088
+ * generated module is imported individually, and any failure exits 1 before
3089
+ * a plan is computed.
3090
+ */ async loadTypes(config) {
3091
+ const result = await loadDbModels({
3092
+ config,
3093
+ cwd: process.cwd(),
3094
+ logger: { log: (message) => this.info(message) }
3095
+ });
3096
+ if (result.diagnostics.errors > 0) {
3097
+ for (const message of result.diagnostics.messages) this.logger.error(message);
3098
+ this.logger.error(`Fix the errors above before syncing.`);
3099
+ process.exit(1);
2897
3100
  }
2898
- const dbTypes = [];
2899
- try {
2900
- for (const file of writtenFiles) {
2901
- const mod = await import(
2902
- /* @vite-ignore */
2903
- (0, node_url.pathToFileURL)(file).href
2904
- );
2905
- for (const exp of Object.values(mod)) if (isAnnotatedType(exp) && (exp.metadata?.has("db.table") || exp.metadata?.has("db.view"))) dbTypes.push(exp);
2906
- }
2907
- } catch (error) {
2908
- this.logger.warn?.(`Could not import compiled types: ${error}`);
2909
- } finally {
2910
- try {
2911
- (0, fs.rmSync)(tmpDir, {
2912
- recursive: true,
2913
- force: true
2914
- });
2915
- } catch {}
3101
+ for (const message of result.diagnostics.messages) this.info(message);
3102
+ if (result.failures.length > 0) {
3103
+ for (const failure of result.failures) this.logger.error(`✖ ${failure.file}: ${errorMessage(failure.error)}`);
3104
+ this.logger.error(`${partialInventoryMessage(result.failures.length)}`);
3105
+ process.exit(1);
2916
3106
  }
2917
- return dbTypes;
3107
+ if (result.modelsError) {
3108
+ this.logger.error(`config.models failed: ${errorMessage(result.modelsError)}`);
3109
+ process.exit(1);
3110
+ }
3111
+ if (result.packaged > 0) this.info(`Loaded ${result.packaged} packaged model(s) from config.models`);
3112
+ return result.types;
2918
3113
  }
2919
3114
  async resolveDbSpace(dbConfig) {
2920
3115
  if (typeof dbConfig === "function") {
@@ -3023,9 +3218,6 @@ DbSyncController = _ts_decorate([
3023
3218
  _ts_metadata("design:type", Function),
3024
3219
  _ts_metadata("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
3025
3220
  ], DbSyncController);
3026
- function patchAsImports(content) {
3027
- return content.replace(/(from\s+["'][^"']+)\.as(["'])/g, "$1.as.mjs$2");
3028
- }
3029
3221
 
3030
3222
  //#endregion
3031
3223
  //#region packages/typescript/src/cli/cli.ts
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
2
- const require_plugin = require('./plugin-DMBkdYCf.cjs');
2
+ const require_plugin = require('./plugin-Cs9mKJ8h.cjs');
3
3
 
4
4
  exports.default = require_plugin.tsPlugin;
5
5
  exports.tsPlugin = require_plugin.tsPlugin;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { t as tsPlugin } from "./plugin-BOoquMkD.mjs";
1
+ import { t as tsPlugin } from "./plugin-DHhdrTs8.mjs";
2
2
 
3
3
  export { tsPlugin as default, tsPlugin };
@@ -875,11 +875,8 @@ var JsRenderer = class extends BaseRenderer {
875
875
  const unwound = this.doc.unwindType(annotateNode.targetName);
876
876
  if (unwound?.def) {
877
877
  let def = this.doc.mergeIntersection(unwound.def);
878
- if ((0, _atscript_core.isInterface)(def)) if (def.hasExtends) {
879
- const resolved = unwound.doc.resolveInterfaceExtends(def);
880
- if (resolved) def = resolved;
881
- else def = def.getDefinition() || def;
882
- } else def = def.getDefinition() || def;
878
+ if ((0, _atscript_core.isInterface)(def)) if (def.hasExtends) def = unwound.doc.resolveInterfaceExtends(def) || def.getDefinition() || def;
879
+ else def = def.getDefinition() || def;
883
880
  this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
884
881
  this.annotateType(def, node.id);
885
882
  this._adHocAnnotations = null;
@@ -1392,8 +1389,7 @@ var JsRenderer = class extends BaseRenderer {
1392
1389
  targetValue += "}";
1393
1390
  } else {
1394
1391
  const aSpec = spec.arguments[0];
1395
- if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
1396
- else targetValue = "true";
1392
+ targetValue = an.args[0] ? this.emitArgValue(aSpec, an.args[0]) : "true";
1397
1393
  }
1398
1394
  } else {
1399
1395
  multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
@@ -847,11 +847,8 @@ var JsRenderer = class extends BaseRenderer {
847
847
  const unwound = this.doc.unwindType(annotateNode.targetName);
848
848
  if (unwound?.def) {
849
849
  let def = this.doc.mergeIntersection(unwound.def);
850
- if (isInterface(def)) if (def.hasExtends) {
851
- const resolved = unwound.doc.resolveInterfaceExtends(def);
852
- if (resolved) def = resolved;
853
- else def = def.getDefinition() || def;
854
- } else def = def.getDefinition() || def;
850
+ if (isInterface(def)) if (def.hasExtends) def = unwound.doc.resolveInterfaceExtends(def) || def.getDefinition() || def;
851
+ else def = def.getDefinition() || def;
855
852
  this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
856
853
  this.annotateType(def, node.id);
857
854
  this._adHocAnnotations = null;
@@ -1364,8 +1361,7 @@ var JsRenderer = class extends BaseRenderer {
1364
1361
  targetValue += "}";
1365
1362
  } else {
1366
1363
  const aSpec = spec.arguments[0];
1367
- if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
1368
- else targetValue = "true";
1364
+ targetValue = an.args[0] ? this.emitArgValue(aSpec, an.args[0]) : "true";
1369
1365
  }
1370
1366
  } else {
1371
1367
  multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_plugin = require('./plugin-DMBkdYCf.cjs');
2
+ const require_plugin = require('./plugin-Cs9mKJ8h.cjs');
3
3
  let path = require("path");
4
4
  path = require_plugin.__toESM(path);
5
5
  let _atscript_core = require("@atscript/core");
@@ -1,4 +1,4 @@
1
- import { t as tsPlugin } from "./plugin-BOoquMkD.mjs";
1
+ import { t as tsPlugin } from "./plugin-DHhdrTs8.mjs";
2
2
  import path from "path";
3
3
  import { build } from "@atscript/core";
4
4
  import { readFileSync, writeFileSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/typescript",
3
- "version": "0.1.89",
3
+ "version": "0.1.90",
4
4
  "description": "Atscript: typescript-gen support.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -63,8 +63,8 @@
63
63
  "./package.json": "./package.json"
64
64
  },
65
65
  "dependencies": {
66
- "@moostjs/event-cli": "^0.6.35",
67
- "moost": "^0.6.35"
66
+ "@moostjs/event-cli": "^0.6.36",
67
+ "moost": "^0.6.36"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@atscript/db": "^0.1.125",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@atscript/db": "^0.1.97",
76
- "@atscript/core": "^0.1.89"
76
+ "@atscript/core": "^0.1.90"
77
77
  },
78
78
  "peerDependenciesMeta": {
79
79
  "@atscript/db": {