@atscript/typescript 0.1.92 → 0.1.93
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 +63 -44
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{plugin-BYtucpiS.cjs → plugin-B4kAIw0J.cjs} +9 -13
- package/dist/{plugin-ac7ZXMDN.mjs → plugin-C7I4ICoT.mjs} +10 -14
- package/dist/test-utils.cjs +1 -1
- package/dist/test-utils.mjs +1 -1
- package/package.json +3 -3
package/dist/cli.cjs
CHANGED
|
@@ -349,7 +349,7 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
349
349
|
this.writeln("static toJsonSchema: () => any");
|
|
350
350
|
if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
|
|
351
351
|
this.writeln("static toExampleData?: () => any");
|
|
352
|
-
if (interfaceNode &&
|
|
352
|
+
if (interfaceNode && (0, _atscript_core.isDbEntityNode)(interfaceNode)) {
|
|
353
353
|
this.renderFlat(interfaceNode);
|
|
354
354
|
this.renderOwnProps(interfaceNode);
|
|
355
355
|
this.renderNavProps(interfaceNode);
|
|
@@ -444,15 +444,6 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
444
444
|
this.popln();
|
|
445
445
|
}
|
|
446
446
|
/**
|
|
447
|
-
* Checks whether an interface is a DB entity (`@db.table` or `@db.view`).
|
|
448
|
-
*
|
|
449
|
-
* Only DB entities get `__flat`, `__pk`, `__ownProps`, and `__navProps` static properties.
|
|
450
|
-
* These exist solely to improve type-safety for filter expressions, `$select`/`$sort`,
|
|
451
|
-
* and `$with` operations in the DB layer.
|
|
452
|
-
*/ hasDbEntity(node) {
|
|
453
|
-
return !!node.annotations?.some((a) => a.name === "db.table" || a.name === "db.view" || a.name === "db.view.for");
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
447
|
* Renders the `static __flat` property — a map of all dot-notation paths
|
|
457
448
|
* to their TypeScript value types.
|
|
458
449
|
*
|
|
@@ -484,6 +475,8 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
484
475
|
* - **Intermediate paths** (structures, arrays of structures) → `never`
|
|
485
476
|
* - **`@db.json` fields** → `string` (stored as serialized JSON in DB)
|
|
486
477
|
* - **Leaf fields** → their original TypeScript type
|
|
478
|
+
* - **Optional leaf / `@db.json` fields** → `<type> | null` — the DB layer treats
|
|
479
|
+
* optional as nullable in filters, so `null` must be assignable to the path's type
|
|
487
480
|
*/ renderFlatMap(propName, flatMap, opts) {
|
|
488
481
|
if (flatMap.size === 0) return;
|
|
489
482
|
if (opts?.leadingNewline) this.writeln();
|
|
@@ -493,12 +486,15 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
493
486
|
this.write(`"${escapeQuotes(path)}"`);
|
|
494
487
|
if (descriptor.optional) this.write("?");
|
|
495
488
|
this.write(": ");
|
|
489
|
+
const nullable = descriptor.optional ? " | null" : "";
|
|
496
490
|
if (descriptor.intermediate) this.writeln("never");
|
|
497
|
-
else if (descriptor.dbJson) this.writeln(
|
|
491
|
+
else if (descriptor.dbJson) this.writeln(`string${nullable}`);
|
|
498
492
|
else {
|
|
499
493
|
const originalDef = descriptor.propNode?.getDefinition();
|
|
500
494
|
const defToRender = originalDef && !((0, _atscript_core.isGroup)(descriptor.def) && descriptor.def !== originalDef) ? originalDef : descriptor.def;
|
|
501
|
-
this.renderTypeDefString(defToRender).split("\n")
|
|
495
|
+
const lines = this.renderTypeDefString(defToRender).split("\n");
|
|
496
|
+
lines[lines.length - 1] += nullable;
|
|
497
|
+
lines.forEach((l) => this.writeln(l));
|
|
502
498
|
}
|
|
503
499
|
}
|
|
504
500
|
if (opts?.trailingNewline) this.popln();
|
|
@@ -1882,7 +1878,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
1882
1878
|
renderDimMeasure(node) {
|
|
1883
1879
|
if (!(0, _atscript_core.isInterface)(node)) return;
|
|
1884
1880
|
const interfaceNode = node;
|
|
1885
|
-
if (!
|
|
1881
|
+
if (!(0, _atscript_core.isDbEntityNode)(interfaceNode)) return;
|
|
1886
1882
|
let struct;
|
|
1887
1883
|
if (interfaceNode.hasExtends) struct = this.doc.resolveInterfaceExtends(interfaceNode);
|
|
1888
1884
|
if (!struct) struct = interfaceNode.getDefinition();
|
|
@@ -2797,15 +2793,24 @@ async function importGeneratedModules(outputs, rootDir, cwd) {
|
|
|
2797
2793
|
while (i < first.length && parts.every((p) => p[i] === first[i])) i++;
|
|
2798
2794
|
return first.slice(0, i).join(path.default.sep) || path.default.sep;
|
|
2799
2795
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2796
|
+
/**
|
|
2797
|
+
* Runtime side of `DB_ENTITY_ANNOTATIONS` — the same rule as `DbSpace.get()`
|
|
2798
|
+
* in `@atscript/db`: a type carrying only `@db.view.for` is a managed view, so
|
|
2799
|
+
* it belongs in the inventory too (leaving it out would plan the view as a drop).
|
|
2800
|
+
*
|
|
2801
|
+
* Lives here rather than in `@atscript/typescript/utils`: `utils` is the
|
|
2802
|
+
* runtime entry every generated `.as.js` module imports (browsers included)
|
|
2803
|
+
* and carries no `@atscript/core` import, which is externalized in the build.
|
|
2804
|
+
*/ function isDbEntityType(value) {
|
|
2805
|
+
if (!isAnnotatedType(value)) return false;
|
|
2806
|
+
return _atscript_core.DB_ENTITY_ANNOTATIONS.some((name) => value.metadata?.has(name));
|
|
2802
2807
|
}
|
|
2803
2808
|
/** `seen` deduplicates by identity and guarantees termination on cyclic graphs. */ function walkModels(value, out, seen) {
|
|
2804
2809
|
if (!value || typeof value !== "object" && typeof value !== "function") return;
|
|
2805
2810
|
if (seen.has(value)) return;
|
|
2806
2811
|
seen.add(value);
|
|
2807
2812
|
if (isAnnotatedType(value)) {
|
|
2808
|
-
if (
|
|
2813
|
+
if (isDbEntityType(value)) out.push(value);
|
|
2809
2814
|
return;
|
|
2810
2815
|
}
|
|
2811
2816
|
const items = Array.isArray(value) ? value : Object.values(value);
|
|
@@ -2863,7 +2868,8 @@ const PLAN_HEADER = [
|
|
|
2863
2868
|
return {
|
|
2864
2869
|
destructive: plan.entries.some((e) => e.destructive),
|
|
2865
2870
|
hasChanges: plan.entries.some((e) => e.hasChanges),
|
|
2866
|
-
hasErrors: plan.entries.some((e) => e.hasErrors)
|
|
2871
|
+
hasErrors: plan.entries.some((e) => e.hasErrors),
|
|
2872
|
+
refused: plan.entries.some((e) => e.refused)
|
|
2867
2873
|
};
|
|
2868
2874
|
}
|
|
2869
2875
|
var DbSyncPrinter = class {
|
|
@@ -2893,19 +2899,33 @@ var DbSyncPrinter = class {
|
|
|
2893
2899
|
this.printGrouped(result.entries, "result");
|
|
2894
2900
|
this.log("");
|
|
2895
2901
|
}
|
|
2896
|
-
/**
|
|
2902
|
+
/**
|
|
2903
|
+
* A refused run issued no DDL and left tracking untouched, so its `entries`
|
|
2904
|
+
* are the plan, not an outcome — only the entries that carry the refusal
|
|
2905
|
+
* (or another error) are printed, in plan mode.
|
|
2906
|
+
*/ refused(result) {
|
|
2907
|
+
this.log("");
|
|
2908
|
+
this.log(this.colors.red(this.colors.bold("Schema sync refused — nothing was applied.")));
|
|
2909
|
+
this.log("");
|
|
2910
|
+
this.printGrouped(result.entries.filter((e) => e.hasErrors), "plan");
|
|
2911
|
+
this.log("");
|
|
2912
|
+
}
|
|
2913
|
+
/**
|
|
2914
|
+
* Renders the plan as a JSON document for CI consumption. Every `SyncEntry`
|
|
2915
|
+
* field (`toInit()`) is emitted, plus its derived flags; `columnsToAdd` is
|
|
2916
|
+
* narrowed to the serializable column facts.
|
|
2917
|
+
*/ renderJson(plan) {
|
|
2897
2918
|
const doc = {
|
|
2898
2919
|
status: plan.status,
|
|
2899
2920
|
schemaHash: plan.schemaHash,
|
|
2900
2921
|
...planFlags(plan),
|
|
2901
2922
|
entries: plan.entries.map((e) => ({
|
|
2902
|
-
|
|
2923
|
+
...e.toInit(),
|
|
2903
2924
|
kind: e.viewType ? "view" : "table",
|
|
2904
|
-
viewType: e.viewType,
|
|
2905
|
-
status: e.status,
|
|
2906
2925
|
destructive: e.destructive,
|
|
2907
|
-
|
|
2908
|
-
|
|
2926
|
+
hasChanges: e.hasChanges,
|
|
2927
|
+
hasErrors: e.hasErrors,
|
|
2928
|
+
pending: e.pending,
|
|
2909
2929
|
columnsToAdd: e.columnsToAdd.map((c) => ({
|
|
2910
2930
|
path: c.path,
|
|
2911
2931
|
physicalName: c.physicalName,
|
|
@@ -2913,27 +2933,17 @@ var DbSyncPrinter = class {
|
|
|
2913
2933
|
optional: c.optional,
|
|
2914
2934
|
isPrimaryKey: c.isPrimaryKey,
|
|
2915
2935
|
storage: c.storage
|
|
2916
|
-
}))
|
|
2917
|
-
columnsToRename: e.columnsToRename,
|
|
2918
|
-
typeChanges: e.typeChanges,
|
|
2919
|
-
nullableChanges: e.nullableChanges,
|
|
2920
|
-
defaultChanges: e.defaultChanges,
|
|
2921
|
-
columnsToDrop: e.columnsToDrop,
|
|
2922
|
-
optionChanges: e.optionChanges,
|
|
2923
|
-
fkAdded: e.fkAdded,
|
|
2924
|
-
fkRemoved: e.fkRemoved,
|
|
2925
|
-
fkChanged: e.fkChanged,
|
|
2926
|
-
errors: e.errors
|
|
2936
|
+
}))
|
|
2927
2937
|
}))
|
|
2928
2938
|
};
|
|
2929
2939
|
return `${JSON.stringify(doc, void 0, 2)}\n`;
|
|
2930
2940
|
}
|
|
2931
2941
|
/** Renders the plan as a Markdown document (e.g. for PR comments). */ renderMarkdown(plan) {
|
|
2932
|
-
const { destructive } = planFlags(plan);
|
|
2942
|
+
const { destructive, refused } = planFlags(plan);
|
|
2933
2943
|
const lines = [
|
|
2934
2944
|
"# Schema Sync Plan",
|
|
2935
2945
|
"",
|
|
2936
|
-
`- **Status:** ${plan.status}${destructive ? " (destructive)" : ""}`,
|
|
2946
|
+
`- **Status:** ${plan.status}${destructive ? " (destructive)" : ""}${refused ? " (refused)" : ""}`,
|
|
2937
2947
|
`- **Schema hash:** \`${plan.schemaHash}\``,
|
|
2938
2948
|
""
|
|
2939
2949
|
];
|
|
@@ -3008,7 +3018,7 @@ var DbSyncController = class {
|
|
|
3008
3018
|
if (!config.db) this.fail("No \"db\" field in atscript config. Add a db configuration to use schema sync.");
|
|
3009
3019
|
const dbTypes = await this.loadTypes(config);
|
|
3010
3020
|
if (dbTypes.length === 0) {
|
|
3011
|
-
this.info(`No types with @db.table or @db.view found. Nothing to sync.`);
|
|
3021
|
+
this.info(`No types with @db.table, @db.view or @db.view.for found. Nothing to sync.`);
|
|
3012
3022
|
return;
|
|
3013
3023
|
}
|
|
3014
3024
|
this.printer.typeCount(dbTypes.length);
|
|
@@ -3020,7 +3030,7 @@ var DbSyncController = class {
|
|
|
3020
3030
|
force,
|
|
3021
3031
|
safe
|
|
3022
3032
|
});
|
|
3023
|
-
const { destructive: hasDestructive, hasChanges, hasErrors } = planFlags(plan);
|
|
3033
|
+
const { destructive: hasDestructive, hasChanges, hasErrors, refused } = planFlags(plan);
|
|
3024
3034
|
if (format) {
|
|
3025
3035
|
const doc = format === "json" ? this.printer.renderJson(plan) : this.printer.renderMarkdown(plan);
|
|
3026
3036
|
if (out) {
|
|
@@ -3031,7 +3041,7 @@ var DbSyncController = class {
|
|
|
3031
3041
|
if (plan.status === "up-to-date") this.printer.planUpToDate(plan);
|
|
3032
3042
|
else {
|
|
3033
3043
|
this.printer.plan(plan);
|
|
3034
|
-
if (hasErrors) this.fail("Schema has errors. Fix the issues above before syncing.");
|
|
3044
|
+
if (hasErrors) this.fail(refused ? "Schema sync would be refused — nothing would be applied. Fix the issues above." : "Schema has errors. Fix the issues above before syncing.");
|
|
3035
3045
|
}
|
|
3036
3046
|
if (check || format) {
|
|
3037
3047
|
if (check && hasChanges) {
|
|
@@ -3042,10 +3052,7 @@ var DbSyncController = class {
|
|
|
3042
3052
|
}
|
|
3043
3053
|
if (plan.status === "up-to-date") return;
|
|
3044
3054
|
if (!hasChanges) {
|
|
3045
|
-
if (!dryRun) await
|
|
3046
|
-
force: true,
|
|
3047
|
-
safe
|
|
3048
|
-
});
|
|
3055
|
+
if (!dryRun) await this.runSync(sync, dbTypes, safe);
|
|
3049
3056
|
return;
|
|
3050
3057
|
}
|
|
3051
3058
|
if (dryRun) {
|
|
@@ -3060,11 +3067,23 @@ var DbSyncController = class {
|
|
|
3060
3067
|
}
|
|
3061
3068
|
}
|
|
3062
3069
|
} else this.logger.log(`No destructive changes, proceeding to sync...`);
|
|
3070
|
+
const result = await this.runSync(sync, dbTypes, safe);
|
|
3071
|
+
this.printer.result(result);
|
|
3072
|
+
}
|
|
3073
|
+
/**
|
|
3074
|
+
* Applies the sync. A refused run (`status: 'refused'`) issued no DDL and
|
|
3075
|
+
* left tracking untouched — its refusal entries are printed and the command
|
|
3076
|
+
* exits 1 instead of reporting a successful sync.
|
|
3077
|
+
*/ async runSync(sync, dbTypes, safe) {
|
|
3063
3078
|
const result = await sync.run(dbTypes, {
|
|
3064
3079
|
force: true,
|
|
3065
3080
|
safe
|
|
3066
3081
|
});
|
|
3067
|
-
|
|
3082
|
+
if (result.status === "refused") {
|
|
3083
|
+
this.printer.refused(result);
|
|
3084
|
+
this.fail("Schema sync refused — nothing was applied. Fix the issues above and re-run.");
|
|
3085
|
+
}
|
|
3086
|
+
return result;
|
|
3068
3087
|
}
|
|
3069
3088
|
/**
|
|
3070
3089
|
* Loads the full model inventory or aborts. Diagnostics run first, every
|
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-
|
|
2
|
+
const require_plugin = require('./plugin-B4kAIw0J.cjs');
|
|
3
3
|
|
|
4
4
|
exports.default = require_plugin.tsPlugin;
|
|
5
5
|
exports.tsPlugin = require_plugin.tsPlugin;
|
package/dist/index.mjs
CHANGED
|
@@ -344,7 +344,7 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
344
344
|
this.writeln("static toJsonSchema: () => any");
|
|
345
345
|
if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
|
|
346
346
|
this.writeln("static toExampleData?: () => any");
|
|
347
|
-
if (interfaceNode &&
|
|
347
|
+
if (interfaceNode && (0, _atscript_core.isDbEntityNode)(interfaceNode)) {
|
|
348
348
|
this.renderFlat(interfaceNode);
|
|
349
349
|
this.renderOwnProps(interfaceNode);
|
|
350
350
|
this.renderNavProps(interfaceNode);
|
|
@@ -439,15 +439,6 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
439
439
|
this.popln();
|
|
440
440
|
}
|
|
441
441
|
/**
|
|
442
|
-
* Checks whether an interface is a DB entity (`@db.table` or `@db.view`).
|
|
443
|
-
*
|
|
444
|
-
* Only DB entities get `__flat`, `__pk`, `__ownProps`, and `__navProps` static properties.
|
|
445
|
-
* These exist solely to improve type-safety for filter expressions, `$select`/`$sort`,
|
|
446
|
-
* and `$with` operations in the DB layer.
|
|
447
|
-
*/ hasDbEntity(node) {
|
|
448
|
-
return !!node.annotations?.some((a) => a.name === "db.table" || a.name === "db.view" || a.name === "db.view.for");
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
442
|
* Renders the `static __flat` property — a map of all dot-notation paths
|
|
452
443
|
* to their TypeScript value types.
|
|
453
444
|
*
|
|
@@ -479,6 +470,8 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
479
470
|
* - **Intermediate paths** (structures, arrays of structures) → `never`
|
|
480
471
|
* - **`@db.json` fields** → `string` (stored as serialized JSON in DB)
|
|
481
472
|
* - **Leaf fields** → their original TypeScript type
|
|
473
|
+
* - **Optional leaf / `@db.json` fields** → `<type> | null` — the DB layer treats
|
|
474
|
+
* optional as nullable in filters, so `null` must be assignable to the path's type
|
|
482
475
|
*/ renderFlatMap(propName, flatMap, opts) {
|
|
483
476
|
if (flatMap.size === 0) return;
|
|
484
477
|
if (opts?.leadingNewline) this.writeln();
|
|
@@ -488,12 +481,15 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
488
481
|
this.write(`"${escapeQuotes(path)}"`);
|
|
489
482
|
if (descriptor.optional) this.write("?");
|
|
490
483
|
this.write(": ");
|
|
484
|
+
const nullable = descriptor.optional ? " | null" : "";
|
|
491
485
|
if (descriptor.intermediate) this.writeln("never");
|
|
492
|
-
else if (descriptor.dbJson) this.writeln(
|
|
486
|
+
else if (descriptor.dbJson) this.writeln(`string${nullable}`);
|
|
493
487
|
else {
|
|
494
488
|
const originalDef = descriptor.propNode?.getDefinition();
|
|
495
489
|
const defToRender = originalDef && !((0, _atscript_core.isGroup)(descriptor.def) && descriptor.def !== originalDef) ? originalDef : descriptor.def;
|
|
496
|
-
this.renderTypeDefString(defToRender).split("\n")
|
|
490
|
+
const lines = this.renderTypeDefString(defToRender).split("\n");
|
|
491
|
+
lines[lines.length - 1] += nullable;
|
|
492
|
+
lines.forEach((l) => this.writeln(l));
|
|
497
493
|
}
|
|
498
494
|
}
|
|
499
495
|
if (opts?.trailingNewline) this.popln();
|
|
@@ -967,7 +963,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
967
963
|
renderDimMeasure(node) {
|
|
968
964
|
if (!(0, _atscript_core.isInterface)(node)) return;
|
|
969
965
|
const interfaceNode = node;
|
|
970
|
-
if (!
|
|
966
|
+
if (!(0, _atscript_core.isDbEntityNode)(interfaceNode)) return;
|
|
971
967
|
let struct;
|
|
972
968
|
if (interfaceNode.hasExtends) struct = this.doc.resolveInterfaceExtends(interfaceNode);
|
|
973
969
|
if (!struct) struct = interfaceNode.getDefinition();
|
|
@@ -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, isBareSpecifier, isConst, isGroup, isInterface, isPrimitive, isProp, isQueryLogical, isRef, isStructure } from "@atscript/core";
|
|
3
|
+
import { DEFAULT_FORMAT, flattenInterfaceNode, getRelPath, hasNavPropAnnotation, isArray, isBareId, isBareSpecifier, isConst, isDbEntityNode, 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) {
|
|
@@ -316,7 +316,7 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
316
316
|
this.writeln("static toJsonSchema: () => any");
|
|
317
317
|
if (!this.opts?.exampleData) this.writeln("/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */");
|
|
318
318
|
this.writeln("static toExampleData?: () => any");
|
|
319
|
-
if (interfaceNode &&
|
|
319
|
+
if (interfaceNode && isDbEntityNode(interfaceNode)) {
|
|
320
320
|
this.renderFlat(interfaceNode);
|
|
321
321
|
this.renderOwnProps(interfaceNode);
|
|
322
322
|
this.renderNavProps(interfaceNode);
|
|
@@ -411,15 +411,6 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
411
411
|
this.popln();
|
|
412
412
|
}
|
|
413
413
|
/**
|
|
414
|
-
* Checks whether an interface is a DB entity (`@db.table` or `@db.view`).
|
|
415
|
-
*
|
|
416
|
-
* Only DB entities get `__flat`, `__pk`, `__ownProps`, and `__navProps` static properties.
|
|
417
|
-
* These exist solely to improve type-safety for filter expressions, `$select`/`$sort`,
|
|
418
|
-
* and `$with` operations in the DB layer.
|
|
419
|
-
*/ hasDbEntity(node) {
|
|
420
|
-
return !!node.annotations?.some((a) => a.name === "db.table" || a.name === "db.view" || a.name === "db.view.for");
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
414
|
* Renders the `static __flat` property — a map of all dot-notation paths
|
|
424
415
|
* to their TypeScript value types.
|
|
425
416
|
*
|
|
@@ -451,6 +442,8 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
451
442
|
* - **Intermediate paths** (structures, arrays of structures) → `never`
|
|
452
443
|
* - **`@db.json` fields** → `string` (stored as serialized JSON in DB)
|
|
453
444
|
* - **Leaf fields** → their original TypeScript type
|
|
445
|
+
* - **Optional leaf / `@db.json` fields** → `<type> | null` — the DB layer treats
|
|
446
|
+
* optional as nullable in filters, so `null` must be assignable to the path's type
|
|
454
447
|
*/ renderFlatMap(propName, flatMap, opts) {
|
|
455
448
|
if (flatMap.size === 0) return;
|
|
456
449
|
if (opts?.leadingNewline) this.writeln();
|
|
@@ -460,12 +453,15 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
460
453
|
this.write(`"${escapeQuotes(path)}"`);
|
|
461
454
|
if (descriptor.optional) this.write("?");
|
|
462
455
|
this.write(": ");
|
|
456
|
+
const nullable = descriptor.optional ? " | null" : "";
|
|
463
457
|
if (descriptor.intermediate) this.writeln("never");
|
|
464
|
-
else if (descriptor.dbJson) this.writeln(
|
|
458
|
+
else if (descriptor.dbJson) this.writeln(`string${nullable}`);
|
|
465
459
|
else {
|
|
466
460
|
const originalDef = descriptor.propNode?.getDefinition();
|
|
467
461
|
const defToRender = originalDef && !(isGroup(descriptor.def) && descriptor.def !== originalDef) ? originalDef : descriptor.def;
|
|
468
|
-
this.renderTypeDefString(defToRender).split("\n")
|
|
462
|
+
const lines = this.renderTypeDefString(defToRender).split("\n");
|
|
463
|
+
lines[lines.length - 1] += nullable;
|
|
464
|
+
lines.forEach((l) => this.writeln(l));
|
|
469
465
|
}
|
|
470
466
|
}
|
|
471
467
|
if (opts?.trailingNewline) this.popln();
|
|
@@ -939,7 +935,7 @@ var JsRenderer = class extends BaseRenderer {
|
|
|
939
935
|
renderDimMeasure(node) {
|
|
940
936
|
if (!isInterface(node)) return;
|
|
941
937
|
const interfaceNode = node;
|
|
942
|
-
if (!interfaceNode
|
|
938
|
+
if (!isDbEntityNode(interfaceNode)) return;
|
|
943
939
|
let struct;
|
|
944
940
|
if (interfaceNode.hasExtends) struct = this.doc.resolveInterfaceExtends(interfaceNode);
|
|
945
941
|
if (!struct) struct = interfaceNode.getDefinition();
|
package/dist/test-utils.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_plugin = require('./plugin-
|
|
2
|
+
const require_plugin = require('./plugin-B4kAIw0J.cjs');
|
|
3
3
|
let path = require("path");
|
|
4
4
|
path = require_plugin.__toESM(path);
|
|
5
5
|
let _atscript_core = require("@atscript/core");
|
package/dist/test-utils.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"description": "Atscript: typescript-gen support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
"moost": "^0.6.37"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@atscript/db": "^0.1.
|
|
70
|
+
"@atscript/db": "^0.1.128",
|
|
71
71
|
"@uniqu/core": "^0.1.7",
|
|
72
72
|
"vitest": "3.2.7"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"@atscript/db": "^0.1.97",
|
|
76
|
-
"@atscript/core": "^0.1.
|
|
76
|
+
"@atscript/core": "^0.1.93"
|
|
77
77
|
},
|
|
78
78
|
"peerDependenciesMeta": {
|
|
79
79
|
"@atscript/db": {
|