@atscript/typescript 0.1.89 → 0.1.91

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
@@ -1606,6 +1606,12 @@ const QUERY_OP_MAP = {
1606
1606
  "not exists": "$exists"
1607
1607
  };
1608
1608
  var JsRenderer = class extends BaseRenderer {
1609
+ /**
1610
+ * Relative imports get the configured `moduleExtension`; bare specifiers
1611
+ * always keep `.as` — they resolve through the package's `exports` map.
1612
+ */ transformFromPath(path) {
1613
+ return (0, _atscript_core.isBareSpecifier)(path) ? `${path}.as` : `${path}${this.opts?.moduleExtension ?? ".as"}`;
1614
+ }
1609
1615
  /**
1610
1616
  * Override base `unused` to subtract symbols that the JS output references
1611
1617
  * transitively through `extends`-resolved parent prop trees. Without this,
@@ -1790,11 +1796,8 @@ var JsRenderer = class extends BaseRenderer {
1790
1796
  const unwound = this.doc.unwindType(annotateNode.targetName);
1791
1797
  if (unwound?.def) {
1792
1798
  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;
1799
+ if ((0, _atscript_core.isInterface)(def)) if (def.hasExtends) def = unwound.doc.resolveInterfaceExtends(def) || def.getDefinition() || def;
1800
+ else def = def.getDefinition() || def;
1798
1801
  this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
1799
1802
  this.annotateType(def, node.id);
1800
1803
  this._adHocAnnotations = null;
@@ -2307,8 +2310,7 @@ var JsRenderer = class extends BaseRenderer {
2307
2310
  targetValue += "}";
2308
2311
  } else {
2309
2312
  const aSpec = spec.arguments[0];
2310
- if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
2311
- else targetValue = "true";
2313
+ targetValue = an.args[0] ? this.emitArgValue(aSpec, an.args[0]) : "true";
2312
2314
  }
2313
2315
  } else {
2314
2316
  multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
@@ -2522,6 +2524,49 @@ async function getConfig(configFile, logger) {
2522
2524
  }
2523
2525
  }
2524
2526
 
2527
+ //#endregion
2528
+ //#region packages/typescript/src/cli/diagnostics.ts
2529
+ /**
2530
+ * Runs the builder's diagnostics and renders every message the way the
2531
+ * default `asc` command prints it. Shared by `asc` and `asc db sync` so both
2532
+ * commands count and format diagnostics identically.
2533
+ */ async function collectDiagnostics(builder) {
2534
+ const summary = {
2535
+ errors: 0,
2536
+ warnings: 0,
2537
+ messages: []
2538
+ };
2539
+ const diagMap = await builder.diagnostics();
2540
+ for (const [docId, messages] of diagMap) {
2541
+ const doc = builder.getDoc(docId);
2542
+ for (const m of messages) {
2543
+ if (m.severity === 1) summary.errors++;
2544
+ else if (m.severity === 2) summary.warnings++;
2545
+ if (doc) summary.messages.push(doc.renderDiagMessage(m, true, true));
2546
+ }
2547
+ }
2548
+ return summary;
2549
+ }
2550
+
2551
+ //#endregion
2552
+ //#region packages/typescript/src/cli/emit-policy.ts
2553
+ /**
2554
+ * Printed when diagnostics found errors and the emit was suppressed, so the
2555
+ * user knows the previous outputs are still the last known-good ones.
2556
+ */ const NOTHING_EMITTED_MESSAGE = "Nothing emitted — previous outputs were left untouched. Fix the errors above, or pass --skipDiag to emit anyway.";
2557
+ /**
2558
+ * Decides whether `asc` may write its outputs — and, when it may not, why.
2559
+ *
2560
+ * A failing compile must never replace valid artifacts: half of the outputs
2561
+ * would be stale and aggregate manifests produced in `buildEnd` would be
2562
+ * regenerated from an incomplete document set. Errors therefore block the
2563
+ * write entirely — `--skipDiag` is the explicit opt-out.
2564
+ */ function emitDecision(input) {
2565
+ if (input.noEmit) return "noEmit";
2566
+ if (input.skipDiag || input.errorCount === 0) return "emit";
2567
+ return "blocked";
2568
+ }
2569
+
2525
2570
  //#endregion
2526
2571
  //#region packages/typescript/src/cli/commands.controller.ts
2527
2572
  function _define_property$2(obj, key, value) {
@@ -2557,17 +2602,17 @@ var Commands = class {
2557
2602
  let errorCount = 0;
2558
2603
  let warningCount = 0;
2559
2604
  if (!skipDiag) {
2560
- const diagMap = await builder.diagnostics();
2561
- for (const [docId, messages] of diagMap) {
2562
- const doc = builder.getDoc(docId);
2563
- for (const m of messages) {
2564
- if (m.severity === 1) errorCount++;
2565
- else if (m.severity === 2) warningCount++;
2566
- if (doc) this.logger.log(doc.renderDiagMessage(m, true, true));
2567
- }
2568
- }
2569
- }
2570
- if (!noEmit) {
2605
+ const diagnostics = await collectDiagnostics(builder);
2606
+ for (const message of diagnostics.messages) this.logger.log(message);
2607
+ errorCount = diagnostics.errors;
2608
+ warningCount = diagnostics.warnings;
2609
+ }
2610
+ const decision = emitDecision({
2611
+ noEmit,
2612
+ skipDiag,
2613
+ errorCount
2614
+ });
2615
+ if (decision === "emit") {
2571
2616
  const out = await builder.write(config);
2572
2617
  for (const { target } of out) this.logger.log(`✅ created ${target}`);
2573
2618
  }
@@ -2577,6 +2622,7 @@ var Commands = class {
2577
2622
  if (warningCount > 0) parts.push(`${warningCount} warning${warningCount > 1 ? "s" : ""}`);
2578
2623
  this.logger.log(`\nFound ${parts.join(" and ")}`);
2579
2624
  }
2625
+ if (decision === "blocked") this.logger.log(`${NOTHING_EMITTED_MESSAGE}`);
2580
2626
  if (errorCount > 0) process.exit(1);
2581
2627
  }
2582
2628
  constructor(logger) {
@@ -2619,6 +2665,153 @@ Commands = _ts_decorate$1([
2619
2665
  _ts_metadata$1("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
2620
2666
  ], Commands);
2621
2667
 
2668
+ //#endregion
2669
+ //#region packages/typescript/src/cli/db-sync-models.ts
2670
+ /**
2671
+ * Compiles the project's `.as` files and loads every `@db.table` / `@db.view`
2672
+ * model, plus the models contributed by `config.models`.
2673
+ *
2674
+ * The result is only a complete inventory when `diagnostics.errors` is 0 and
2675
+ * both `failures` and `modelsError` are empty — a caller that plans a sync
2676
+ * from a partial inventory would propose dropping the tables it failed to see.
2677
+ */ async function loadDbModels(options) {
2678
+ const { config, cwd = process.cwd() } = options;
2679
+ const buildConfig = toBuildConfig(config);
2680
+ const builder = await (0, _atscript_core.build)(buildConfig);
2681
+ const rootDir = buildConfig.rootDir;
2682
+ const diagnostics = await collectDiagnostics(builder);
2683
+ if (diagnostics.errors > 0) return {
2684
+ types: [],
2685
+ failures: [],
2686
+ diagnostics,
2687
+ packaged: 0
2688
+ };
2689
+ const { types, failures } = await importGeneratedModules(await builder.generate(buildConfig), rootDir, cwd);
2690
+ const result = {
2691
+ types,
2692
+ failures,
2693
+ diagnostics,
2694
+ packaged: 0
2695
+ };
2696
+ if (failures.length > 0 || !config.models) return result;
2697
+ try {
2698
+ const models = flattenModels(await config.models());
2699
+ types.push(...models);
2700
+ result.packaged = models.length;
2701
+ } catch (error) {
2702
+ result.modelsError = error;
2703
+ }
2704
+ return result;
2705
+ }
2706
+ function errorMessage(error) {
2707
+ return error instanceof Error ? error.message : String(error);
2708
+ }
2709
+ /**
2710
+ * Collects every `@db.table` / `@db.view` model out of whatever `config.models`
2711
+ * returned — an annotated type, an array, a module namespace object, or any
2712
+ * nesting of those. Deduplicated by identity.
2713
+ */ function flattenModels(value) {
2714
+ const out = [];
2715
+ walkModels(value, out, /* @__PURE__ */ new Set());
2716
+ return out;
2717
+ }
2718
+ function toBuildConfig(config) {
2719
+ const buildConfig = { ...config };
2720
+ if (typeof config.db === "object" && "adapter" in config.db) {
2721
+ const dbConfig = config.db;
2722
+ if (dbConfig.include) buildConfig.include = dbConfig.include;
2723
+ if (dbConfig.exclude) buildConfig.exclude = dbConfig.exclude;
2724
+ }
2725
+ buildConfig.format = "js";
2726
+ const syncTs = tsPlugin({ moduleExtension: ".as.mjs" });
2727
+ const plugins = (config.plugins ?? []).map((p) => p.name === "typescript" ? syncTs : p);
2728
+ if (!plugins.includes(syncTs)) plugins.push(syncTs);
2729
+ buildConfig.plugins = plugins;
2730
+ return buildConfig;
2731
+ }
2732
+ async function importGeneratedModules(outputs, rootDir, cwd) {
2733
+ const modules = outputs.filter((o) => o.fileName.endsWith(".js")).map((o) => ({
2734
+ srcDir: path.default.dirname((0, _atscript_core.fileUriToPath)(o.source)),
2735
+ fileName: o.fileName.replace(/\.js$/, ".mjs"),
2736
+ content: o.content
2737
+ }));
2738
+ const base = commonAncestor([rootDir, ...modules.map((m) => m.srcDir)]);
2739
+ const tmpDir = (0, fs.mkdtempSync)(path.default.join(cwd, ".atscript-db-sync-"));
2740
+ const cleanup = () => {
2741
+ try {
2742
+ (0, fs.rmSync)(tmpDir, {
2743
+ recursive: true,
2744
+ force: true
2745
+ });
2746
+ } catch {}
2747
+ };
2748
+ process.on("exit", cleanup);
2749
+ try {
2750
+ const files = [];
2751
+ const dirs = /* @__PURE__ */ new Set();
2752
+ for (const m of modules) {
2753
+ const rel = path.default.join(path.default.relative(base, m.srcDir), m.fileName);
2754
+ const abs = path.default.join(tmpDir, rel);
2755
+ const dir = path.default.dirname(abs);
2756
+ if (!dirs.has(dir)) {
2757
+ dirs.add(dir);
2758
+ (0, fs.mkdirSync)(dir, { recursive: true });
2759
+ }
2760
+ (0, fs.writeFileSync)(abs, m.content);
2761
+ files.push({
2762
+ abs,
2763
+ rel
2764
+ });
2765
+ }
2766
+ const types = [];
2767
+ const failures = [];
2768
+ const seen = /* @__PURE__ */ new Set();
2769
+ for (const file of files) try {
2770
+ walkModels(await import(
2771
+ /* @vite-ignore */
2772
+ (0, node_url.pathToFileURL)(file.abs).href
2773
+ ), types, seen);
2774
+ } catch (error) {
2775
+ failures.push({
2776
+ file: file.rel,
2777
+ error
2778
+ });
2779
+ }
2780
+ return {
2781
+ types,
2782
+ failures
2783
+ };
2784
+ } finally {
2785
+ cleanup();
2786
+ process.off("exit", cleanup);
2787
+ }
2788
+ }
2789
+ /**
2790
+ * Directory the temp layout mirrors: the common ancestor of `rootDir` and
2791
+ * every source directory — `rootDir` itself when every source lives under it —
2792
+ * so that no `..` segment ever escapes the temp directory.
2793
+ */ function commonAncestor(dirs) {
2794
+ const parts = dirs.map((d) => path.default.resolve(d).split(path.default.sep));
2795
+ const first = parts[0];
2796
+ let i = 0;
2797
+ while (i < first.length && parts.every((p) => p[i] === first[i])) i++;
2798
+ return first.slice(0, i).join(path.default.sep) || path.default.sep;
2799
+ }
2800
+ function isDbModel(value) {
2801
+ return isAnnotatedType(value) && Boolean(value.metadata?.has("db.table") || value.metadata?.has("db.view"));
2802
+ }
2803
+ /** `seen` deduplicates by identity and guarantees termination on cyclic graphs. */ function walkModels(value, out, seen) {
2804
+ if (!value || typeof value !== "object" && typeof value !== "function") return;
2805
+ if (seen.has(value)) return;
2806
+ seen.add(value);
2807
+ if (isAnnotatedType(value)) {
2808
+ if (isDbModel(value)) out.push(value);
2809
+ return;
2810
+ }
2811
+ const items = Array.isArray(value) ? value : Object.values(value);
2812
+ for (const item of items) walkModels(item, out, seen);
2813
+ }
2814
+
2622
2815
  //#endregion
2623
2816
  //#region packages/typescript/src/cli/db-sync-printer.ts
2624
2817
  function _define_property$1(obj, key, value) {
@@ -2803,25 +2996,24 @@ var DbSyncController = class {
2803
2996
  info(message) {
2804
2997
  if (!this.quiet) this.logger.log(message);
2805
2998
  }
2999
+ /** Prints each line in red and exits 1. */ fail(...lines) {
3000
+ for (const line of lines) this.logger.error(`${line}`);
3001
+ process.exit(1);
3002
+ }
2806
3003
  async dbSync(configFile, dryRun, yes, force, safe, check, format, out) {
2807
- if (format && format !== "json" && format !== "markdown") {
2808
- this.logger.error(`Unknown --format "${format}". Use "json" or "markdown".`);
2809
- process.exit(1);
2810
- }
3004
+ if (format && format !== "json" && format !== "markdown") this.fail(`Unknown --format "${format}". Use "json" or "markdown".`);
2811
3005
  this.quiet = Boolean(format) && !out;
2812
3006
  this.printer.muted = this.quiet;
2813
3007
  const config = await getConfig(configFile, this.quiet ? Object.create(this.logger, { log: { value: () => {} } }) : this.logger);
2814
- if (!config.db) {
2815
- this.logger.error("\x1B[31mNo \"db\" field in atscript config. Add a db configuration to use schema sync.\x1B[39m");
2816
- process.exit(1);
2817
- }
2818
- const [dbSpace, dbTypes] = await Promise.all([this.resolveDbSpace(config.db), this.compileAndLoadTypes(config)]);
3008
+ if (!config.db) this.fail("No \"db\" field in atscript config. Add a db configuration to use schema sync.");
3009
+ const dbTypes = await this.loadTypes(config);
2819
3010
  if (dbTypes.length === 0) {
2820
3011
  this.info(`No types with @db.table or @db.view found. Nothing to sync.`);
2821
3012
  return;
2822
3013
  }
2823
3014
  this.printer.typeCount(dbTypes.length);
2824
3015
  this.printer.banner();
3016
+ const dbSpace = await this.resolveDbSpace(config.db);
2825
3017
  const { SchemaSync } = await this.importFromCwd("@atscript/db/sync", true);
2826
3018
  const sync = new SchemaSync(dbSpace);
2827
3019
  const plan = await sync.plan(dbTypes, {
@@ -2839,10 +3031,7 @@ var DbSyncController = class {
2839
3031
  if (plan.status === "up-to-date") this.printer.planUpToDate(plan);
2840
3032
  else {
2841
3033
  this.printer.plan(plan);
2842
- if (hasErrors) {
2843
- this.logger.error(`Schema has errors. Fix the issues above before syncing.`);
2844
- process.exit(1);
2845
- }
3034
+ if (hasErrors) this.fail("Schema has errors. Fix the issues above before syncing.");
2846
3035
  }
2847
3036
  if (check || format) {
2848
3037
  if (check && hasChanges) {
@@ -2877,44 +3066,22 @@ var DbSyncController = class {
2877
3066
  });
2878
3067
  this.printer.result(result);
2879
3068
  }
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";
3069
+ /**
3070
+ * Loads the full model inventory or aborts. Diagnostics run first, every
3071
+ * generated module is imported individually, and any failure exits 1 before
3072
+ * a plan is computed.
3073
+ */ async loadTypes(config) {
2888
3074
  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);
2897
- }
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 {}
3075
+ const result = await loadDbModels({ config });
3076
+ if (result.diagnostics.errors > 0) {
3077
+ for (const message of result.diagnostics.messages) this.logger.error(message);
3078
+ this.fail("Fix the errors above before syncing.");
2916
3079
  }
2917
- return dbTypes;
3080
+ for (const message of result.diagnostics.messages) this.info(message);
3081
+ if (result.failures.length > 0) this.fail(...result.failures.map((f) => `✖ ${f.file}: ${errorMessage(f.error)}`), `Could not load ${result.failures.length} compiled model module(s); aborting before planning — a partial inventory would propose dropping tables.`);
3082
+ if (result.modelsError) this.fail(`config.models failed: ${errorMessage(result.modelsError)}`);
3083
+ if (result.packaged > 0) this.info(`Loaded ${result.packaged} packaged model(s) from config.models`);
3084
+ return result.types;
2918
3085
  }
2919
3086
  async resolveDbSpace(dbConfig) {
2920
3087
  if (typeof dbConfig === "function") {
@@ -2927,13 +3094,9 @@ var DbSyncController = class {
2927
3094
  try {
2928
3095
  mod = await this.importFromCwd(adapter);
2929
3096
  } catch {
2930
- this.logger.error(`Could not import adapter package "${adapter}". Is it installed?`);
2931
- process.exit(1);
2932
- }
2933
- if (typeof mod.createAdapter !== "function") {
2934
- this.logger.error(`Adapter package "${adapter}" does not export a createAdapter function.`);
2935
- process.exit(1);
3097
+ this.fail(`Could not import adapter package "${adapter}". Is it installed?`);
2936
3098
  }
3099
+ if (typeof mod.createAdapter !== "function") this.fail(`Adapter package "${adapter}" does not export a createAdapter function.`);
2937
3100
  const resolvedConnection = typeof connection === "function" ? await connection() : connection;
2938
3101
  return mod.createAdapter(resolvedConnection, options);
2939
3102
  }
@@ -3023,9 +3186,6 @@ DbSyncController = _ts_decorate([
3023
3186
  _ts_metadata("design:type", Function),
3024
3187
  _ts_metadata("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
3025
3188
  ], DbSyncController);
3026
- function patchAsImports(content) {
3027
- return content.replace(/(from\s+["'][^"']+)\.as(["'])/g, "$1.as.mjs$2");
3028
- }
3029
3189
 
3030
3190
  //#endregion
3031
3191
  //#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-BYtucpiS.cjs');
3
3
 
4
4
  exports.default = require_plugin.tsPlugin;
5
5
  exports.tsPlugin = require_plugin.tsPlugin;
package/dist/index.d.ts CHANGED
@@ -17,6 +17,16 @@ interface TTsPluginOptions {
17
17
  * - `true` — Import `createDataFromAnnotatedType`, create example data on each call.
18
18
  */
19
19
  exampleData?: boolean;
20
+ /**
21
+ * Extension the emitted JS uses for **relative** `.as` imports
22
+ * (`./user` → `./user.as` by default). Bare specifiers (packages, e.g.
23
+ * `some-pkg/models/user.as`) always keep `.as` because they resolve through
24
+ * the package's `exports` map.
25
+ *
26
+ * `.as.mjs` is what `asc db sync` uses to load the compiled models straight
27
+ * from Node. *(default: `'.as'`)*
28
+ */
29
+ moduleExtension?: '.as' | '.as.js' | '.as.mjs';
20
30
  }
21
31
  declare const tsPlugin: (opts?: TTsPluginOptions) => TAtscriptPlugin;
22
32
 
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-ac7ZXMDN.mjs";
2
2
 
3
3
  export { tsPlugin as default, tsPlugin };
@@ -691,6 +691,12 @@ const QUERY_OP_MAP = {
691
691
  "not exists": "$exists"
692
692
  };
693
693
  var JsRenderer = class extends BaseRenderer {
694
+ /**
695
+ * Relative imports get the configured `moduleExtension`; bare specifiers
696
+ * always keep `.as` — they resolve through the package's `exports` map.
697
+ */ transformFromPath(path) {
698
+ return (0, _atscript_core.isBareSpecifier)(path) ? `${path}.as` : `${path}${this.opts?.moduleExtension ?? ".as"}`;
699
+ }
694
700
  /**
695
701
  * Override base `unused` to subtract symbols that the JS output references
696
702
  * transitively through `extends`-resolved parent prop trees. Without this,
@@ -875,11 +881,8 @@ var JsRenderer = class extends BaseRenderer {
875
881
  const unwound = this.doc.unwindType(annotateNode.targetName);
876
882
  if (unwound?.def) {
877
883
  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;
884
+ if ((0, _atscript_core.isInterface)(def)) if (def.hasExtends) def = unwound.doc.resolveInterfaceExtends(def) || def.getDefinition() || def;
885
+ else def = def.getDefinition() || def;
883
886
  this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
884
887
  this.annotateType(def, node.id);
885
888
  this._adHocAnnotations = null;
@@ -1392,8 +1395,7 @@ var JsRenderer = class extends BaseRenderer {
1392
1395
  targetValue += "}";
1393
1396
  } else {
1394
1397
  const aSpec = spec.arguments[0];
1395
- if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
1396
- else targetValue = "true";
1398
+ targetValue = an.args[0] ? this.emitArgValue(aSpec, an.args[0]) : "true";
1397
1399
  }
1398
1400
  } else {
1399
1401
  multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
@@ -1,6 +1,6 @@
1
1
  import { l as defineAnnotatedType, t as buildJsonSchema } from "./json-schema-DycaD0Rm.mjs";
2
2
  import path from "path";
3
- import { DEFAULT_FORMAT, flattenInterfaceNode, getRelPath, hasNavPropAnnotation, isArray, isBareId, isConst, isGroup, isInterface, isPrimitive, isProp, isQueryLogical, isRef, isStructure } from "@atscript/core";
3
+ import { DEFAULT_FORMAT, flattenInterfaceNode, getRelPath, hasNavPropAnnotation, isArray, isBareId, isBareSpecifier, isConst, isGroup, isInterface, isPrimitive, isProp, isQueryLogical, isRef, isStructure } from "@atscript/core";
4
4
 
5
5
  //#region packages/typescript/src/codegen/code-printer.ts
6
6
  function _define_property$3(obj, key, value) {
@@ -663,6 +663,12 @@ const QUERY_OP_MAP = {
663
663
  "not exists": "$exists"
664
664
  };
665
665
  var JsRenderer = class extends BaseRenderer {
666
+ /**
667
+ * Relative imports get the configured `moduleExtension`; bare specifiers
668
+ * always keep `.as` — they resolve through the package's `exports` map.
669
+ */ transformFromPath(path) {
670
+ return isBareSpecifier(path) ? `${path}.as` : `${path}${this.opts?.moduleExtension ?? ".as"}`;
671
+ }
666
672
  /**
667
673
  * Override base `unused` to subtract symbols that the JS output references
668
674
  * transitively through `extends`-resolved parent prop trees. Without this,
@@ -847,11 +853,8 @@ var JsRenderer = class extends BaseRenderer {
847
853
  const unwound = this.doc.unwindType(annotateNode.targetName);
848
854
  if (unwound?.def) {
849
855
  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;
856
+ if (isInterface(def)) if (def.hasExtends) def = unwound.doc.resolveInterfaceExtends(def) || def.getDefinition() || def;
857
+ else def = def.getDefinition() || def;
855
858
  this._adHocAnnotations = this.buildAdHocMap([annotateNode]);
856
859
  this.annotateType(def, node.id);
857
860
  this._adHocAnnotations = null;
@@ -1364,8 +1367,7 @@ var JsRenderer = class extends BaseRenderer {
1364
1367
  targetValue += "}";
1365
1368
  } else {
1366
1369
  const aSpec = spec.arguments[0];
1367
- if (an.args[0]) targetValue = this.emitArgValue(aSpec, an.args[0]);
1368
- else targetValue = "true";
1370
+ targetValue = an.args[0] ? this.emitArgValue(aSpec, an.args[0]) : "true";
1369
1371
  }
1370
1372
  } else {
1371
1373
  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-BYtucpiS.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-ac7ZXMDN.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.91",
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.91"
77
77
  },
78
78
  "peerDependenciesMeta": {
79
79
  "@atscript/db": {