@supacloud/compiler 0.21.1 → 0.22.0

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.js CHANGED
@@ -355,7 +355,7 @@ class ModuleGenerator {
355
355
  this.imports = imports;
356
356
  this.pascal = pascalName(module.name);
357
357
  if (module.providers.some((provider) => (provider.functionalInjects?.length ?? 0) > 0) || module.controllers.some((controller) => (controller.functionalInjects?.length ?? 0) > 0)) {
358
- imports.add("runInInjectionContext", undefined, "@supacloud/app");
358
+ throw new Error("SC2012: Compiled DI requires constructor injection; property inject() is not supported.");
359
359
  }
360
360
  }
361
361
  renderFactories() {
@@ -389,6 +389,7 @@ class ModuleGenerator {
389
389
  lines.push(` jobs: ${this.renderJobs()},`);
390
390
  if (this.module.aspects && this.module.aspects.length > 0) {
391
391
  lines.push(` aspects: ${this.renderAspects(this.module.aspects)},`);
392
+ lines.push(` aspectPipeline: ${this.renderAspectPipeline(this.module.aspects)},`);
392
393
  }
393
394
  lines.push(`}`);
394
395
  return lines.join(`
@@ -465,6 +466,7 @@ class ModuleGenerator {
465
466
  }
466
467
  if (route.aspects && route.aspects.length > 0) {
467
468
  fields.push(`aspects: ${this.renderAspects(route.aspects)}`);
469
+ fields.push(`aspectPipeline: ${this.renderAspectPipeline(route.aspects)}`);
468
470
  }
469
471
  const invokerArgs = (route.handlerParams ?? []).map((hp) => {
470
472
  if (hp.kind === "param") {
@@ -545,7 +547,7 @@ ${indent(item, 2)}`).join(",")}
545
547
  `idempotency: ${JSON.stringify(command.idempotency)}`,
546
548
  ...command.rpc ? [`rpc: ${JSON.stringify(command.rpc)}`] : [],
547
549
  ...command.standalone ? ["standalone: true"] : [],
548
- ...command.aspects && command.aspects.length > 0 ? [`aspects: ${this.renderAspects(command.aspects)}`] : []
550
+ ...command.aspects && command.aspects.length > 0 ? [`aspects: ${this.renderAspects(command.aspects)}`, `aspectPipeline: ${this.renderAspectPipeline(command.aspects)}`] : []
549
551
  ];
550
552
  return `{ ${fields.join(", ")} }`;
551
553
  }).join(", ")}]`;
@@ -578,6 +580,7 @@ ${indent(item, 2)}`).join(",")}
578
580
  fields.push(`idempotency: ${JSON.stringify(job.idempotency)}`);
579
581
  if (job.aspects && job.aspects.length > 0) {
580
582
  fields.push(`aspects: ${this.renderAspects(job.aspects)}`);
583
+ fields.push(`aspectPipeline: ${this.renderAspectPipeline(job.aspects)}`);
581
584
  }
582
585
  return `{ ${fields.join(", ")}, }`;
583
586
  }).join(", ")}]`;
@@ -585,6 +588,24 @@ ${indent(item, 2)}`).join(",")}
585
588
  renderAspects(aspects) {
586
589
  return `[${aspects.map((aspect) => this.imports.add(aspect.name, aspect.importPath, aspect.importModule)).join(", ")}]`;
587
590
  }
591
+ renderAspectPipeline(aspects) {
592
+ const lines = [
593
+ `async (context, next, observe) => {`,
594
+ ` const state = { active: true };`,
595
+ ` const step${aspects.length} = compiledAspectNext(next, state);`
596
+ ];
597
+ for (let index = aspects.length - 1;index >= 0; index--) {
598
+ const aspect = aspects[index];
599
+ if (!aspect)
600
+ continue;
601
+ const name = this.imports.add(aspect.name, aspect.importPath, aspect.importModule);
602
+ const stage = JSON.stringify(`aspect[${index}]:${aspect.name}`);
603
+ lines.push(` const step${index} = compiledAspectNext(() => observeCompiledAspect(observe, ${stage}, () => ${name}(context, step${index + 1})), state);`);
604
+ }
605
+ lines.push(` try { return await step0(); } finally { state.active = false; }`, `}`);
606
+ return lines.join(`
607
+ `);
608
+ }
588
609
  renderServicesFactory() {
589
610
  return [
590
611
  `function create${this.pascal}Services(`,
@@ -699,7 +720,7 @@ ${indent(item, 2)}`).join(",")}
699
720
  const args = provider.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(provider, dep), `ConstructorParameters<typeof ${useClass}>[${index}]`)).join(", ");
700
721
  const local = this.localVar(isMulti ? provider.useClass ?? `${provider.token}Item` : provider.token, kind);
701
722
  return {
702
- constLine: `const ${local} = ${this.instantiate(useClass, args, kind, provider.functionalInjects)};`,
723
+ constLine: `const ${local} = new ${useClass}(${args});`,
703
724
  key,
704
725
  expr: local
705
726
  };
@@ -735,32 +756,11 @@ ${indent(item, 2)}`).join(",")}
735
756
  const key = camelName(controller.className);
736
757
  const local = this.localVar(controller.className, kind);
737
758
  return {
738
- constLine: `const ${local} = ${this.instantiate(className, args, kind, controller.functionalInjects)};`,
759
+ constLine: `const ${local} = new ${className}(${args});`,
739
760
  key,
740
761
  expr: local
741
762
  };
742
763
  }
743
- instantiate(className, args, kind, functionalInjects) {
744
- if (!functionalInjects || functionalInjects.length === 0) {
745
- return `new ${className}(${args})`;
746
- }
747
- const clauses = functionalInjects.map((entry) => {
748
- const token = this.imports.add(entry.expression, entry.importPath, entry.importModule);
749
- const value = this.depExpr(entry.token, kind, entry);
750
- return `if (token === ${token}) return ${value} as T;`;
751
- });
752
- const missing = `if (options?.optional) return undefined; throw new Error("Static inject token not available: " + String(token));`;
753
- const injector = [
754
- `{`,
755
- `get<T>(token: unknown, options?: { optional?: boolean; self?: boolean; skipSelf?: boolean; host?: boolean }): T | undefined {`,
756
- ...clauses,
757
- missing,
758
- `},`,
759
- `}`
760
- ].join(`
761
- `);
762
- return `runInInjectionContext(${injector}, () => new ${className}(${args}))`;
763
- }
764
764
  localVar(token, kind) {
765
765
  const locals = this.locals[kind];
766
766
  const existing = locals.get(token);
@@ -1933,6 +1933,7 @@ var HEADER = "// GENERATED BY @supacloud/compiler — do not edit", INTERFACES =
1933
1933
  title?: string;
1934
1934
  data?: Record<string, unknown>;
1935
1935
  aspects?: CompiledAspect[];
1936
+ aspectPipeline?: CompiledAspectPipeline;
1936
1937
  invoker?: (
1937
1938
  controller: unknown,
1938
1939
  request: {
@@ -1956,6 +1957,7 @@ export interface CompiledCommand {
1956
1957
  idempotency: "required" | "none";
1957
1958
  standalone?: boolean;
1958
1959
  aspects?: CompiledAspect[];
1960
+ aspectPipeline?: CompiledAspectPipeline;
1959
1961
  }
1960
1962
 
1961
1963
  export interface CompiledJob {
@@ -1970,6 +1972,7 @@ export interface CompiledJob {
1970
1972
  maxAttempts?: number;
1971
1973
  idempotency?: "required" | "none";
1972
1974
  aspects?: CompiledAspect[];
1975
+ aspectPipeline?: CompiledAspectPipeline;
1973
1976
  }
1974
1977
 
1975
1978
  export interface CompiledAspectContext {
@@ -2017,7 +2020,24 @@ export interface CompiledModule {
2017
2020
  commands: CompiledCommand[];
2018
2021
  jobs: CompiledJob[];
2019
2022
  aspects?: CompiledAspect[];
2020
- }`, TYPE_GUARDS = `function isRecord(value: unknown): value is Record<string, unknown> {
2023
+ aspectPipeline?: CompiledAspectPipeline;
2024
+ }`, TYPE_GUARDS = `type CompiledAspectObserver = (stage: string, run: () => unknown | Promise<unknown>) => unknown | Promise<unknown>;
2025
+ type CompiledAspectPipeline = (context: CompiledAspectContext, next: () => unknown | Promise<unknown>, observe?: CompiledAspectObserver) => unknown | Promise<unknown>;
2026
+
2027
+ function compiledAspectNext(next: () => unknown | Promise<unknown>, state: { active: boolean }): () => Promise<unknown> {
2028
+ let called = false;
2029
+ return async () => {
2030
+ if (!state.active) throw new Error("Aspect continuation is closed");
2031
+ if (called) throw new Error("Aspect continuation called multiple times");
2032
+ called = true;
2033
+ return await next();
2034
+ };
2035
+ }
2036
+ function observeCompiledAspect(observe: CompiledAspectObserver | undefined, stage: string, run: () => unknown | Promise<unknown>): unknown | Promise<unknown> {
2037
+ return observe ? observe(stage, run) : run();
2038
+ }
2039
+
2040
+ function isRecord(value: unknown): value is Record<string, unknown> {
2021
2041
  return typeof value === "object" && value !== null;
2022
2042
  }
2023
2043
 
@@ -2199,7 +2219,7 @@ var init_graphql_options = __esm(() => {
2199
2219
 
2200
2220
  // src/graphql-inputs.ts
2201
2221
  import { resolve as resolve3 } from "node:path";
2202
- import * as ts5 from "@typescript/typescript6";
2222
+ import * as ts7 from "@typescript/typescript6";
2203
2223
  function graphqlInputPaths(options) {
2204
2224
  if (!options.graphql)
2205
2225
  return [];
@@ -2210,7 +2230,7 @@ function graphqlInputPaths(options) {
2210
2230
  }
2211
2231
  const root = resolve3(options.rootDir);
2212
2232
  const schema = resolve3(root, options.graphql.schema);
2213
- const documents = ts5.sys.readDirectory(root, [".graphql", ".gql"], ["**/node_modules/**", "**/.git/**", resolve3(options.outDir)], options.graphql.documents ?? ["**/*.graphql", "**/*.gql"]).map((path) => resolve3(path)).filter((path) => path !== schema);
2233
+ const documents = ts7.sys.readDirectory(root, [".graphql", ".gql"], ["**/node_modules/**", "**/.git/**", resolve3(options.outDir)], options.graphql.documents ?? ["**/*.graphql", "**/*.gql"]).map((path) => resolve3(path)).filter((path) => path !== schema);
2214
2234
  return [schema, ...[...new Set(documents)].sort()];
2215
2235
  }
2216
2236
  var init_graphql_inputs = __esm(() => {
@@ -2218,7 +2238,7 @@ var init_graphql_inputs = __esm(() => {
2218
2238
  });
2219
2239
 
2220
2240
  // src/graphql-runtime.ts
2221
- import * as ts6 from "@typescript/typescript6";
2241
+ import * as ts8 from "@typescript/typescript6";
2222
2242
  import { resolve as resolve4 } from "node:path";
2223
2243
  function renderGraphqlValidators(source, operationNames) {
2224
2244
  const fileName = resolve4("/__supacloud_graphql__/contracts.ts");
@@ -2230,18 +2250,18 @@ function renderGraphqlValidators(source, operationNames) {
2230
2250
  noPropertyAccessFromIndexSignature: true,
2231
2251
  noFallthroughCasesInSwitch: true,
2232
2252
  skipLibCheck: false,
2233
- target: ts6.ScriptTarget.ES2022,
2253
+ target: ts8.ScriptTarget.ES2022,
2234
2254
  lib: ["lib.es2022.d.ts"],
2235
2255
  types: [],
2236
2256
  noEmit: true
2237
2257
  };
2238
- const host = ts6.createCompilerHost(options);
2258
+ const host = ts8.createCompilerHost(options);
2239
2259
  const getSourceFile = host.getSourceFile.bind(host);
2240
- host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => path === fileName ? ts6.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
2241
- const program = ts6.createProgram([fileName], options, host);
2242
- const diagnostics = ts6.getPreEmitDiagnostics(program);
2260
+ host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => path === fileName ? ts8.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
2261
+ const program = ts8.createProgram([fileName], options, host);
2262
+ const diagnostics = ts8.getPreEmitDiagnostics(program);
2243
2263
  if (diagnostics.length) {
2244
- throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts6.flattenDiagnosticMessageText(item.messageText, `
2264
+ throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts8.flattenDiagnosticMessageText(item.messageText, `
2245
2265
  `)).join("; ")}`);
2246
2266
  }
2247
2267
  const checker = program.getTypeChecker();
@@ -2271,25 +2291,25 @@ function renderGraphqlValidators(source, operationNames) {
2271
2291
  return name;
2272
2292
  }
2273
2293
  function expression(type) {
2274
- if (type.flags & ts6.TypeFlags.Any)
2294
+ if (type.flags & ts8.TypeFlags.Any)
2275
2295
  return unsupported(type);
2276
- if (type.flags & ts6.TypeFlags.Unknown)
2296
+ if (type.flags & ts8.TypeFlags.Unknown)
2277
2297
  return "true";
2278
- if (type.flags & ts6.TypeFlags.Never)
2298
+ if (type.flags & ts8.TypeFlags.Never)
2279
2299
  return "false";
2280
- if (type.flags & ts6.TypeFlags.Null)
2300
+ if (type.flags & ts8.TypeFlags.Null)
2281
2301
  return "value === null";
2282
- if (type.flags & ts6.TypeFlags.Undefined)
2302
+ if (type.flags & ts8.TypeFlags.Undefined)
2283
2303
  return "value === undefined";
2284
2304
  if (type.isStringLiteral() || type.isNumberLiteral())
2285
2305
  return `value === ${JSON.stringify(type.value)}`;
2286
- if (type.flags & ts6.TypeFlags.BooleanLiteral)
2306
+ if (type.flags & ts8.TypeFlags.BooleanLiteral)
2287
2307
  return `value === ${checker.typeToString(type)}`;
2288
- if (type.flags & ts6.TypeFlags.String)
2308
+ if (type.flags & ts8.TypeFlags.String)
2289
2309
  return 'typeof value === "string"';
2290
- if (type.flags & ts6.TypeFlags.Number)
2310
+ if (type.flags & ts8.TypeFlags.Number)
2291
2311
  return 'typeof value === "number" && Number.isFinite(value)';
2292
- if (type.flags & ts6.TypeFlags.Boolean)
2312
+ if (type.flags & ts8.TypeFlags.Boolean)
2293
2313
  return 'typeof value === "boolean"';
2294
2314
  if (type.isUnion())
2295
2315
  return type.types.map((part) => `${reference(part)}(value)`).join(" || ");
@@ -2298,16 +2318,16 @@ function renderGraphqlValidators(source, operationNames) {
2298
2318
  if (checker.isTupleType(type))
2299
2319
  return unsupported(type);
2300
2320
  if (checker.isArrayType(type)) {
2301
- const item = checker.getIndexTypeOfType(type, ts6.IndexKind.Number);
2321
+ const item = checker.getIndexTypeOfType(type, ts8.IndexKind.Number);
2302
2322
  if (!item)
2303
2323
  return unsupported(type);
2304
2324
  return `isGraphqlArray(value) && Array.from(value).every(${reference(item)})`;
2305
2325
  }
2306
- if (type.flags & ts6.TypeFlags.Object) {
2326
+ if (type.flags & ts8.TypeFlags.Object) {
2307
2327
  if (type.getCallSignatures().length || type.getConstructSignatures().length)
2308
2328
  return unsupported(type);
2309
2329
  const indexes = checker.getIndexInfosOfType(type);
2310
- if (indexes.some((index) => !(index.keyType.flags & ts6.TypeFlags.String)))
2330
+ if (indexes.some((index) => !(index.keyType.flags & ts8.TypeFlags.String)))
2311
2331
  return unsupported(type);
2312
2332
  const properties = checker.getPropertiesOfType(type).map((property) => {
2313
2333
  const declaration = property.valueDeclaration ?? property.declarations?.[0];
@@ -2316,7 +2336,7 @@ function renderGraphqlValidators(source, operationNames) {
2316
2336
  const check = reference(checker.getTypeOfSymbolAtLocation(property, declaration));
2317
2337
  const key = JSON.stringify(property.name);
2318
2338
  const present = `Object.prototype.hasOwnProperty.call(value, ${key})`;
2319
- return property.flags & ts6.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
2339
+ return property.flags & ts8.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
2320
2340
  });
2321
2341
  const indexedValues = indexes.map((index) => `Object.values(value).every(${reference(index.type)})`);
2322
2342
  return ["isGraphqlRecord(value)", ...properties, ...indexedValues].join(" && ");
@@ -2574,10 +2594,155 @@ var init_graphql = __esm(() => {
2574
2594
  init_graphql_runtime();
2575
2595
  });
2576
2596
 
2577
- // src/graphql-schema.ts
2578
- import { mkdir as mkdir5, readFile as readFile11 } from "node:fs/promises";
2597
+ // src/database-contracts.ts
2579
2598
  import { createHash as createHash9 } from "node:crypto";
2580
- import { dirname as dirname10, resolve as resolve15 } from "node:path";
2599
+ import { mkdir as mkdir5, readFile as readFile11 } from "node:fs/promises";
2600
+ import { dirname as dirname10, relative as relative12, resolve as resolve15 } from "node:path";
2601
+ import * as ts13 from "@typescript/typescript6";
2602
+ function hash2(value) {
2603
+ return createHash9("sha256").update(value).digest("hex");
2604
+ }
2605
+ function importPath(out, path) {
2606
+ const value = relative12(out, path).replaceAll("\\", "/").replace(/\.(?:d\.)?[cm]?ts$/, "");
2607
+ return value.startsWith(".") ? value : `./${value}`;
2608
+ }
2609
+ function parseDatabaseContractsOptions(value, directory) {
2610
+ if (!value || typeof value !== "object" || Array.isArray(value))
2611
+ throw new TypeError("Expected database contracts configuration");
2612
+ const allowed = ["rootDir", "outDir", "postgrestTypes", "drizzleSchema", "role", "graphql", "migrations"];
2613
+ if (Object.keys(value).some((name) => !allowed.includes(name)))
2614
+ throw new TypeError("Unknown database contracts option");
2615
+ const field = (name) => {
2616
+ const result = Reflect.get(value, name);
2617
+ if (typeof result !== "string" || !result.trim())
2618
+ throw new TypeError(`Missing database contracts ${name}`);
2619
+ return result;
2620
+ };
2621
+ const graphql = Reflect.get(value, "graphql");
2622
+ assertGraphqlOptions(graphql);
2623
+ const migrations = Reflect.get(value, "migrations");
2624
+ if (!Array.isArray(migrations) || !migrations.every((entry) => typeof entry === "string" && entry.endsWith(".sql"))) {
2625
+ throw new TypeError("migrations must be an ordered list of SQL files");
2626
+ }
2627
+ return {
2628
+ rootDir: resolve15(directory, field("rootDir")),
2629
+ outDir: resolve15(directory, field("outDir")),
2630
+ postgrestTypes: resolve15(directory, field("postgrestTypes")),
2631
+ drizzleSchema: resolve15(directory, field("drizzleSchema")),
2632
+ role: field("role"),
2633
+ graphql: { ...graphql, schema: resolve15(directory, graphql.schema) },
2634
+ migrations: migrations.map((file) => resolve15(directory, file))
2635
+ };
2636
+ }
2637
+ async function generateDatabaseContracts(options, check = false) {
2638
+ const rootDir = resolve15(options.rootDir), outDir = resolve15(options.outDir);
2639
+ const postgrestTypes = resolve15(rootDir, options.postgrestTypes), drizzleSchema = resolve15(rootDir, options.drizzleSchema);
2640
+ const snapshot = await readFile11(postgrestTypes, "utf8");
2641
+ const syntax = ts13.createSourceFile(postgrestTypes, snapshot, ts13.ScriptTarget.Latest, true);
2642
+ const database = syntax.statements.find((node) => (ts13.isTypeAliasDeclaration(node) || ts13.isInterfaceDeclaration(node)) && node.name.text === "Database" && node.modifiers?.some((modifier) => modifier.kind === ts13.SyntaxKind.ExportKeyword));
2643
+ if (!database)
2644
+ throw new Error("PostgREST snapshot must export Database from the official type generator");
2645
+ const program = ts13.createProgram([postgrestTypes], {
2646
+ strict: true,
2647
+ noEmit: true,
2648
+ skipLibCheck: true,
2649
+ types: [],
2650
+ target: ts13.ScriptTarget.ES2022,
2651
+ module: ts13.ModuleKind.ESNext,
2652
+ moduleResolution: ts13.ModuleResolutionKind.Bundler
2653
+ });
2654
+ if (ts13.getPreEmitDiagnostics(program).length)
2655
+ throw new Error("PostgREST snapshot has TypeScript errors");
2656
+ const artifacts = await renderGraphql({
2657
+ rootDir,
2658
+ outDir,
2659
+ graphql: options.graphql
2660
+ });
2661
+ if (artifacts.diagnostics.some((item) => item.severity === "error")) {
2662
+ throw new Error(artifacts.diagnostics.map((item) => item.message).join(`
2663
+ `));
2664
+ }
2665
+ const inputs = {};
2666
+ const addInput = async (path) => {
2667
+ const absolute = resolve15(rootDir, path);
2668
+ inputs[relative12(rootDir, absolute).replaceAll("\\", "/")] = hash2(await readFile11(absolute, "utf8"));
2669
+ };
2670
+ await addInput(postgrestTypes);
2671
+ await addInput(drizzleSchema);
2672
+ const drizzleProgram = ts13.createProgram([drizzleSchema], {
2673
+ noEmit: true,
2674
+ moduleResolution: ts13.ModuleResolutionKind.Bundler,
2675
+ module: ts13.ModuleKind.ESNext,
2676
+ target: ts13.ScriptTarget.ES2022,
2677
+ types: [],
2678
+ skipLibCheck: true
2679
+ });
2680
+ for (const source of drizzleProgram.getSourceFiles()) {
2681
+ if (!source.isDeclarationFile && !source.fileName.includes("/node_modules/"))
2682
+ await addInput(source.fileName);
2683
+ }
2684
+ await addInput(resolve15(rootDir, options.graphql.schema));
2685
+ if (new Set(options.migrations.map((path) => resolve15(rootDir, path))).size !== options.migrations.length) {
2686
+ throw new Error("Duplicate migration in database contracts configuration");
2687
+ }
2688
+ for (const path of options.migrations)
2689
+ await addInput(path);
2690
+ const files = {
2691
+ ...artifacts.files,
2692
+ "database.ts": [
2693
+ "// GENERATED BY @supacloud/compiler database-contracts. Do not edit.",
2694
+ `export type { Database } from ${JSON.stringify(importPath(outDir, postgrestTypes))};`,
2695
+ 'export type { QueryData, QueryResult, QueryError } from "@supabase/supabase-js";',
2696
+ `export type DrizzleSchema = typeof import(${JSON.stringify(importPath(outDir, drizzleSchema))});`,
2697
+ 'export * from "./graphql";',
2698
+ ""
2699
+ ].join(`
2700
+ `)
2701
+ };
2702
+ const manifest = {
2703
+ version: 1,
2704
+ role: options.role,
2705
+ inputs: Object.fromEntries(Object.entries(inputs).sort(([a], [b]) => a.localeCompare(b))),
2706
+ migrationOrder: options.migrations.map((path) => relative12(rootDir, resolve15(rootDir, path)).replaceAll("\\", "/")),
2707
+ outputs: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([file, text]) => [file, hash2(text)]))
2708
+ };
2709
+ files["database.manifest.json"] = JSON.stringify(manifest, null, 2) + `
2710
+ `;
2711
+ const mismatches = [];
2712
+ for (const [file, content] of Object.entries(files)) {
2713
+ const path = resolve15(outDir, file);
2714
+ let current;
2715
+ try {
2716
+ current = await readFile11(path, "utf8");
2717
+ } catch (error) {
2718
+ if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
2719
+ throw error;
2720
+ }
2721
+ if (current !== content)
2722
+ mismatches.push(file);
2723
+ }
2724
+ if (!check) {
2725
+ await mkdir5(outDir, { recursive: true });
2726
+ for (const [file, content] of Object.entries(files))
2727
+ await writeFileIfChanged(resolve15(outDir, file), content);
2728
+ }
2729
+ return { upToDate: mismatches.length === 0, mismatches, written: check ? [] : mismatches, manifest };
2730
+ }
2731
+ async function runDatabaseContractsFile(path, check = false) {
2732
+ const absolute = resolve15(path);
2733
+ const value = JSON.parse(await readFile11(absolute, "utf8"));
2734
+ return generateDatabaseContracts(parseDatabaseContractsOptions(value, dirname10(absolute)), check);
2735
+ }
2736
+ var init_database_contracts = __esm(() => {
2737
+ init_graphql();
2738
+ init_generate();
2739
+ init_graphql_options();
2740
+ });
2741
+
2742
+ // src/graphql-schema.ts
2743
+ import { mkdir as mkdir6, readFile as readFile12 } from "node:fs/promises";
2744
+ import { createHash as createHash10 } from "node:crypto";
2745
+ import { dirname as dirname11, resolve as resolve16 } from "node:path";
2581
2746
  async function pullGraphqlSchema(options) {
2582
2747
  assertGraphqlOptions({ schema: options.output });
2583
2748
  const endpoint = new URL(options.url);
@@ -2617,7 +2782,7 @@ async function pullGraphqlSchema(options) {
2617
2782
  throw new Error("GraphQL schema export failed. Verify caller grants and enable introspection only in the intended development environment.");
2618
2783
  }
2619
2784
  const schema = lexicographicSortSchema(buildClientSchema(data));
2620
- const path = resolve15(options.output);
2785
+ const path = resolve16(options.output);
2621
2786
  const content = path.endsWith(".json") ? JSON.stringify(introspectionFromSchema(schema), null, 2) + `
2622
2787
  ` : `# GENERATED BY supacloud-compiler graphql-schema. DO NOT EDIT.
2623
2788
  # Database First: change database declarations, apply migrations, then re-export for the intended role.
@@ -2625,16 +2790,16 @@ async function pullGraphqlSchema(options) {
2625
2790
  `;
2626
2791
  let previous;
2627
2792
  try {
2628
- previous = await readFile11(path, "utf8");
2793
+ previous = await readFile12(path, "utf8");
2629
2794
  } catch (error) {
2630
2795
  if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
2631
2796
  throw error;
2632
2797
  }
2633
2798
  const upToDate = previous === content;
2634
- const schemaHash = createHash9("sha256").update(content).digest("hex");
2799
+ const schemaHash = createHash10("sha256").update(content).digest("hex");
2635
2800
  if (options.check)
2636
2801
  return { path, schemaHash, upToDate, written: false };
2637
- await mkdir5(dirname10(path), { recursive: true });
2802
+ await mkdir6(dirname11(path), { recursive: true });
2638
2803
  await writeFileIfChanged(path, content);
2639
2804
  return { path, schemaHash, upToDate: true, written: true };
2640
2805
  }
@@ -2644,13 +2809,13 @@ var init_graphql_schema = __esm(() => {
2644
2809
  });
2645
2810
 
2646
2811
  // src/cli.ts
2647
- import { resolve as resolve16 } from "node:path";
2648
- import { readFile as readFile12 } from "node:fs/promises";
2812
+ import { resolve as resolve17 } from "node:path";
2813
+ import { readFile as readFile13 } from "node:fs/promises";
2649
2814
 
2650
2815
  // src/analyze.ts
2651
2816
  import { createHash as createHash3 } from "node:crypto";
2652
2817
  import { relative as relative2, resolve as resolvePath, sep as sep2 } from "node:path";
2653
- import * as ts3 from "@typescript/typescript6";
2818
+ import * as ts4 from "@typescript/typescript6";
2654
2819
 
2655
2820
  // src/program.ts
2656
2821
  import { createHash as createHash2 } from "node:crypto";
@@ -3300,6 +3465,7 @@ var COMPILER_DIAGNOSTIC_CODES = {
3300
3465
  "missing-token-factory": { code: "SC2009", docsUrl: "https://supacloud.dev/errors/SC2009" },
3301
3466
  "provider-type-mismatch": { code: "SC2010", docsUrl: "https://supacloud.dev/errors/SC2010" },
3302
3467
  "unsupported-provider-helper": { code: "SC2011", docsUrl: "https://supacloud.dev/errors/SC2011" },
3468
+ "runtime-injection-disallowed": { code: "SC2012", docsUrl: "https://supacloud.dev/errors/SC2012" },
3303
3469
  "command-missing-permission": { code: "SC4001", docsUrl: "https://supacloud.dev/errors/SC4001" },
3304
3470
  "duplicate-command": { code: "SC4002", docsUrl: "https://supacloud.dev/errors/SC4002" },
3305
3471
  "route-command-unresolved": { code: "SC4003", docsUrl: "https://supacloud.dev/errors/SC4003" },
@@ -3346,6 +3512,20 @@ var COMPILER_DIAGNOSTIC_CODES = {
3346
3512
  function validateGraph(graph, options = false) {
3347
3513
  const strict = typeof options === "boolean" ? options : options.strict ?? false;
3348
3514
  const diagnostics = [];
3515
+ for (const module of graph.modules) {
3516
+ for (const owner of [...module.providers, ...module.controllers]) {
3517
+ if (owner.functionalInjects?.length)
3518
+ diagnostics.push({
3519
+ severity: "error",
3520
+ code: "runtime-injection-disallowed",
3521
+ errorCode: "SC2012",
3522
+ docsUrl: "https://supacloud.dev/errors/SC2012",
3523
+ file: owner.file,
3524
+ message: "Property inject() requires runtime token resolution. Compiled applications require constructor injection.",
3525
+ suggestion: "Move injected fields into typed constructor parameters with @Inject(TOKEN) where needed."
3526
+ });
3527
+ }
3528
+ }
3349
3529
  let moduleBoundaries;
3350
3530
  if (typeof options === "object") {
3351
3531
  try {
@@ -4126,6 +4306,67 @@ function detectOrphanModules(graph) {
4126
4306
  }
4127
4307
  return diagnostics;
4128
4308
  }
4309
+ // src/static-di.ts
4310
+ import * as ts3 from "@typescript/typescript6";
4311
+ var runtimeApis = new Set([
4312
+ "inject",
4313
+ "createEnvironmentInjector",
4314
+ "runInInjectionContext",
4315
+ "EnvironmentInjector",
4316
+ "bootstrapBun",
4317
+ "runInScope",
4318
+ "runInRequestContext",
4319
+ "runInJobContext",
4320
+ "runInTransactionContext"
4321
+ ]);
4322
+ function scanRuntimeDi(source, file) {
4323
+ const diagnostics = [];
4324
+ const namespaces = new Set;
4325
+ const report = (node) => diagnostics.push({
4326
+ severity: "error",
4327
+ code: "runtime-injection-disallowed",
4328
+ errorCode: "SC2012",
4329
+ docsUrl: "https://supacloud.dev/errors/SC2012",
4330
+ file,
4331
+ line: source.getLineAndCharacterOfPosition(node.getStart()).line + 1,
4332
+ message: "Compiled applications cannot import runtime DI. Use explicit constructors and generated scope factories."
4333
+ });
4334
+ for (const statement of source.statements) {
4335
+ if (!(ts3.isImportDeclaration(statement) || ts3.isExportDeclaration(statement)) || !statement.moduleSpecifier || !ts3.isStringLiteral(statement.moduleSpecifier) || !/^@supacloud\/app(?:\/|$)/.test(statement.moduleSpecifier.text))
4336
+ continue;
4337
+ if (ts3.isImportDeclaration(statement)) {
4338
+ if (statement.importClause?.isTypeOnly)
4339
+ continue;
4340
+ const binding = statement.importClause?.namedBindings;
4341
+ if (binding && ts3.isNamespaceImport(binding))
4342
+ namespaces.add(binding.name.text);
4343
+ if (binding && ts3.isNamedImports(binding))
4344
+ for (const item of binding.elements) {
4345
+ if (!item.isTypeOnly && runtimeApis.has((item.propertyName ?? item.name).text))
4346
+ report(item);
4347
+ }
4348
+ } else if (!statement.isTypeOnly) {
4349
+ if (!statement.exportClause)
4350
+ report(statement);
4351
+ else if (ts3.isNamedExports(statement.exportClause))
4352
+ for (const item of statement.exportClause.elements) {
4353
+ if (!item.isTypeOnly && runtimeApis.has((item.propertyName ?? item.name).text))
4354
+ report(item);
4355
+ }
4356
+ }
4357
+ }
4358
+ const visit = (node) => {
4359
+ if (ts3.isPropertyAccessExpression(node) && ts3.isIdentifier(node.expression) && namespaces.has(node.expression.text) && runtimeApis.has(node.name.text))
4360
+ report(node);
4361
+ if (ts3.isElementAccessExpression(node) && ts3.isIdentifier(node.expression) && namespaces.has(node.expression.text) && (!ts3.isStringLiteral(node.argumentExpression) || runtimeApis.has(node.argumentExpression.text)))
4362
+ report(node);
4363
+ if (ts3.isVariableDeclaration(node) && node.initializer && ts3.isIdentifier(node.initializer) && namespaces.has(node.initializer.text))
4364
+ report(node);
4365
+ ts3.forEachChild(node, visit);
4366
+ };
4367
+ visit(source);
4368
+ return diagnostics;
4369
+ }
4129
4370
 
4130
4371
  // src/analyze.ts
4131
4372
  var DEFAULT_INCLUDE = ["**/*.module.ts", "**/*.ts"];
@@ -4167,26 +4408,26 @@ function lineOf(node) {
4167
4408
  return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
4168
4409
  }
4169
4410
  function variableName(decl) {
4170
- return ts3.isIdentifier(decl.name) ? decl.name.text : nodeText(decl.name);
4411
+ return ts4.isIdentifier(decl.name) ? decl.name.text : nodeText(decl.name);
4171
4412
  }
4172
4413
  function propertyName(name) {
4173
- if (ts3.isIdentifier(name) || ts3.isPrivateIdentifier(name))
4414
+ if (ts4.isIdentifier(name) || ts4.isPrivateIdentifier(name))
4174
4415
  return name.text;
4175
- if (ts3.isStringLiteral(name) || ts3.isNumericLiteral(name))
4416
+ if (ts4.isStringLiteral(name) || ts4.isNumericLiteral(name))
4176
4417
  return name.text;
4177
4418
  return nodeText(name);
4178
4419
  }
4179
4420
  function parameterName(param) {
4180
- return ts3.isIdentifier(param.name) ? param.name.text : nodeText(param.name);
4421
+ return ts4.isIdentifier(param.name) ? param.name.text : nodeText(param.name);
4181
4422
  }
4182
4423
  function decoratorsOf(node) {
4183
- return ts3.canHaveDecorators(node) ? ts3.getDecorators(node) ?? [] : [];
4424
+ return ts4.canHaveDecorators(node) ? ts4.getDecorators(node) ?? [] : [];
4184
4425
  }
4185
4426
  function decoratorArguments(dec) {
4186
- return ts3.isCallExpression(dec.expression) ? dec.expression.arguments : [];
4427
+ return ts4.isCallExpression(dec.expression) ? dec.expression.arguments : [];
4187
4428
  }
4188
4429
  function hasMethod(cls, name) {
4189
- return cls.members.some((member) => (ts3.isMethodDeclaration(member) || ts3.isGetAccessorDeclaration(member) || ts3.isSetAccessorDeclaration(member)) && member.name !== undefined && propertyName(member.name) === name);
4430
+ return cls.members.some((member) => (ts4.isMethodDeclaration(member) || ts4.isGetAccessorDeclaration(member) || ts4.isSetAccessorDeclaration(member)) && member.name !== undefined && propertyName(member.name) === name);
4190
4431
  }
4191
4432
  function hasDestroyHook(cls) {
4192
4433
  return hasMethod(cls, "onDestroy") || hasMethod(cls, "ngOnDestroy");
@@ -4196,7 +4437,7 @@ function descendantsOfKind(root, predicate) {
4196
4437
  const visit = (node) => {
4197
4438
  if (predicate(node))
4198
4439
  result.push(node);
4199
- ts3.forEachChild(node, visit);
4440
+ ts4.forEachChild(node, visit);
4200
4441
  };
4201
4442
  visit(root);
4202
4443
  return result;
@@ -4205,7 +4446,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
4205
4446
  const session = cache?.programSession ?? createIncrementalProgramSession(rootDir);
4206
4447
  if (cache)
4207
4448
  cache.programSession = session;
4208
- const rootNames = ts3.sys.readDirectory(rootDir, [".ts", ".tsx"], ["node_modules", "dist"], include ?? DEFAULT_INCLUDE);
4449
+ const rootNames = ts4.sys.readDirectory(rootDir, [".ts", ".tsx"], ["node_modules", "dist"], include ?? DEFAULT_INCLUDE);
4209
4450
  const update = session.update(rootNames, changedPaths);
4210
4451
  const program = update.program;
4211
4452
  const checker = program.getTypeChecker();
@@ -4229,13 +4470,16 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
4229
4470
  nativeTraitFiles.set(trait.file, kinds);
4230
4471
  }
4231
4472
  for (const sf of sourceFiles) {
4473
+ if (!/\.(?:test|spec)\.[cm]?tsx?$/.test(sf.fileName)) {
4474
+ ctx.diagnostics.push(...scanRuntimeDi(sf, sourcePath(rootDir, sf.fileName)));
4475
+ }
4232
4476
  indexFile(sf, ctx);
4233
4477
  }
4234
4478
  const candidates = [];
4235
4479
  for (const sf of sourceFiles) {
4236
4480
  const traits = nativeTraitFiles.get(sf.fileName);
4237
4481
  if (!cache || traits?.has("module")) {
4238
- for (const cls of sf.statements.filter(ts3.isClassDeclaration)) {
4482
+ for (const cls of sf.statements.filter(ts4.isClassDeclaration)) {
4239
4483
  const moduleDec = findDecorator(cls, "Module");
4240
4484
  if (!moduleDec)
4241
4485
  continue;
@@ -4252,14 +4496,14 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
4252
4496
  }
4253
4497
  }
4254
4498
  if (!cache || traits?.has("defineModule") || traits?.has("defineFeatureSlice")) {
4255
- for (const call of descendantsOfKind(sf, ts3.isCallExpression)) {
4499
+ for (const call of descendantsOfKind(sf, ts4.isCallExpression)) {
4256
4500
  if (!["defineModule", "defineFeatureSlice"].includes(nodeText(call.expression)))
4257
4501
  continue;
4258
4502
  const parent = call.parent;
4259
- if (!parent || !ts3.isVariableDeclaration(parent))
4503
+ if (!parent || !ts4.isVariableDeclaration(parent))
4260
4504
  continue;
4261
4505
  const arg = call.arguments[0];
4262
- if (!arg || !ts3.isObjectLiteralExpression(arg))
4506
+ if (!arg || !ts4.isObjectLiteralExpression(arg))
4263
4507
  continue;
4264
4508
  candidates.push({
4265
4509
  node: parent,
@@ -4403,7 +4647,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
4403
4647
  const controllerDec = findDecorator(classInfo.decl, "Controller");
4404
4648
  if (controllerDec) {
4405
4649
  const arg = decoratorArguments(controllerDec)[0];
4406
- const isStandalone = arg && ts3.isObjectLiteralExpression(arg) && booleanProp(arg, "standalone");
4650
+ const isStandalone = arg && ts4.isObjectLiteralExpression(arg) && booleanProp(arg, "standalone");
4407
4651
  if (isStandalone) {
4408
4652
  const ctrl = parseController(classInfo.decl, ctx);
4409
4653
  if (ctrl)
@@ -4528,16 +4772,16 @@ function collectModuleSourceClosure(module, ctx) {
4528
4772
  ownedFiles.add(relativeFile);
4529
4773
  for (const statement of sourceFile.statements) {
4530
4774
  let moduleName;
4531
- if (ts3.isImportDeclaration(statement) && ts3.isStringLiteral(statement.moduleSpecifier)) {
4775
+ if (ts4.isImportDeclaration(statement) && ts4.isStringLiteral(statement.moduleSpecifier)) {
4532
4776
  moduleName = statement.moduleSpecifier.text;
4533
- } else if (ts3.isExportDeclaration(statement) && statement.moduleSpecifier && ts3.isStringLiteral(statement.moduleSpecifier)) {
4777
+ } else if (ts4.isExportDeclaration(statement) && statement.moduleSpecifier && ts4.isStringLiteral(statement.moduleSpecifier)) {
4534
4778
  moduleName = statement.moduleSpecifier.text;
4535
- } else if (ts3.isImportEqualsDeclaration(statement) && ts3.isExternalModuleReference(statement.moduleReference) && ts3.isStringLiteral(statement.moduleReference.expression)) {
4779
+ } else if (ts4.isImportEqualsDeclaration(statement) && ts4.isExternalModuleReference(statement.moduleReference) && ts4.isStringLiteral(statement.moduleReference.expression)) {
4536
4780
  moduleName = statement.moduleReference.expression.text;
4537
4781
  }
4538
4782
  if (!moduleName || moduleName.startsWith("node:"))
4539
4783
  continue;
4540
- const resolved = ts3.resolveModuleName(moduleName, sourceFile.fileName, ctx.program.getCompilerOptions(), ts3.sys).resolvedModule?.resolvedFileName;
4784
+ const resolved = ts4.resolveModuleName(moduleName, sourceFile.fileName, ctx.program.getCompilerOptions(), ts4.sys).resolvedModule?.resolvedFileName;
4541
4785
  if (resolved && isProjectSourcePath(resolved, ctx.rootDir) && !enqueued.has(resolved)) {
4542
4786
  enqueued.add(resolved);
4543
4787
  queue.push(resolved);
@@ -4559,15 +4803,15 @@ function isProjectSourceFile(sourceFile, rootDir) {
4559
4803
  return isProjectSourcePath(sourceFile.fileName, rootDir) && /\.(tsx?|mts|cts)$/.test(sourceFile.fileName);
4560
4804
  }
4561
4805
  function indexFile(sf, ctx) {
4562
- for (const cls of sf.statements.filter(ts3.isClassDeclaration)) {
4806
+ for (const cls of sf.statements.filter(ts4.isClassDeclaration)) {
4563
4807
  const name = cls.name?.text;
4564
4808
  if (name && !ctx.classesByName.has(name)) {
4565
4809
  ctx.classesByName.set(name, { name, decl: cls, file: sf.fileName });
4566
4810
  }
4567
4811
  }
4568
- for (const statement of sf.statements.filter(ts3.isVariableStatement)) {
4812
+ for (const statement of sf.statements.filter(ts4.isVariableStatement)) {
4569
4813
  for (const decl of statement.declarationList.declarations) {
4570
- if (ts3.isIdentifier(decl.name) && !ctx.variablesByName.has(decl.name.text)) {
4814
+ if (ts4.isIdentifier(decl.name) && !ctx.variablesByName.has(decl.name.text)) {
4571
4815
  ctx.variablesByName.set(decl.name.text, decl);
4572
4816
  }
4573
4817
  const info = parseTokenVariable(decl, sf.fileName);
@@ -4579,16 +4823,16 @@ function indexFile(sf, ctx) {
4579
4823
  }
4580
4824
  function parseTokenVariable(decl, file) {
4581
4825
  const init = decl.initializer;
4582
- if (!init || !ts3.isNewExpression(init))
4826
+ if (!init || !ts4.isNewExpression(init))
4583
4827
  return;
4584
4828
  if (nodeText(init.expression) !== "InjectionToken")
4585
4829
  return;
4586
4830
  const [nameArg, optionsArg] = init.arguments ?? [];
4587
4831
  const info = { name: variableName(decl), file, line: lineOf(decl) };
4588
- if (nameArg && ts3.isStringLiteral(nameArg)) {
4832
+ if (nameArg && ts4.isStringLiteral(nameArg)) {
4589
4833
  info.stringName = nameArg.text;
4590
4834
  }
4591
- if (optionsArg && ts3.isObjectLiteralExpression(optionsArg)) {
4835
+ if (optionsArg && ts4.isObjectLiteralExpression(optionsArg)) {
4592
4836
  const scope = stringLiteralProp(optionsArg, "scope");
4593
4837
  if (scope && isScope(scope)) {
4594
4838
  info.scope = scope;
@@ -4608,22 +4852,22 @@ function parseModule(candidate, nameByNode, ctx) {
4608
4852
  const { options, className, file, line } = candidate;
4609
4853
  const name = nameByNode.get(candidate.node) ?? className;
4610
4854
  const featureSpec = parseFeatureSpec(getProp(options, "spec"), ctx);
4611
- const tags = arrayProp(options, "tags").map((el) => ts3.isStringLiteral(el) ? el.text : nodeText(el).replace(/['"]/g, "")).filter(Boolean);
4855
+ const tags = arrayProp(options, "tags").map((el) => ts4.isStringLiteral(el) ? el.text : nodeText(el).replace(/['"]/g, "")).filter(Boolean);
4612
4856
  const aspects = parseAspectRefs(getProp(options, "aspects"), ctx, `module ${name}`);
4613
4857
  const imports = arrayProp(options, "imports").map((el) => {
4614
4858
  const unwrapped = unwrapForwardRef(el);
4615
- const decl = ts3.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
4859
+ const decl = ts4.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
4616
4860
  if (decl) {
4617
4861
  const known = nameByNode.get(decl);
4618
4862
  if (known)
4619
4863
  return known;
4620
- if (ts3.isClassDeclaration(decl)) {
4864
+ if (ts4.isClassDeclaration(decl)) {
4621
4865
  const dec = findDecorator(decl, "Module");
4622
4866
  const decOptions = dec && decoratorObjectArg(dec);
4623
4867
  const decName = decOptions && stringLiteralProp(decOptions, "name");
4624
4868
  return decName ?? decl.name?.text ?? nodeText(el);
4625
4869
  }
4626
- if (ts3.isVariableDeclaration(decl))
4870
+ if (ts4.isVariableDeclaration(decl))
4627
4871
  return variableName(decl);
4628
4872
  }
4629
4873
  return nodeText(el);
@@ -4637,7 +4881,7 @@ function parseModule(candidate, nameByNode, ctx) {
4637
4881
  providers.push(...parsedProviders);
4638
4882
  continue;
4639
4883
  }
4640
- if (ts3.isCallExpression(el)) {
4884
+ if (ts4.isCallExpression(el)) {
4641
4885
  const helper = nodeText(el.expression).split(".").pop() ?? nodeText(el.expression);
4642
4886
  warn(ctx, "unsupported-provider-helper", `无法静态展开 provider helper '${helper}';请改用显式 Provider 或实现编译器支持的 helper`, sourcePath(ctx.rootDir, el.getSourceFile().fileName), lineOf(el));
4643
4887
  continue;
@@ -4647,10 +4891,10 @@ function parseModule(candidate, nameByNode, ctx) {
4647
4891
  providers.push(provider);
4648
4892
  }
4649
4893
  for (const el of arrayProp(options, "jobs")) {
4650
- if (!ts3.isIdentifier(el))
4894
+ if (!ts4.isIdentifier(el))
4651
4895
  continue;
4652
4896
  const decl = resolveDeclaration(el, ctx)[0];
4653
- if (!decl || !ts3.isClassDeclaration(decl))
4897
+ if (!decl || !ts4.isClassDeclaration(decl))
4654
4898
  continue;
4655
4899
  const className = decl.name?.text ?? el.text;
4656
4900
  const registeredProvider = providers.find((provider) => provider.token === className || provider.useClass === className);
@@ -4687,18 +4931,18 @@ function parseModule(candidate, nameByNode, ctx) {
4687
4931
  const handlerClasses = [];
4688
4932
  const seenHandlers = new Set;
4689
4933
  const collectHandler = (expr) => {
4690
- if (!ts3.isIdentifier(expr))
4934
+ if (!ts4.isIdentifier(expr))
4691
4935
  return;
4692
4936
  const decl = resolveDeclaration(expr, ctx)[0];
4693
- if (decl && ts3.isClassDeclaration(decl) && !seenHandlers.has(decl.name?.text ?? "")) {
4937
+ if (decl && ts4.isClassDeclaration(decl) && !seenHandlers.has(decl.name?.text ?? "")) {
4694
4938
  seenHandlers.add(decl.name?.text ?? "");
4695
4939
  handlerClasses.push(decl);
4696
4940
  }
4697
4941
  };
4698
4942
  for (const el of arrayProp(options, "providers")) {
4699
- if (ts3.isIdentifier(el))
4943
+ if (ts4.isIdentifier(el))
4700
4944
  collectHandler(el);
4701
- if (ts3.isObjectLiteralExpression(el)) {
4945
+ if (ts4.isObjectLiteralExpression(el)) {
4702
4946
  const useClass = getProp(el, "useClass");
4703
4947
  if (useClass)
4704
4948
  collectHandler(useClass);
@@ -4798,17 +5042,17 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
4798
5042
  if (seen.has(input))
4799
5043
  return;
4800
5044
  seen.add(input);
4801
- if (ts3.isIdentifier(input)) {
4802
- const local = input.getSourceFile().statements.flatMap((statement) => ts3.isVariableStatement(statement) ? [...statement.declarationList.declarations] : []);
5045
+ if (ts4.isIdentifier(input)) {
5046
+ const local = input.getSourceFile().statements.flatMap((statement) => ts4.isVariableStatement(statement) ? [...statement.declarationList.declarations] : []);
4803
5047
  const resolved = resolveDeclaration(input, ctx)[0];
4804
- const decl = (resolved && ts3.isVariableDeclaration(resolved) ? resolved : undefined) ?? ctx.variablesByName.get(input.text) ?? local.find((candidate) => ts3.isIdentifier(candidate.name) && candidate.name.text === input.text) ?? descendantsOfKind(input.getSourceFile(), ts3.isVariableDeclaration).find((candidate) => ts3.isIdentifier(candidate.name) && candidate.name.text === input.text);
4805
- if (decl && ts3.isVariableDeclaration(decl))
5048
+ const decl = (resolved && ts4.isVariableDeclaration(resolved) ? resolved : undefined) ?? ctx.variablesByName.get(input.text) ?? local.find((candidate) => ts4.isIdentifier(candidate.name) && candidate.name.text === input.text) ?? descendantsOfKind(input.getSourceFile(), ts4.isVariableDeclaration).find((candidate) => ts4.isIdentifier(candidate.name) && candidate.name.text === input.text);
5049
+ if (decl && ts4.isVariableDeclaration(decl))
4806
5050
  return parseFeatureSpec(decl.initializer, ctx, seen);
4807
5051
  }
4808
- if (ts3.isCallExpression(input) && nodeText(input.expression) === "defineFeatureSpec") {
5052
+ if (ts4.isCallExpression(input) && nodeText(input.expression) === "defineFeatureSpec") {
4809
5053
  return parseFeatureSpec(input.arguments[0], ctx, seen);
4810
5054
  }
4811
- if (ts3.isAsExpression(input) || ts3.isSatisfiesExpression(input) || ts3.isParenthesizedExpression(input)) {
5055
+ if (ts4.isAsExpression(input) || ts4.isSatisfiesExpression(input) || ts4.isParenthesizedExpression(input)) {
4812
5056
  return parseFeatureSpec(input.expression, ctx, seen);
4813
5057
  }
4814
5058
  const invalid = () => {
@@ -4821,28 +5065,28 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
4821
5065
  });
4822
5066
  return;
4823
5067
  };
4824
- if (!ts3.isObjectLiteralExpression(input))
5068
+ if (!ts4.isObjectLiteralExpression(input))
4825
5069
  return invalid();
4826
5070
  const name = stringLiteralProp(input, "name");
4827
5071
  const statesExpr = getProp(input, "states");
4828
5072
  const transitionObject = getProp(input, "transitions");
4829
- if (!name || !statesExpr || !ts3.isArrayLiteralExpression(statesExpr) || statesExpr.elements.some((state) => !ts3.isStringLiteral(state)) || !transitionObject || !ts3.isObjectLiteralExpression(transitionObject) || input.properties.some((property) => !ts3.isPropertyAssignment(property))) {
5073
+ if (!name || !statesExpr || !ts4.isArrayLiteralExpression(statesExpr) || statesExpr.elements.some((state) => !ts4.isStringLiteral(state)) || !transitionObject || !ts4.isObjectLiteralExpression(transitionObject) || input.properties.some((property) => !ts4.isPropertyAssignment(property))) {
4830
5074
  return invalid();
4831
5075
  }
4832
5076
  const states = [];
4833
5077
  for (const state of statesExpr.elements) {
4834
- if (!ts3.isStringLiteral(state))
5078
+ if (!ts4.isStringLiteral(state))
4835
5079
  return invalid();
4836
5080
  states.push(state.text);
4837
5081
  }
4838
5082
  const transitions = [];
4839
5083
  for (const property of transitionObject.properties) {
4840
- if (!ts3.isPropertyAssignment(property) || ts3.isComputedPropertyName(property.name) || !ts3.isObjectLiteralExpression(property.initializer))
5084
+ if (!ts4.isPropertyAssignment(property) || ts4.isComputedPropertyName(property.name) || !ts4.isObjectLiteralExpression(property.initializer))
4841
5085
  return invalid();
4842
5086
  const options = property.initializer;
4843
5087
  const from = stringLiteralProp(options, "from");
4844
5088
  const to = stringLiteralProp(options, "to");
4845
- if (!from || !to || options.properties.some((prop) => !ts3.isPropertyAssignment(prop)) || ["permission", "command", "route", "audit"].some((key) => getProp(options, key) && !stringLiteralProp(options, key)) || ["transaction", "idempotency"].some((key) => getProp(options, key) && !commandModeProp(options, key))) {
5089
+ if (!from || !to || options.properties.some((prop) => !ts4.isPropertyAssignment(prop)) || ["permission", "command", "route", "audit"].some((key) => getProp(options, key) && !stringLiteralProp(options, key)) || ["transaction", "idempotency"].some((key) => getProp(options, key) && !commandModeProp(options, key))) {
4846
5090
  return invalid();
4847
5091
  }
4848
5092
  const permission = stringLiteralProp(options, "permission");
@@ -4869,21 +5113,21 @@ function resolveStaticObjectLiteral(input, ctx, seen = new Set) {
4869
5113
  if (!input || seen.has(input))
4870
5114
  return;
4871
5115
  seen.add(input);
4872
- if (ts3.isAsExpression(input) || ts3.isSatisfiesExpression(input) || ts3.isParenthesizedExpression(input)) {
5116
+ if (ts4.isAsExpression(input) || ts4.isSatisfiesExpression(input) || ts4.isParenthesizedExpression(input)) {
4873
5117
  return resolveStaticObjectLiteral(input.expression, ctx, seen);
4874
5118
  }
4875
- if (ts3.isIdentifier(input)) {
4876
- const declaration = resolveDeclaration(input, ctx).find(ts3.isVariableDeclaration);
5119
+ if (ts4.isIdentifier(input)) {
5120
+ const declaration = resolveDeclaration(input, ctx).find(ts4.isVariableDeclaration);
4877
5121
  return declaration?.initializer ? resolveStaticObjectLiteral(declaration.initializer, ctx, seen) : undefined;
4878
5122
  }
4879
- if (ts3.isCallExpression(input)) {
5123
+ if (ts4.isCallExpression(input)) {
4880
5124
  const expressionName = nodeText(input.expression);
4881
5125
  if (expressionName === "defineRouteContract" || expressionName.endsWith(".defineRouteContract")) {
4882
5126
  return resolveStaticObjectLiteral(input.arguments[0], ctx, seen);
4883
5127
  }
4884
5128
  return;
4885
5129
  }
4886
- return ts3.isObjectLiteralExpression(input) ? input : undefined;
5130
+ return ts4.isObjectLiteralExpression(input) ? input : undefined;
4887
5131
  }
4888
5132
  function commandModeProp(object, name) {
4889
5133
  const value = stringLiteralProp(object, name);
@@ -4918,9 +5162,9 @@ function parseProvider(el, exportsSet, ctx) {
4918
5162
  const file = sourcePath(ctx.rootDir, el.getSourceFile().fileName);
4919
5163
  const line = lineOf(el);
4920
5164
  const unwrappedEl = unwrapForwardRef(el);
4921
- if (ts3.isIdentifier(unwrappedEl)) {
5165
+ if (ts4.isIdentifier(unwrappedEl)) {
4922
5166
  const decl = resolveDeclaration(unwrappedEl, ctx)[0];
4923
- const cls = decl && ts3.isClassDeclaration(decl) ? decl : undefined;
5167
+ const cls = decl && ts4.isClassDeclaration(decl) ? decl : undefined;
4924
5168
  const className = cls?.name?.text ?? unwrappedEl.text;
4925
5169
  const { deps, optionalDeps, selfDeps, skipSelfDeps, hostDeps, functionalInjects, missing } = cls ? classDeps(cls, ctx) : { deps: [], optionalDeps: [], selfDeps: [], skipSelfDeps: [], hostDeps: [], functionalInjects: [], missing: false };
4926
5170
  const injectable = cls ? parseInjectableOptions(cls, ctx) : undefined;
@@ -4947,7 +5191,7 @@ function parseProvider(el, exportsSet, ctx) {
4947
5191
  ...cls ? { importPath: modulePath(ctx.rootDir, cls.getSourceFile().fileName) } : {}
4948
5192
  };
4949
5193
  }
4950
- if (!ts3.isObjectLiteralExpression(el))
5194
+ if (!ts4.isObjectLiteralExpression(el))
4951
5195
  return;
4952
5196
  const provideExpr = getProp(el, "provide");
4953
5197
  if (!provideExpr)
@@ -4962,8 +5206,8 @@ function parseProvider(el, exportsSet, ctx) {
4962
5206
  const useExistingExpr = getProp(el, "useExisting");
4963
5207
  if (useClassExpr) {
4964
5208
  const unwrappedClass = unwrapForwardRef(useClassExpr);
4965
- const decl = ts3.isIdentifier(unwrappedClass) ? resolveDeclaration(unwrappedClass, ctx)[0] : undefined;
4966
- const cls = decl && ts3.isClassDeclaration(decl) ? decl : undefined;
5209
+ const decl = ts4.isIdentifier(unwrappedClass) ? resolveDeclaration(unwrappedClass, ctx)[0] : undefined;
5210
+ const cls = decl && ts4.isClassDeclaration(decl) ? decl : undefined;
4967
5211
  const useClass = cls?.name?.text ?? nodeText(unwrappedClass);
4968
5212
  let deps = explicitDeps;
4969
5213
  let optionalDeps = [];
@@ -5019,7 +5263,7 @@ function parseProvider(el, exportsSet, ctx) {
5019
5263
  }
5020
5264
  if (useValueExpr) {
5021
5265
  validateProviderCompatibility(provideExpr, useValueExpr, "value", token, ctx, file, line);
5022
- const importPath = ts3.isIdentifier(useValueExpr) ? importPathOf(useValueExpr, ctx) : undefined;
5266
+ const importPath = ts4.isIdentifier(useValueExpr) ? importPathOf(useValueExpr, ctx) : undefined;
5023
5267
  return {
5024
5268
  token,
5025
5269
  tokenKind,
@@ -5035,12 +5279,12 @@ function parseProvider(el, exportsSet, ctx) {
5035
5279
  };
5036
5280
  }
5037
5281
  if (useFactoryExpr) {
5038
- const factoryName = ts3.isIdentifier(useFactoryExpr) ? (() => {
5282
+ const factoryName = ts4.isIdentifier(useFactoryExpr) ? (() => {
5039
5283
  const decl = resolveDeclaration(useFactoryExpr, ctx)[0];
5040
- return decl && (ts3.isFunctionDeclaration(decl) || ts3.isVariableDeclaration(decl)) ? (ts3.isFunctionDeclaration(decl) ? decl.name?.text : variableName(decl)) ?? useFactoryExpr.text : useFactoryExpr.text;
5284
+ return decl && (ts4.isFunctionDeclaration(decl) || ts4.isVariableDeclaration(decl)) ? (ts4.isFunctionDeclaration(decl) ? decl.name?.text : variableName(decl)) ?? useFactoryExpr.text : useFactoryExpr.text;
5041
5285
  })() : nodeText(useFactoryExpr);
5042
5286
  validateProviderCompatibility(provideExpr, useFactoryExpr, "factory", token, ctx, file, line);
5043
- const importPath = ts3.isIdentifier(useFactoryExpr) ? importPathOf(useFactoryExpr, ctx) : undefined;
5287
+ const importPath = ts4.isIdentifier(useFactoryExpr) ? importPathOf(useFactoryExpr, ctx) : undefined;
5044
5288
  return {
5045
5289
  token,
5046
5290
  tokenKind,
@@ -5076,20 +5320,20 @@ function parseProvider(el, exportsSet, ctx) {
5076
5320
  function expandProviderExpressions(expressions, ctx, seen = new Set) {
5077
5321
  const result = [];
5078
5322
  for (const expression of expressions) {
5079
- if (ts3.isSpreadElement(expression)) {
5323
+ if (ts4.isSpreadElement(expression)) {
5080
5324
  result.push(...expandProviderExpressions([expression.expression], ctx, seen));
5081
5325
  continue;
5082
5326
  }
5083
- if (ts3.isIdentifier(expression)) {
5327
+ if (ts4.isIdentifier(expression)) {
5084
5328
  const declaration = resolveDeclaration(expression, ctx)[0];
5085
- if (declaration && ts3.isVariableDeclaration(declaration) && declaration.initializer) {
5329
+ if (declaration && ts4.isVariableDeclaration(declaration) && declaration.initializer) {
5086
5330
  const key = `${declaration.getSourceFile().fileName}:${declaration.pos}`;
5087
5331
  if (seen.has(key))
5088
5332
  continue;
5089
5333
  const initializer = declaration.initializer;
5090
- if (ts3.isCallExpression(initializer) && isProviderHelper(initializer, "makeEnvironmentProviders")) {
5334
+ if (ts4.isCallExpression(initializer) && isProviderHelper(initializer, "makeEnvironmentProviders")) {
5091
5335
  const nested = initializer.arguments[0];
5092
- if (nested && ts3.isArrayLiteralExpression(nested)) {
5336
+ if (nested && ts4.isArrayLiteralExpression(nested)) {
5093
5337
  seen.add(key);
5094
5338
  result.push(...expandProviderExpressions([...nested.elements], ctx, seen));
5095
5339
  seen.delete(key);
@@ -5098,9 +5342,9 @@ function expandProviderExpressions(expressions, ctx, seen = new Set) {
5098
5342
  }
5099
5343
  }
5100
5344
  }
5101
- if (ts3.isCallExpression(expression) && isProviderHelper(expression, "makeEnvironmentProviders")) {
5345
+ if (ts4.isCallExpression(expression) && isProviderHelper(expression, "makeEnvironmentProviders")) {
5102
5346
  const nested = expression.arguments[0];
5103
- if (nested && ts3.isArrayLiteralExpression(nested)) {
5347
+ if (nested && ts4.isArrayLiteralExpression(nested)) {
5104
5348
  result.push(...expandProviderExpressions([...nested.elements], ctx, seen));
5105
5349
  continue;
5106
5350
  }
@@ -5113,7 +5357,7 @@ function isProviderHelper(expression, name) {
5113
5357
  return nodeText(expression.expression).split(".").pop() === name;
5114
5358
  }
5115
5359
  function parseFunctionalProvider(expression, exportsSet, ctx) {
5116
- if (!ts3.isCallExpression(expression))
5360
+ if (!ts4.isCallExpression(expression))
5117
5361
  return;
5118
5362
  const helper = nodeText(expression.expression).split(".").pop();
5119
5363
  const args = expression.arguments;
@@ -5126,7 +5370,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
5126
5370
  return [];
5127
5371
  const { name: token, kind: tokenKind } = tokenNameOf(tokenExpr, ctx);
5128
5372
  validateProviderCompatibility(tokenExpr, valueExpr, "value", token, ctx, file, line);
5129
- const importPath = ts3.isIdentifier(valueExpr) ? importPathOf(valueExpr, ctx) : undefined;
5373
+ const importPath = ts4.isIdentifier(valueExpr) ? importPathOf(valueExpr, ctx) : undefined;
5130
5374
  return [{
5131
5375
  token,
5132
5376
  tokenKind,
@@ -5145,7 +5389,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
5145
5389
  if (!initializer)
5146
5390
  return [];
5147
5391
  const token = helper === "provideAppInitializer" ? "APP_INITIALIZER" : "ENVIRONMENT_INITIALIZER";
5148
- const importPath = ts3.isIdentifier(initializer) ? importPathOf(initializer, ctx) : undefined;
5392
+ const importPath = ts4.isIdentifier(initializer) ? importPathOf(initializer, ctx) : undefined;
5149
5393
  return [{
5150
5394
  token,
5151
5395
  tokenKind: "injection-token",
@@ -5164,7 +5408,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
5164
5408
  const providers = [];
5165
5409
  const routes = args[0];
5166
5410
  if (routes) {
5167
- const importPath = ts3.isIdentifier(routes) ? importPathOf(routes, ctx) : undefined;
5411
+ const importPath = ts4.isIdentifier(routes) ? importPathOf(routes, ctx) : undefined;
5168
5412
  providers.push({
5169
5413
  token: "ROUTE_CONFIG",
5170
5414
  tokenKind: "injection-token",
@@ -5179,7 +5423,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
5179
5423
  });
5180
5424
  }
5181
5425
  for (const feature of args.slice(1)) {
5182
- if (!ts3.isCallExpression(feature))
5426
+ if (!ts4.isCallExpression(feature))
5183
5427
  continue;
5184
5428
  const featureName = nodeText(feature.expression).split(".").pop();
5185
5429
  if (featureName === "withRouterConfig" && feature.arguments[0]) {
@@ -5196,8 +5440,8 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
5196
5440
  });
5197
5441
  } else if (featureName === "withTitleStrategy" && feature.arguments[0]) {
5198
5442
  const strategy = feature.arguments[0];
5199
- const isClass = ts3.isIdentifier(strategy) && Boolean(resolveDeclaration(strategy, ctx).find((declaration) => ts3.isClassDeclaration(declaration)));
5200
- const importPath = ts3.isIdentifier(strategy) ? importPathOf(strategy, ctx) : undefined;
5443
+ const isClass = ts4.isIdentifier(strategy) && Boolean(resolveDeclaration(strategy, ctx).find((declaration) => ts4.isClassDeclaration(declaration)));
5444
+ const importPath = ts4.isIdentifier(strategy) ? importPathOf(strategy, ctx) : undefined;
5201
5445
  providers.push({
5202
5446
  token: "TITLE_STRATEGY",
5203
5447
  tokenKind: "injection-token",
@@ -5229,14 +5473,14 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
5229
5473
  importModule: "@supacloud/app"
5230
5474
  }];
5231
5475
  for (const feature of args) {
5232
- if (!ts3.isCallExpression(feature))
5476
+ if (!ts4.isCallExpression(feature))
5233
5477
  continue;
5234
5478
  const featureName = nodeText(feature.expression).split(".").pop();
5235
5479
  if (featureName === "withInterceptors") {
5236
5480
  for (const interceptorArg of feature.arguments) {
5237
- const values = ts3.isArrayLiteralExpression(interceptorArg) ? [...interceptorArg.elements] : [interceptorArg];
5481
+ const values = ts4.isArrayLiteralExpression(interceptorArg) ? [...interceptorArg.elements] : [interceptorArg];
5238
5482
  for (const value of values) {
5239
- const importPath = ts3.isIdentifier(value) ? importPathOf(value, ctx) : undefined;
5483
+ const importPath = ts4.isIdentifier(value) ? importPathOf(value, ctx) : undefined;
5240
5484
  providers.push({
5241
5485
  token: "HTTP_INTERCEPTORS",
5242
5486
  tokenKind: "injection-token",
@@ -5283,9 +5527,9 @@ function providerTokenValueType(expr, ctx) {
5283
5527
  const typeArguments = typeArgumentsOf(type, ctx);
5284
5528
  if (typeArguments.length > 0)
5285
5529
  return typeArguments[0];
5286
- if (ts3.isIdentifier(expr)) {
5530
+ if (ts4.isIdentifier(expr)) {
5287
5531
  const declaration = resolveDeclaration(expr, ctx)[0];
5288
- if (declaration && ts3.isClassDeclaration(declaration)) {
5532
+ if (declaration && ts4.isClassDeclaration(declaration)) {
5289
5533
  return declaredClassType(declaration, ctx);
5290
5534
  }
5291
5535
  }
@@ -5293,9 +5537,9 @@ function providerTokenValueType(expr, ctx) {
5293
5537
  }
5294
5538
  function providerImplementationType(expr, kind, ctx) {
5295
5539
  if (kind === "class" || kind === "existing") {
5296
- if (ts3.isIdentifier(expr)) {
5540
+ if (ts4.isIdentifier(expr)) {
5297
5541
  const declaration = resolveDeclaration(expr, ctx)[0];
5298
- if (declaration && ts3.isClassDeclaration(declaration)) {
5542
+ if (declaration && ts4.isClassDeclaration(declaration)) {
5299
5543
  return declaredClassType(declaration, ctx);
5300
5544
  }
5301
5545
  }
@@ -5305,7 +5549,7 @@ function providerImplementationType(expr, kind, ctx) {
5305
5549
  }
5306
5550
  if (kind === "factory") {
5307
5551
  const type = ctx.checker.getTypeAtLocation(expr);
5308
- const signature = ctx.checker.getSignaturesOfType(type, ts3.SignatureKind.Call)[0];
5552
+ const signature = ctx.checker.getSignaturesOfType(type, ts4.SignatureKind.Call)[0];
5309
5553
  return signature?.getReturnType();
5310
5554
  }
5311
5555
  return ctx.checker.getTypeAtLocation(expr);
@@ -5324,16 +5568,16 @@ function isTypeReference(type) {
5324
5568
  return "target" in type;
5325
5569
  }
5326
5570
  function isUnknownOrAny(type) {
5327
- return (type.flags & (ts3.TypeFlags.Any | ts3.TypeFlags.Unknown)) !== 0;
5571
+ return (type.flags & (ts4.TypeFlags.Any | ts4.TypeFlags.Unknown)) !== 0;
5328
5572
  }
5329
5573
  function parseController(input, ctx) {
5330
5574
  let decl;
5331
- if (ts3.isClassDeclaration(input)) {
5575
+ if (ts4.isClassDeclaration(input)) {
5332
5576
  decl = input;
5333
5577
  } else {
5334
5578
  const unwrapped = unwrapForwardRef(input);
5335
- const resolved = ts3.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
5336
- if (resolved && ts3.isClassDeclaration(resolved)) {
5579
+ const resolved = ts4.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
5580
+ if (resolved && ts4.isClassDeclaration(resolved)) {
5337
5581
  decl = resolved;
5338
5582
  }
5339
5583
  }
@@ -5346,9 +5590,9 @@ function parseController(input, ctx) {
5346
5590
  let standalone;
5347
5591
  const pathArg = decoratorArguments(controllerDec)[0];
5348
5592
  if (pathArg) {
5349
- if (ts3.isStringLiteral(pathArg)) {
5593
+ if (ts4.isStringLiteral(pathArg)) {
5350
5594
  path = pathArg.text;
5351
- } else if (ts3.isObjectLiteralExpression(pathArg)) {
5595
+ } else if (ts4.isObjectLiteralExpression(pathArg)) {
5352
5596
  const p = stringLiteralProp(pathArg, "path");
5353
5597
  if (p)
5354
5598
  path = p;
@@ -5371,7 +5615,7 @@ function parseController(input, ctx) {
5371
5615
  }
5372
5616
  }
5373
5617
  }
5374
- for (const method of decl.members.filter(ts3.isMethodDeclaration)) {
5618
+ for (const method of decl.members.filter(ts4.isMethodDeclaration)) {
5375
5619
  for (const dec of decoratorsOf(method)) {
5376
5620
  const name = decoratorName2(dec);
5377
5621
  const httpMethod = name ? ROUTE_DECORATORS[name] : undefined;
@@ -5379,7 +5623,7 @@ function parseController(input, ctx) {
5379
5623
  continue;
5380
5624
  const args = decoratorArguments(dec);
5381
5625
  const pathArg = args[0];
5382
- const routePath = pathArg && ts3.isStringLiteral(pathArg) ? pathArg.text : "/";
5626
+ const routePath = pathArg && ts4.isStringLiteral(pathArg) ? pathArg.text : "/";
5383
5627
  const route = {
5384
5628
  method: httpMethod,
5385
5629
  path: routePath,
@@ -5450,12 +5694,12 @@ function parseController(input, ctx) {
5450
5694
  } else if (dName === "Headers") {
5451
5695
  hasBindingDecorator = true;
5452
5696
  const argument = dArgs[0];
5453
- const bindingName = argument !== undefined && ts3.isStringLiteral(argument) ? argument.text : undefined;
5697
+ const bindingName = argument !== undefined && ts4.isStringLiteral(argument) ? argument.text : undefined;
5454
5698
  paramNode = { name: pName, kind: "headers", ...bindingName === undefined ? {} : { bindingName } };
5455
5699
  } else if (dName === "Cookie") {
5456
5700
  hasBindingDecorator = true;
5457
5701
  const argument = dArgs[0];
5458
- const bindingName = argument !== undefined && ts3.isStringLiteral(argument) ? argument.text : undefined;
5702
+ const bindingName = argument !== undefined && ts4.isStringLiteral(argument) ? argument.text : undefined;
5459
5703
  paramNode = { name: pName, kind: "cookie", ...bindingName === undefined ? {} : { bindingName } };
5460
5704
  }
5461
5705
  }
@@ -5517,20 +5761,20 @@ function parseController(input, ctx) {
5517
5761
  }
5518
5762
  } else if (dName === "Title") {
5519
5763
  const tArg = mArgs[0];
5520
- if (tArg && ts3.isStringLiteral(tArg)) {
5764
+ if (tArg && ts4.isStringLiteral(tArg)) {
5521
5765
  route.title = tArg.text;
5522
5766
  }
5523
5767
  } else if (dName === "Data") {
5524
5768
  const dArg = mArgs[0];
5525
- if (dArg && ts3.isObjectLiteralExpression(dArg)) {
5769
+ if (dArg && ts4.isObjectLiteralExpression(dArg)) {
5526
5770
  route.data = { ...route.data, ...parseObjectLiteralValues(dArg) };
5527
5771
  }
5528
5772
  } else if (dName === "Resolve") {
5529
5773
  const rArg = mArgs[0];
5530
- if (rArg && ts3.isObjectLiteralExpression(rArg)) {
5774
+ if (rArg && ts4.isObjectLiteralExpression(rArg)) {
5531
5775
  const resolvers = route.resolvers ?? {};
5532
5776
  for (const prop of rArg.properties) {
5533
- if (ts3.isPropertyAssignment(prop)) {
5777
+ if (ts4.isPropertyAssignment(prop)) {
5534
5778
  const rName = propertyName(prop.name);
5535
5779
  const init = prop.initializer;
5536
5780
  if (init)
@@ -5561,7 +5805,7 @@ function parseController(input, ctx) {
5561
5805
  });
5562
5806
  }
5563
5807
  const contract = getProp(optionsObject, "contract");
5564
- if (contract && ts3.isObjectLiteralExpression(contract)) {
5808
+ if (contract && ts4.isObjectLiteralExpression(contract)) {
5565
5809
  route.contract = {};
5566
5810
  for (const field of ["body", "response", "evidence"]) {
5567
5811
  const value = stringLiteralProp(contract, field);
@@ -5579,15 +5823,15 @@ function parseController(input, ctx) {
5579
5823
  }
5580
5824
  for (const field of ["body", "params", "query", "headers", "cookie", "response"]) {
5581
5825
  const schemaExpr = getProp(optionsObject, field);
5582
- if (schemaExpr && ts3.isIdentifier(schemaExpr)) {
5826
+ if (schemaExpr && ts4.isIdentifier(schemaExpr)) {
5583
5827
  route[field] = nodeText(schemaExpr);
5584
5828
  const importPath = importPathOf(schemaExpr, ctx);
5585
5829
  if (importPath)
5586
5830
  schemaImports[schemaExpr.text] = importPath;
5587
5831
  const declaration = resolveDeclaration(schemaExpr, ctx)[0];
5588
5832
  const typeName = ctx.checker.typeToString(ctx.checker.getTypeAtLocation(schemaExpr));
5589
- const initializer = declaration && ts3.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
5590
- const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts3.isCallExpression(initializer) && ts3.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
5833
+ const initializer = declaration && ts4.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
5834
+ const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts4.isCallExpression(initializer) && ts4.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
5591
5835
  (route.schemaKinds ??= {})[field] = opaque ? "opaque" : "declared";
5592
5836
  }
5593
5837
  }
@@ -5596,7 +5840,7 @@ function parseController(input, ctx) {
5596
5840
  const responses = {};
5597
5841
  const selectors = new Map;
5598
5842
  for (const property of responsesObject.properties) {
5599
- if (!ts3.isPropertyAssignment(property) || ts3.isComputedPropertyName(property.name))
5843
+ if (!ts4.isPropertyAssignment(property) || ts4.isComputedPropertyName(property.name))
5600
5844
  continue;
5601
5845
  const status = propertyName(property.name);
5602
5846
  if (!isRouteResponseSelector(status)) {
@@ -5628,7 +5872,7 @@ function parseController(input, ctx) {
5628
5872
  }
5629
5873
  selectors.set(canonical, status);
5630
5874
  const schemaExpr = property.initializer;
5631
- if (!ts3.isIdentifier(schemaExpr)) {
5875
+ if (!ts4.isIdentifier(schemaExpr)) {
5632
5876
  ctx.diagnostics.push({
5633
5877
  severity: "error",
5634
5878
  code: "invalid-route-response-map",
@@ -5643,8 +5887,8 @@ function parseController(input, ctx) {
5643
5887
  schemaImports[schemaExpr.text] = importPath;
5644
5888
  const declaration = resolveDeclaration(schemaExpr, ctx)[0];
5645
5889
  const typeName = ctx.checker.typeToString(ctx.checker.getTypeAtLocation(schemaExpr));
5646
- const initializer = declaration && ts3.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
5647
- const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts3.isCallExpression(initializer) && ts3.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
5890
+ const initializer = declaration && ts4.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
5891
+ const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts4.isCallExpression(initializer) && ts4.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
5648
5892
  const previousKind = route.schemaKinds?.response;
5649
5893
  (route.schemaKinds ??= {}).response = opaque || previousKind === "opaque" ? "opaque" : "declared";
5650
5894
  }
@@ -5652,18 +5896,18 @@ function parseController(input, ctx) {
5652
5896
  route.responses = responses;
5653
5897
  }
5654
5898
  const commandExpr = getProp(optionsObject, "command");
5655
- if (commandExpr && ts3.isIdentifier(commandExpr)) {
5899
+ if (commandExpr && ts4.isIdentifier(commandExpr)) {
5656
5900
  const commandDecl = resolveDeclaration(commandExpr, ctx)[0];
5657
- route.command = commandDecl && ts3.isClassDeclaration(commandDecl) ? commandDecl.name?.text ?? commandExpr.text : commandExpr.text;
5901
+ route.command = commandDecl && ts4.isClassDeclaration(commandDecl) ? commandDecl.name?.text ?? commandExpr.text : commandExpr.text;
5658
5902
  }
5659
5903
  const guardsExpr = getProp(optionsObject, "guards");
5660
- if (guardsExpr && ts3.isArrayLiteralExpression(guardsExpr)) {
5904
+ if (guardsExpr && ts4.isArrayLiteralExpression(guardsExpr)) {
5661
5905
  for (const el of guardsExpr.elements) {
5662
5906
  routeGuards.push(tokenText(el, ctx));
5663
5907
  }
5664
5908
  }
5665
5909
  const canMatchExpr = getProp(optionsObject, "canMatch");
5666
- if (canMatchExpr && ts3.isArrayLiteralExpression(canMatchExpr)) {
5910
+ if (canMatchExpr && ts4.isArrayLiteralExpression(canMatchExpr)) {
5667
5911
  const canMatchList = [];
5668
5912
  for (const el of canMatchExpr.elements) {
5669
5913
  canMatchList.push(tokenText(el, ctx));
@@ -5673,16 +5917,16 @@ function parseController(input, ctx) {
5673
5917
  }
5674
5918
  }
5675
5919
  const canDeactivateExpr = getProp(optionsObject, "canDeactivate");
5676
- if (canDeactivateExpr && ts3.isArrayLiteralExpression(canDeactivateExpr)) {
5920
+ if (canDeactivateExpr && ts4.isArrayLiteralExpression(canDeactivateExpr)) {
5677
5921
  for (const el of canDeactivateExpr.elements) {
5678
5922
  routeCanDeactivate.push(tokenText(el, ctx));
5679
5923
  }
5680
5924
  }
5681
5925
  const resolversExpr = getProp(optionsObject, "resolvers");
5682
- if (resolversExpr && ts3.isObjectLiteralExpression(resolversExpr)) {
5926
+ if (resolversExpr && ts4.isObjectLiteralExpression(resolversExpr)) {
5683
5927
  const resolvers = {};
5684
5928
  for (const prop of resolversExpr.properties) {
5685
- if (ts3.isPropertyAssignment(prop)) {
5929
+ if (ts4.isPropertyAssignment(prop)) {
5686
5930
  const rName = propertyName(prop.name);
5687
5931
  const init = prop.initializer;
5688
5932
  if (init)
@@ -5694,22 +5938,22 @@ function parseController(input, ctx) {
5694
5938
  }
5695
5939
  }
5696
5940
  const redirectToExpr = getProp(optionsObject, "redirectTo");
5697
- if (redirectToExpr && ts3.isStringLiteral(redirectToExpr)) {
5941
+ if (redirectToExpr && ts4.isStringLiteral(redirectToExpr)) {
5698
5942
  route.redirectTo = redirectToExpr.text;
5699
5943
  }
5700
5944
  const pathMatchExpr = getProp(optionsObject, "pathMatch");
5701
- if (pathMatchExpr && ts3.isStringLiteral(pathMatchExpr)) {
5945
+ if (pathMatchExpr && ts4.isStringLiteral(pathMatchExpr)) {
5702
5946
  const val = pathMatchExpr.text;
5703
5947
  if (val === "full" || val === "prefix") {
5704
5948
  route.pathMatch = val;
5705
5949
  }
5706
5950
  }
5707
5951
  const titleExpr = getProp(optionsObject, "title");
5708
- if (titleExpr && ts3.isStringLiteral(titleExpr)) {
5952
+ if (titleExpr && ts4.isStringLiteral(titleExpr)) {
5709
5953
  route.title = titleExpr.text;
5710
5954
  }
5711
5955
  const dataExpr = getProp(optionsObject, "data");
5712
- if (dataExpr && ts3.isObjectLiteralExpression(dataExpr)) {
5956
+ if (dataExpr && ts4.isObjectLiteralExpression(dataExpr)) {
5713
5957
  route.data = { ...route.data, ...parseObjectLiteralValues(dataExpr) };
5714
5958
  }
5715
5959
  const aspects = parseAspectRefs(getProp(optionsObject, "aspects"), ctx, `route ${httpMethod} ${routePath}`);
@@ -5764,7 +6008,7 @@ function parseJobOptions(meta, owner, ctx) {
5764
6008
  const expression = getProp(meta, field);
5765
6009
  if (!expression)
5766
6010
  continue;
5767
- if (!ts3.isIdentifier(expression)) {
6011
+ if (!ts4.isIdentifier(expression)) {
5768
6012
  jobOptionError(ctx, "invalid-job-schema", `${owner} 的 ${field} schema 必须是可静态解析的标识符引用,不能使用内联调用或动态表达式`, expression, "SC4019", `将 schema 提取为命名导出,例如 ${field}: ${field === "input" ? "JobInput" : "JobOutput"}。`);
5769
6013
  continue;
5770
6014
  }
@@ -5788,7 +6032,7 @@ function parseJobEnum(meta, field, allowed, owner, ctx, code, errorCode) {
5788
6032
  const expression = getProp(meta, field);
5789
6033
  if (!expression)
5790
6034
  return;
5791
- if (!ts3.isStringLiteral(expression) || !allowed.includes(expression.text)) {
6035
+ if (!ts4.isStringLiteral(expression) || !allowed.includes(expression.text)) {
5792
6036
  jobOptionError(ctx, code, `${owner} 的 ${field} 必须是 ${allowed.map((value) => JSON.stringify(value)).join(" 或 ")} 字符串字面量`, expression, errorCode);
5793
6037
  return;
5794
6038
  }
@@ -5798,7 +6042,7 @@ function parseJobInteger(meta, field, min, max, owner, ctx, code, errorCode) {
5798
6042
  const expression = getProp(meta, field);
5799
6043
  if (!expression)
5800
6044
  return;
5801
- const value = ts3.isNumericLiteral(expression) ? Number(expression.text) : Number.NaN;
6045
+ const value = ts4.isNumericLiteral(expression) ? Number(expression.text) : Number.NaN;
5802
6046
  if (!Number.isSafeInteger(value) || value < min || value > max) {
5803
6047
  jobOptionError(ctx, code, `${owner} 的 ${field} 必须是 ${min} 到 ${max} 之间的安全整数`, expression, errorCode);
5804
6048
  return;
@@ -5819,8 +6063,8 @@ function jobOptionError(ctx, code, message, node, errorCode, suggestion) {
5819
6063
  }
5820
6064
  function jobSchemaKind(identifier, declaration, ctx) {
5821
6065
  const typeName = ctx.checker.typeToString(ctx.checker.getTypeAtLocation(identifier));
5822
- const initializer = ts3.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
5823
- const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts3.isCallExpression(initializer) && ts3.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
6066
+ const initializer = ts4.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
6067
+ const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts4.isCallExpression(initializer) && ts4.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
5824
6068
  return opaque ? "opaque" : "declared";
5825
6069
  }
5826
6070
  function checkedRpc(meta, ctx) {
@@ -5842,7 +6086,7 @@ function checkedRpc(meta, ctx) {
5842
6086
  }
5843
6087
  function classDeps(cls, ctx) {
5844
6088
  const injectable = parseInjectableOptions(cls, ctx);
5845
- const ctor = cls.members.find(ts3.isConstructorDeclaration);
6089
+ const ctor = cls.members.find(ts4.isConstructorDeclaration);
5846
6090
  const deps = injectable?.deps ? [...injectable.deps] : [];
5847
6091
  const optionalDeps = [];
5848
6092
  const selfDeps = [];
@@ -5876,23 +6120,23 @@ function classDeps(cls, ctx) {
5876
6120
  }
5877
6121
  });
5878
6122
  }
5879
- for (const prop of cls.members.filter(ts3.isPropertyDeclaration)) {
6123
+ for (const prop of cls.members.filter(ts4.isPropertyDeclaration)) {
5880
6124
  const init = prop.initializer;
5881
- if (init && ts3.isCallExpression(init)) {
6125
+ if (init && ts4.isCallExpression(init)) {
5882
6126
  const callName = nodeText(init.expression).split(".").pop();
5883
6127
  if (callName === "inject") {
5884
6128
  const [tokenArg, optionsArg] = init.arguments;
5885
6129
  if (tokenArg) {
5886
6130
  const tokenName = tokenText(tokenArg, ctx);
5887
6131
  const unwrappedToken = unwrapForwardRef(tokenArg);
5888
- const known = ts3.isStringLiteral(unwrappedToken) || ts3.isIdentifier(unwrappedToken) && (ctx.tokensByName.has(tokenName) || ctx.classesByName.has(tokenName));
6132
+ const known = ts4.isStringLiteral(unwrappedToken) || ts4.isIdentifier(unwrappedToken) && (ctx.tokensByName.has(tokenName) || ctx.classesByName.has(tokenName));
5889
6133
  if (!known) {
5890
6134
  missing = true;
5891
6135
  continue;
5892
6136
  }
5893
6137
  if (!deps.includes(tokenName))
5894
6138
  deps.push(tokenName);
5895
- const options = optionsArg && ts3.isObjectLiteralExpression(optionsArg) ? {
6139
+ const options = optionsArg && ts4.isObjectLiteralExpression(optionsArg) ? {
5896
6140
  optional: booleanProp(optionsArg, "optional") ?? false,
5897
6141
  self: booleanProp(optionsArg, "self") ?? false,
5898
6142
  skipSelf: booleanProp(optionsArg, "skipSelf") ?? false,
@@ -5907,9 +6151,9 @@ function classDeps(cls, ctx) {
5907
6151
  if (options.host && !hostDeps.includes(tokenName))
5908
6152
  hostDeps.push(tokenName);
5909
6153
  if (!functionalInjects.some((entry) => entry.token === tokenName)) {
5910
- const declaration = ts3.isIdentifier(unwrappedToken) ? resolveDeclaration(unwrappedToken, ctx)[0] : undefined;
6154
+ const declaration = ts4.isIdentifier(unwrappedToken) ? resolveDeclaration(unwrappedToken, ctx)[0] : undefined;
5911
6155
  const localFile = declaration && isProjectSourcePath(declaration.getSourceFile().fileName, ctx.rootDir) ? declaration.getSourceFile().fileName : undefined;
5912
- const importModule = declaration && !localFile && ts3.isIdentifier(unwrappedToken) ? importModuleOf(unwrappedToken, ctx) : undefined;
6156
+ const importModule = declaration && !localFile && ts4.isIdentifier(unwrappedToken) ? importModuleOf(unwrappedToken, ctx) : undefined;
5913
6157
  functionalInjects.push({
5914
6158
  token: tokenName,
5915
6159
  expression: nodeText(unwrappedToken),
@@ -5953,7 +6197,7 @@ function parseInjectableOptions(cls, ctx) {
5953
6197
  }
5954
6198
  function parseInjectParams(cls, ctx) {
5955
6199
  const result = new Map;
5956
- const ctor = cls.members.find(ts3.isConstructorDeclaration);
6200
+ const ctor = cls.members.find(ts4.isConstructorDeclaration);
5957
6201
  if (!ctor)
5958
6202
  return result;
5959
6203
  ctor.parameters.forEach((param, index) => {
@@ -5969,7 +6213,7 @@ function parseInjectParams(cls, ctx) {
5969
6213
  }
5970
6214
  function parseOptionalParams(cls) {
5971
6215
  const result = new Set;
5972
- const ctor = cls.members.find(ts3.isConstructorDeclaration);
6216
+ const ctor = cls.members.find(ts4.isConstructorDeclaration);
5973
6217
  if (!ctor)
5974
6218
  return result;
5975
6219
  ctor.parameters.forEach((param, index) => {
@@ -5984,7 +6228,7 @@ function parseOptionalParams(cls) {
5984
6228
  }
5985
6229
  function parseModifierParams(cls, modifierName) {
5986
6230
  const result = new Set;
5987
- const ctor = cls.members.find(ts3.isConstructorDeclaration);
6231
+ const ctor = cls.members.find(ts4.isConstructorDeclaration);
5988
6232
  if (!ctor)
5989
6233
  return result;
5990
6234
  ctor.parameters.forEach((param, index) => {
@@ -5996,13 +6240,13 @@ function parseModifierParams(cls, modifierName) {
5996
6240
  return result;
5997
6241
  }
5998
6242
  function unwrapForwardRef(expr) {
5999
- if (ts3.isCallExpression(expr)) {
6243
+ if (ts4.isCallExpression(expr)) {
6000
6244
  const exprText = nodeText(expr.expression);
6001
6245
  if (exprText === "forwardRef" || exprText.endsWith(".forwardRef")) {
6002
6246
  const arg = expr.arguments[0];
6003
- if (arg && (ts3.isArrowFunction(arg) || ts3.isFunctionExpression(arg))) {
6247
+ if (arg && (ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg))) {
6004
6248
  const body = arg.body;
6005
- if (body && ts3.isExpression(body)) {
6249
+ if (body && ts4.isExpression(body)) {
6006
6250
  return unwrapForwardRef(body);
6007
6251
  }
6008
6252
  }
@@ -6012,13 +6256,13 @@ function unwrapForwardRef(expr) {
6012
6256
  }
6013
6257
  function tokenText(expr, ctx) {
6014
6258
  const unwrapped = unwrapForwardRef(expr);
6015
- if (ts3.isStringLiteral(unwrapped))
6259
+ if (ts4.isStringLiteral(unwrapped))
6016
6260
  return unwrapped.text;
6017
- if (ts3.isIdentifier(unwrapped)) {
6261
+ if (ts4.isIdentifier(unwrapped)) {
6018
6262
  const decl = resolveDeclaration(unwrapped, ctx)[0];
6019
- if (decl && ts3.isClassDeclaration(decl))
6263
+ if (decl && ts4.isClassDeclaration(decl))
6020
6264
  return decl.name?.text ?? unwrapped.text;
6021
- if (decl && ts3.isVariableDeclaration(decl))
6265
+ if (decl && ts4.isVariableDeclaration(decl))
6022
6266
  return variableName(decl);
6023
6267
  }
6024
6268
  return nodeText(unwrapped);
@@ -6038,12 +6282,12 @@ function resolveScope(input, ctx) {
6038
6282
  }
6039
6283
  function tokenNameOf(expr, ctx) {
6040
6284
  const unwrapped = unwrapForwardRef(expr);
6041
- if (ts3.isIdentifier(unwrapped)) {
6285
+ if (ts4.isIdentifier(unwrapped)) {
6042
6286
  const decl = resolveDeclaration(unwrapped, ctx)[0];
6043
- if (decl && ts3.isClassDeclaration(decl)) {
6287
+ if (decl && ts4.isClassDeclaration(decl)) {
6044
6288
  return { name: decl.name?.text ?? nodeText(expr), kind: "class" };
6045
6289
  }
6046
- if (decl && ts3.isVariableDeclaration(decl)) {
6290
+ if (decl && ts4.isVariableDeclaration(decl)) {
6047
6291
  const name = variableName(decl);
6048
6292
  return { name, kind: ctx.tokensByName.has(name) ? "injection-token" : "class" };
6049
6293
  }
@@ -6059,10 +6303,10 @@ function resolveDeclaration(id, ctx) {
6059
6303
  return [];
6060
6304
  let declarations = symbol.declarations ?? [];
6061
6305
  for (let guard = 0;guard < 4; guard += 1) {
6062
- const isAlias = declarations.some((d) => ts3.isImportSpecifier(d) || ts3.isImportClause(d) || ts3.isNamespaceImport(d));
6306
+ const isAlias = declarations.some((d) => ts4.isImportSpecifier(d) || ts4.isImportClause(d) || ts4.isNamespaceImport(d));
6063
6307
  if (!isAlias)
6064
6308
  break;
6065
- if (!(symbol.flags & ts3.SymbolFlags.Alias))
6309
+ if (!(symbol.flags & ts4.SymbolFlags.Alias))
6066
6310
  break;
6067
6311
  const aliased = ctx.checker.getAliasedSymbol(symbol);
6068
6312
  symbol = aliased;
@@ -6082,9 +6326,9 @@ function importModuleOf(id, ctx) {
6082
6326
  for (const declaration of declarations) {
6083
6327
  let current = declaration;
6084
6328
  while (current) {
6085
- if (ts3.isImportDeclaration(current)) {
6329
+ if (ts4.isImportDeclaration(current)) {
6086
6330
  const moduleSpecifier = current.moduleSpecifier;
6087
- return ts3.isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : undefined;
6331
+ return ts4.isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : undefined;
6088
6332
  }
6089
6333
  current = current.parent;
6090
6334
  }
@@ -6096,27 +6340,27 @@ function findDecorator(cls, name) {
6096
6340
  }
6097
6341
  function decoratorName2(dec) {
6098
6342
  const expr = dec.expression;
6099
- if (ts3.isCallExpression(expr)) {
6343
+ if (ts4.isCallExpression(expr)) {
6100
6344
  return nodeText(expr.expression).split(".").pop();
6101
6345
  }
6102
- if (ts3.isIdentifier(expr))
6346
+ if (ts4.isIdentifier(expr))
6103
6347
  return expr.text;
6104
6348
  return;
6105
6349
  }
6106
6350
  function decoratorObjectArg(dec) {
6107
6351
  const expr = dec.expression;
6108
- if (!ts3.isCallExpression(expr))
6352
+ if (!ts4.isCallExpression(expr))
6109
6353
  return;
6110
6354
  const arg = expr.arguments[0];
6111
- return arg && ts3.isObjectLiteralExpression(arg) ? arg : undefined;
6355
+ return arg && ts4.isObjectLiteralExpression(arg) ? arg : undefined;
6112
6356
  }
6113
6357
  function getProp(obj, name) {
6114
- const prop = obj.properties.find((item) => (ts3.isPropertyAssignment(item) || ts3.isShorthandPropertyAssignment(item)) && propertyName(item.name) === name);
6358
+ const prop = obj.properties.find((item) => (ts4.isPropertyAssignment(item) || ts4.isShorthandPropertyAssignment(item)) && propertyName(item.name) === name);
6115
6359
  if (!prop)
6116
6360
  return;
6117
- if (ts3.isPropertyAssignment(prop))
6361
+ if (ts4.isPropertyAssignment(prop))
6118
6362
  return prop.initializer;
6119
- if (ts3.isShorthandPropertyAssignment(prop))
6363
+ if (ts4.isShorthandPropertyAssignment(prop))
6120
6364
  return prop.name;
6121
6365
  return;
6122
6366
  }
@@ -6124,10 +6368,10 @@ function toCompilerDiagnostic(diagnostic, rootDir) {
6124
6368
  const file = diagnostic.file;
6125
6369
  const position = file && diagnostic.start !== undefined ? file.getLineAndCharacterOfPosition(diagnostic.start) : undefined;
6126
6370
  return {
6127
- severity: diagnostic.category === ts3.DiagnosticCategory.Error ? "error" : "warn",
6371
+ severity: diagnostic.category === ts4.DiagnosticCategory.Error ? "error" : "warn",
6128
6372
  code: `typescript-${diagnostic.code}`,
6129
6373
  errorCode: `TS${diagnostic.code}`,
6130
- message: ts3.flattenDiagnosticMessageText(diagnostic.messageText, `
6374
+ message: ts4.flattenDiagnosticMessageText(diagnostic.messageText, `
6131
6375
  `),
6132
6376
  ...file ? { file: sourcePath(rootDir, file.fileName) } : {},
6133
6377
  ...position ? { line: position.line + 1 } : {}
@@ -6135,16 +6379,16 @@ function toCompilerDiagnostic(diagnostic, rootDir) {
6135
6379
  }
6136
6380
  function stringLiteralProp(obj, name) {
6137
6381
  const expr = getProp(obj, name);
6138
- return expr && ts3.isStringLiteral(expr) ? expr.text : undefined;
6382
+ return expr && ts4.isStringLiteral(expr) ? expr.text : undefined;
6139
6383
  }
6140
6384
  function arrayProp(obj, name) {
6141
6385
  const expr = getProp(obj, name);
6142
- return expr && ts3.isArrayLiteralExpression(expr) ? [...expr.elements] : [];
6386
+ return expr && ts4.isArrayLiteralExpression(expr) ? [...expr.elements] : [];
6143
6387
  }
6144
6388
  function parseAspectRefs(expression, ctx, owner) {
6145
6389
  if (!expression)
6146
6390
  return [];
6147
- if (!ts3.isArrayLiteralExpression(expression)) {
6391
+ if (!ts4.isArrayLiteralExpression(expression)) {
6148
6392
  ctx.diagnostics.push({
6149
6393
  severity: "error",
6150
6394
  code: "dynamic-aspect-reference",
@@ -6159,7 +6403,7 @@ function parseAspectRefs(expression, ctx, owner) {
6159
6403
  }
6160
6404
  const refs = [];
6161
6405
  for (const element of expression.elements) {
6162
- if (ts3.isSpreadElement(element) || !ts3.isIdentifier(element)) {
6406
+ if (ts4.isSpreadElement(element) || !ts4.isIdentifier(element)) {
6163
6407
  ctx.diagnostics.push({
6164
6408
  severity: "error",
6165
6409
  code: "dynamic-aspect-reference",
@@ -6172,7 +6416,7 @@ function parseAspectRefs(expression, ctx, owner) {
6172
6416
  });
6173
6417
  continue;
6174
6418
  }
6175
- const declaration = resolveDeclaration(element, ctx).find((candidate) => ts3.isFunctionDeclaration(candidate) || ts3.isVariableDeclaration(candidate) && candidate.initializer !== undefined && (ts3.isArrowFunction(candidate.initializer) || ts3.isFunctionExpression(candidate.initializer)));
6419
+ const declaration = resolveDeclaration(element, ctx).find((candidate) => ts4.isFunctionDeclaration(candidate) || ts4.isVariableDeclaration(candidate) && candidate.initializer !== undefined && (ts4.isArrowFunction(candidate.initializer) || ts4.isFunctionExpression(candidate.initializer)));
6176
6420
  if (!declaration) {
6177
6421
  ctx.diagnostics.push({
6178
6422
  severity: "error",
@@ -6186,7 +6430,7 @@ function parseAspectRefs(expression, ctx, owner) {
6186
6430
  });
6187
6431
  continue;
6188
6432
  }
6189
- const name = ts3.isFunctionDeclaration(declaration) ? declaration.name?.text : ts3.isVariableDeclaration(declaration) ? variableName(declaration) : undefined;
6433
+ const name = ts4.isFunctionDeclaration(declaration) ? declaration.name?.text : ts4.isVariableDeclaration(declaration) ? variableName(declaration) : undefined;
6190
6434
  if (!name)
6191
6435
  continue;
6192
6436
  const declaredFile = declaration.getSourceFile().fileName;
@@ -6206,9 +6450,9 @@ function booleanProp(obj, name) {
6206
6450
  const expr = getProp(obj, name);
6207
6451
  if (!expr)
6208
6452
  return;
6209
- if (expr.kind === ts3.SyntaxKind.TrueKeyword)
6453
+ if (expr.kind === ts4.SyntaxKind.TrueKeyword)
6210
6454
  return true;
6211
- if (expr.kind === ts3.SyntaxKind.FalseKeyword)
6455
+ if (expr.kind === ts4.SyntaxKind.FalseKeyword)
6212
6456
  return false;
6213
6457
  return;
6214
6458
  }
@@ -6222,15 +6466,15 @@ function parseBindingOptions(args, defaultName) {
6222
6466
  let defaultValue;
6223
6467
  const first = args[0];
6224
6468
  const second = args[1];
6225
- if (first && ts3.isStringLiteral(first)) {
6469
+ if (first && ts4.isStringLiteral(first)) {
6226
6470
  name = first.text;
6227
- } else if (first && ts3.isObjectLiteralExpression(first)) {
6471
+ } else if (first && ts4.isObjectLiteralExpression(first)) {
6228
6472
  const nameProp = getProp(first, "name");
6229
- if (nameProp && ts3.isStringLiteral(nameProp)) {
6473
+ if (nameProp && ts4.isStringLiteral(nameProp)) {
6230
6474
  name = nameProp.text;
6231
6475
  }
6232
6476
  const trProp = getProp(first, "transform");
6233
- if (trProp && ts3.isStringLiteral(trProp)) {
6477
+ if (trProp && ts4.isStringLiteral(trProp)) {
6234
6478
  const val = trProp.text;
6235
6479
  if (val === "number" || val === "boolean" || val === "string") {
6236
6480
  transform = val;
@@ -6241,9 +6485,9 @@ function parseBindingOptions(args, defaultName) {
6241
6485
  defaultValue = parseLiteralValue(defProp);
6242
6486
  }
6243
6487
  }
6244
- if (second && ts3.isObjectLiteralExpression(second)) {
6488
+ if (second && ts4.isObjectLiteralExpression(second)) {
6245
6489
  const trProp = getProp(second, "transform");
6246
- if (trProp && ts3.isStringLiteral(trProp)) {
6490
+ if (trProp && ts4.isStringLiteral(trProp)) {
6247
6491
  const val = trProp.text;
6248
6492
  if (val === "number" || val === "boolean" || val === "string") {
6249
6493
  transform = val;
@@ -6257,18 +6501,18 @@ function parseBindingOptions(args, defaultName) {
6257
6501
  return { name, ...transform ? { transform } : {}, default: defaultValue };
6258
6502
  }
6259
6503
  function parseLiteralValue(node) {
6260
- if (ts3.isStringLiteral(node))
6504
+ if (ts4.isStringLiteral(node))
6261
6505
  return node.text;
6262
- if (ts3.isNumericLiteral(node))
6506
+ if (ts4.isNumericLiteral(node))
6263
6507
  return Number(node.text);
6264
- if (node.kind === ts3.SyntaxKind.TrueKeyword)
6508
+ if (node.kind === ts4.SyntaxKind.TrueKeyword)
6265
6509
  return true;
6266
- if (node.kind === ts3.SyntaxKind.FalseKeyword)
6510
+ if (node.kind === ts4.SyntaxKind.FalseKeyword)
6267
6511
  return false;
6268
- if (ts3.isArrayLiteralExpression(node)) {
6512
+ if (ts4.isArrayLiteralExpression(node)) {
6269
6513
  return node.elements.map(parseLiteralValue);
6270
6514
  }
6271
- if (ts3.isObjectLiteralExpression(node)) {
6515
+ if (ts4.isObjectLiteralExpression(node)) {
6272
6516
  return parseObjectLiteralValues(node);
6273
6517
  }
6274
6518
  return;
@@ -6276,7 +6520,7 @@ function parseLiteralValue(node) {
6276
6520
  function parseObjectLiteralValues(obj) {
6277
6521
  const result = {};
6278
6522
  for (const prop of obj.properties) {
6279
- if (ts3.isPropertyAssignment(prop)) {
6523
+ if (ts4.isPropertyAssignment(prop)) {
6280
6524
  const name = propertyName(prop.name);
6281
6525
  const init = prop.initializer;
6282
6526
  if (init) {
@@ -6310,7 +6554,50 @@ import { join as join4 } from "node:path";
6310
6554
  // src/type-safety.ts
6311
6555
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
6312
6556
  import { dirname as dirname3, join as join3, relative as relative3, resolve as resolve2, sep as sep3 } from "node:path";
6313
- import * as ts4 from "@typescript/typescript6";
6557
+ import * as ts6 from "@typescript/typescript6";
6558
+
6559
+ // src/sql-safety.ts
6560
+ import * as ts5 from "@typescript/typescript6";
6561
+ var SQL_SAFETY_DIAGNOSTIC_CODES = {
6562
+ "sql-result-assertion": { errorCode: "SC6007", docsUrl: "https://supacloud.dev/errors/SC6007" },
6563
+ "sql-raw-dynamic": { errorCode: "SC6008", docsUrl: "https://supacloud.dev/errors/SC6008" }
6564
+ };
6565
+ function scanDrizzleSql(sourceFile, checker, file, strict) {
6566
+ const diagnostics = [];
6567
+ const importedSql = (expression) => {
6568
+ const symbol = checker.getSymbolAtLocation(ts5.isPropertyAccessExpression(expression) ? expression.name : expression);
6569
+ if (!symbol)
6570
+ return false;
6571
+ const target = symbol.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
6572
+ return target.name === "sql" && (target.declarations ?? []).some((declaration) => /(?:^|\/)node_modules\/drizzle-orm\//.test(declaration.getSourceFile().fileName.replaceAll("\\", "/")));
6573
+ };
6574
+ const report = (code, node, message) => {
6575
+ diagnostics.push({
6576
+ severity: strict ? "error" : "warn",
6577
+ code,
6578
+ ...SQL_SAFETY_DIAGNOSTIC_CODES[code],
6579
+ message,
6580
+ file,
6581
+ line: sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1
6582
+ });
6583
+ };
6584
+ const visit = (node) => {
6585
+ if (ts5.isTaggedTemplateExpression(node) && importedSql(node.tag) && node.typeArguments?.some((type) => type.kind !== ts5.SyntaxKind.UnknownKeyword)) {
6586
+ report("sql-result-assertion", node, "Drizzle sql<T> asserts a result type without checking SQL or decoding rows. Use sql<unknown> and a schema decoder at the result boundary.");
6587
+ }
6588
+ if (ts5.isCallExpression(node) && ts5.isPropertyAccessExpression(node.expression) && node.expression.name.text === "raw" && importedSql(node.expression.expression)) {
6589
+ const argument = node.arguments[0];
6590
+ if (!argument || !ts5.isStringLiteral(argument) && !ts5.isNoSubstitutionTemplateLiteral(argument)) {
6591
+ report("sql-raw-dynamic", node, "Dynamic sql.raw bypasses parameter binding. Interpolate values with sql templates; keep reviewed static DDL in migrations.");
6592
+ }
6593
+ }
6594
+ ts5.forEachChild(node, visit);
6595
+ };
6596
+ visit(sourceFile);
6597
+ return diagnostics;
6598
+ }
6599
+
6600
+ // src/type-safety.ts
6314
6601
  var DEFAULT_EXCLUDES = [
6315
6602
  "**/*.test.ts",
6316
6603
  "**/*.spec.ts",
@@ -6323,6 +6610,7 @@ var DEFAULT_EXCLUDES = [
6323
6610
  "**/*.d.ts"
6324
6611
  ];
6325
6612
  var TYPE_SAFETY_DIAGNOSTIC_CODES = {
6613
+ ...SQL_SAFETY_DIAGNOSTIC_CODES,
6326
6614
  "generated-any": { errorCode: "SC6001", docsUrl: "https://supacloud.dev/errors/SC6001" },
6327
6615
  "source-any": { errorCode: "SC6002", docsUrl: "https://supacloud.dev/errors/SC6002" },
6328
6616
  "source-type-assertion": { errorCode: "SC6003", docsUrl: "https://supacloud.dev/errors/SC6003" },
@@ -6335,7 +6623,7 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
6335
6623
  for (const [file, content] of Object.entries(artifacts)) {
6336
6624
  if (content === undefined)
6337
6625
  continue;
6338
- const sourceFile = ts4.createSourceFile(file, content, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TS);
6626
+ const sourceFile = ts6.createSourceFile(file, content, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TS);
6339
6627
  for (const node of descendantsOfKind2(sourceFile, isAnyKeyword)) {
6340
6628
  diagnostics.push(makeDiagnostic("generated-any", `生成产物 ${file} 包含 any;严格生成模式要求使用 unknown、具体接口或泛型约束。`, sourceFile, node, strict));
6341
6629
  }
@@ -6344,30 +6632,30 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
6344
6632
  }
6345
6633
  function scanProductionSource(options) {
6346
6634
  const rootDir = resolve2(options.rootDir);
6347
- const configPath = ts4.findConfigFile(rootDir, ts4.sys.fileExists) ?? join3(rootDir, "tsconfig.json");
6635
+ const configPath = ts6.findConfigFile(rootDir, ts6.sys.fileExists) ?? join3(rootDir, "tsconfig.json");
6348
6636
  const projectConfig = existsSync2(configPath) ? readProjectConfig2(configPath) : {
6349
6637
  options: {
6350
6638
  strict: true,
6351
6639
  skipLibCheck: true,
6352
- target: ts4.ScriptTarget.ES2022,
6353
- module: ts4.ModuleKind.ESNext,
6354
- moduleResolution: ts4.ModuleResolutionKind.Bundler
6640
+ target: ts6.ScriptTarget.ES2022,
6641
+ module: ts6.ModuleKind.ESNext,
6642
+ moduleResolution: ts6.ModuleResolutionKind.Bundler
6355
6643
  },
6356
6644
  errors: []
6357
6645
  };
6358
6646
  const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
6359
- const rootNames = ts4.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist"], include).filter((file) => isProductionSourcePath(rootDir, file, [...DEFAULT_EXCLUDES, ...options.exclude ?? []]));
6647
+ const rootNames = ts6.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist"], include).filter((file) => isProductionSourcePath(rootDir, file, [...DEFAULT_EXCLUDES, ...options.exclude ?? []]));
6360
6648
  const compilerOptions = { ...projectConfig.options, noEmit: true };
6361
- const host = ts4.createCompilerHost(compilerOptions);
6649
+ const host = ts6.createCompilerHost(compilerOptions);
6362
6650
  host.getCurrentDirectory = () => dirname3(configPath);
6363
- const program = ts4.createProgram(rootNames, compilerOptions, host);
6651
+ const program = ts6.createProgram(rootNames, compilerOptions, host);
6364
6652
  const outDir = options.outDir ? normalizeRelative(rootDir, options.outDir) : undefined;
6365
6653
  const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
6366
6654
  const sourceFiles = program.getSourceFiles().filter((sourceFile) => isProductionSource(rootDir, sourceFile, excludes, outDir));
6367
6655
  const diagnostics = [...projectConfig.errors, ...program.getOptionsDiagnostics()].map((diagnostic) => ({
6368
6656
  severity: "error",
6369
6657
  code: "source-config",
6370
- message: ts4.flattenDiagnosticMessageText(diagnostic.messageText, `
6658
+ message: ts6.flattenDiagnosticMessageText(diagnostic.messageText, `
6371
6659
  `),
6372
6660
  file: diagnostic.file ? normalizeRelative(rootDir, diagnostic.file.fileName) : normalizeRelative(rootDir, configPath),
6373
6661
  ...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
@@ -6384,7 +6672,7 @@ function scanProductionSource(options) {
6384
6672
  diagnostics.push({
6385
6673
  severity: "error",
6386
6674
  code: "source-typescript",
6387
- message: ts4.flattenDiagnosticMessageText(diagnostic.messageText, `
6675
+ message: ts6.flattenDiagnosticMessageText(diagnostic.messageText, `
6388
6676
  `),
6389
6677
  ...diagnostic.file ? { file: normalizeRelative(rootDir, diagnostic.file.fileName) } : {},
6390
6678
  ...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
@@ -6393,9 +6681,10 @@ function scanProductionSource(options) {
6393
6681
  }
6394
6682
  for (const sourceFile of sourceFiles) {
6395
6683
  scanSourceFile(sourceFile, checker, rootDir, diagnostics, options.strict ?? false);
6396
- const scanner = ts4.createScanner(ts4.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
6397
- for (let kind = scanner.scan();kind !== ts4.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
6398
- if ((kind === ts4.SyntaxKind.SingleLineCommentTrivia || kind === ts4.SyntaxKind.MultiLineCommentTrivia) && /@ts-(?:ignore|nocheck|expect-error)\b/.test(scanner.getTokenText())) {
6684
+ diagnostics.push(...scanDrizzleSql(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), options.strict ?? false));
6685
+ const scanner = ts6.createScanner(ts6.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
6686
+ for (let kind = scanner.scan();kind !== ts6.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
6687
+ if ((kind === ts6.SyntaxKind.SingleLineCommentTrivia || kind === ts6.SyntaxKind.MultiLineCommentTrivia) && /@ts-(?:ignore|nocheck|expect-error)\b/.test(scanner.getTokenText())) {
6399
6688
  diagnostics.push({
6400
6689
  severity: "error",
6401
6690
  code: "source-type-suppression",
@@ -6415,22 +6704,22 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
6415
6704
  diagnostics.push(makeDiagnostic("source-any", "生产源码使用了显式 any;请改用 unknown、具体接口或泛型约束。", sourceFile, node, strict, rootDir));
6416
6705
  }
6417
6706
  for (const node of descendants(sourceFile)) {
6418
- if (ts4.isAsExpression(node)) {
6419
- if (ts4.isAsExpression(node.parent) || ts4.isTypeAssertionExpression(node.parent))
6707
+ if (ts6.isAsExpression(node)) {
6708
+ if (ts6.isAsExpression(node.parent) || ts6.isTypeAssertionExpression(node.parent))
6420
6709
  continue;
6421
6710
  const assertedType = node.type.getText(sourceFile);
6422
6711
  if (assertedType === "const")
6423
6712
  continue;
6424
6713
  diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
6425
- } else if (ts4.isTypeAssertionExpression(node)) {
6426
- if (ts4.isAsExpression(node.parent) || ts4.isTypeAssertionExpression(node.parent))
6714
+ } else if (ts6.isTypeAssertionExpression(node)) {
6715
+ if (ts6.isAsExpression(node.parent) || ts6.isTypeAssertionExpression(node.parent))
6427
6716
  continue;
6428
6717
  diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
6429
- } else if (ts4.isNonNullExpression(node)) {
6718
+ } else if (ts6.isNonNullExpression(node)) {
6430
6719
  diagnostics.push(makeDiagnostic("source-non-null-assertion", `生产源码包含非空断言 ${node.getText(sourceFile)};请显式处理 null/undefined。`, sourceFile, node, strict, rootDir));
6431
6720
  }
6432
6721
  }
6433
- for (const declaration of descendantsOfKind2(sourceFile, ts4.isVariableDeclaration)) {
6722
+ for (const declaration of descendantsOfKind2(sourceFile, ts6.isVariableDeclaration)) {
6434
6723
  const initializer = declaration.initializer;
6435
6724
  if (!initializer || declaration.type)
6436
6725
  continue;
@@ -6446,11 +6735,11 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
6446
6735
  if (isLetDeclaration(declaration) && isLiteralSyntax(initializer) && !isLiteralType(declarationType)) {
6447
6736
  diagnostics.push(makeDiagnostic("source-implicit-widening", `变量 ${declaration.name.getText(sourceFile)} 的字面量类型从 ${checker.typeToString(initializerType, initializer)} 隐式宽化为 ${checker.typeToString(declarationType, declaration)};请补充类型或使用 const。`, sourceFile, declaration, strict, rootDir));
6448
6737
  }
6449
- if (ts4.isObjectLiteralExpression(initializer) && isConstDeclaration(declaration) && initializer.getText(sourceFile).length > 0 && initializer.properties.some((property) => ts4.isPropertyAssignment(property) && property.initializer !== undefined && !ts4.isAsExpression(property.initializer) && isLiteralExpression(property.initializer))) {
6738
+ if (ts6.isObjectLiteralExpression(initializer) && isConstDeclaration(declaration) && initializer.getText(sourceFile).length > 0 && initializer.properties.some((property) => ts6.isPropertyAssignment(property) && property.initializer !== undefined && !ts6.isAsExpression(property.initializer) && isLiteralExpression(property.initializer))) {
6450
6739
  diagnostics.push(makeDiagnostic("source-implicit-widening", `常量对象 ${declaration.name.getText(sourceFile)} 的字面量属性会隐式宽化;请补充对象类型或使用 as const。`, sourceFile, declaration, strict, rootDir));
6451
6740
  }
6452
6741
  }
6453
- for (const parameter of descendantsOfKind2(sourceFile, ts4.isParameter)) {
6742
+ for (const parameter of descendantsOfKind2(sourceFile, ts6.isParameter)) {
6454
6743
  if (parameter.type)
6455
6744
  continue;
6456
6745
  for (const name of bindingNames(parameter.name)) {
@@ -6461,10 +6750,10 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
6461
6750
  }
6462
6751
  }
6463
6752
  function readProjectConfig2(configPath) {
6464
- const config = ts4.readConfigFile(configPath, (file) => readFileSync2(file, "utf8"));
6753
+ const config = ts6.readConfigFile(configPath, (file) => readFileSync2(file, "utf8"));
6465
6754
  if (config.error)
6466
6755
  return { options: {}, errors: [config.error] };
6467
- const parsed = ts4.parseJsonConfigFileContent(config.config, ts4.sys, dirname3(configPath));
6756
+ const parsed = ts6.parseJsonConfigFileContent(config.config, ts6.sys, dirname3(configPath));
6468
6757
  return { options: parsed.options, errors: parsed.errors };
6469
6758
  }
6470
6759
  function isProductionSource(rootDir, sourceFile, excludes, outDir) {
@@ -6484,42 +6773,42 @@ function globMatches(value, pattern) {
6484
6773
  return new RegExp(`^${escaped}$`).test(value);
6485
6774
  }
6486
6775
  function bindingNames(name) {
6487
- if (ts4.isIdentifier(name))
6776
+ if (ts6.isIdentifier(name))
6488
6777
  return [name];
6489
- return name.elements.flatMap((element) => ts4.isBindingElement(element) ? bindingNames(element.name) : []);
6778
+ return name.elements.flatMap((element) => ts6.isBindingElement(element) ? bindingNames(element.name) : []);
6490
6779
  }
6491
6780
  function isLiteralExpression(node) {
6492
6781
  if (!node)
6493
6782
  return false;
6494
6783
  return [
6495
- ts4.SyntaxKind.StringLiteral,
6496
- ts4.SyntaxKind.NumericLiteral,
6497
- ts4.SyntaxKind.TrueKeyword,
6498
- ts4.SyntaxKind.FalseKeyword
6784
+ ts6.SyntaxKind.StringLiteral,
6785
+ ts6.SyntaxKind.NumericLiteral,
6786
+ ts6.SyntaxKind.TrueKeyword,
6787
+ ts6.SyntaxKind.FalseKeyword
6499
6788
  ].includes(node.kind);
6500
6789
  }
6501
6790
  function isLiteralSyntax(node) {
6502
- return ts4.isStringLiteral(node) || ts4.isNumericLiteral(node) || node.kind === ts4.SyntaxKind.TrueKeyword || node.kind === ts4.SyntaxKind.FalseKeyword;
6791
+ return ts6.isStringLiteral(node) || ts6.isNumericLiteral(node) || node.kind === ts6.SyntaxKind.TrueKeyword || node.kind === ts6.SyntaxKind.FalseKeyword;
6503
6792
  }
6504
6793
  function isLiteralType(type) {
6505
- return (type.flags & (ts4.TypeFlags.StringLiteral | ts4.TypeFlags.NumberLiteral | ts4.TypeFlags.BooleanLiteral | ts4.TypeFlags.BigIntLiteral)) !== 0;
6794
+ return (type.flags & (ts6.TypeFlags.StringLiteral | ts6.TypeFlags.NumberLiteral | ts6.TypeFlags.BooleanLiteral | ts6.TypeFlags.BigIntLiteral)) !== 0;
6506
6795
  }
6507
6796
  function isAnyType(type) {
6508
- return (type.flags & ts4.TypeFlags.Any) !== 0;
6797
+ return (type.flags & ts6.TypeFlags.Any) !== 0;
6509
6798
  }
6510
6799
  function isLetDeclaration(declaration) {
6511
- return ts4.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts4.NodeFlags.Let) !== 0;
6800
+ return ts6.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts6.NodeFlags.Let) !== 0;
6512
6801
  }
6513
6802
  function isConstDeclaration(declaration) {
6514
- return ts4.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts4.NodeFlags.Const) !== 0;
6803
+ return ts6.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts6.NodeFlags.Const) !== 0;
6515
6804
  }
6516
6805
  function descendants(root) {
6517
6806
  const result = [];
6518
6807
  const visit = (node) => {
6519
6808
  result.push(node);
6520
- ts4.forEachChild(node, visit);
6809
+ ts6.forEachChild(node, visit);
6521
6810
  };
6522
- ts4.forEachChild(root, visit);
6811
+ ts6.forEachChild(root, visit);
6523
6812
  return result;
6524
6813
  }
6525
6814
  function descendantsOfKind2(root, predicate) {
@@ -6527,9 +6816,9 @@ function descendantsOfKind2(root, predicate) {
6527
6816
  const visit = (node) => {
6528
6817
  if (predicate(node))
6529
6818
  result.push(node);
6530
- ts4.forEachChild(node, visit);
6819
+ ts6.forEachChild(node, visit);
6531
6820
  };
6532
- ts4.forEachChild(root, visit);
6821
+ ts6.forEachChild(root, visit);
6533
6822
  return result;
6534
6823
  }
6535
6824
  function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir) {
@@ -6550,7 +6839,7 @@ function normalizeRelative(rootDir, filePath) {
6550
6839
  return relative3(rootDir, filePath).split(sep3).join("/").replace(/^\.\//, "");
6551
6840
  }
6552
6841
  function isAnyKeyword(node) {
6553
- return node.kind === ts4.SyntaxKind.AnyKeyword;
6842
+ return node.kind === ts6.SyntaxKind.AnyKeyword;
6554
6843
  }
6555
6844
 
6556
6845
  // src/route-contracts.ts
@@ -6643,6 +6932,9 @@ async function compileProject(options) {
6643
6932
  ...graph.diagnostics ?? [],
6644
6933
  ...validateGraph(graph, options)
6645
6934
  ];
6935
+ if (diagnostics.some((item) => item.code === "runtime-injection-disallowed")) {
6936
+ return { diagnostics, graph, written: [] };
6937
+ }
6646
6938
  if (options.strict) {
6647
6939
  for (const diagnostic of diagnostics) {
6648
6940
  if (diagnostic.severity === "warn")
@@ -6701,6 +6993,9 @@ async function checkProject(options) {
6701
6993
  ...graph.diagnostics ?? [],
6702
6994
  ...validateGraph(graph, options)
6703
6995
  ];
6996
+ if (diagnostics.some((item) => item.code === "runtime-injection-disallowed")) {
6997
+ return { diagnostics, graph, upToDate: false, mismatches: ["Runtime DI must be migrated to constructor injection."] };
6998
+ }
6704
6999
  if (options.strict) {
6705
7000
  for (const diagnostic of diagnostics) {
6706
7001
  if (diagnostic.severity === "warn")
@@ -10839,7 +11134,7 @@ function compileOptionsFromConfig(config, cwd = process.cwd()) {
10839
11134
  import { randomUUID } from "node:crypto";
10840
11135
  import { lstat, readFile as readFile4, realpath, rename as rename2, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
10841
11136
  import { dirname as dirname6, isAbsolute as isAbsolute2, relative as relative8, resolve as resolve8, sep as sep8 } from "node:path";
10842
- import * as ts7 from "@typescript/typescript6";
11137
+ import * as ts9 from "@typescript/typescript6";
10843
11138
  async function applyDiagnosticFix(fix, options = {}) {
10844
11139
  if (!fix || typeof fix.targetFile !== "string")
10845
11140
  throw new Error("Invalid DiagnosticFix");
@@ -10864,7 +11159,7 @@ async function applyDiagnosticFix(fix, options = {}) {
10864
11159
  if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
10865
11160
  throw new Error("Command mode changed since diagnosis; analyze the project again");
10866
11161
  }
10867
- content = replaceProperty(source, object, fix.property, ts7.factory.createStringLiteral(fix.value));
11162
+ content = replaceProperty(source, object, fix.property, ts9.factory.createStringLiteral(fix.value));
10868
11163
  break;
10869
11164
  }
10870
11165
  case "add_module_import": {
@@ -10875,15 +11170,15 @@ async function applyDiagnosticFix(fix, options = {}) {
10875
11170
  source = parse3(file, withImport);
10876
11171
  const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
10877
11172
  const imports = property(object, "imports");
10878
- if (imports && !ts7.isArrayLiteralExpression(imports.initializer)) {
11173
+ if (imports && !ts9.isArrayLiteralExpression(imports.initializer)) {
10879
11174
  throw new Error("Module imports must be a static array");
10880
11175
  }
10881
- const values = imports && ts7.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
10882
- if (values.some(ts7.isSpreadElement))
11176
+ const values = imports && ts9.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
11177
+ if (values.some(ts9.isSpreadElement))
10883
11178
  throw new Error("Module imports cannot contain spread elements");
10884
- content = values.some((value) => ts7.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts7.factory.createArrayLiteralExpression([
11179
+ content = values.some((value) => ts9.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts9.factory.createArrayLiteralExpression([
10885
11180
  ...values,
10886
- ts7.factory.createIdentifier(fix.symbol)
11181
+ ts9.factory.createIdentifier(fix.symbol)
10887
11182
  ]));
10888
11183
  break;
10889
11184
  }
@@ -10895,24 +11190,24 @@ async function applyDiagnosticFix(fix, options = {}) {
10895
11190
  const command = findClass(source, fix.command);
10896
11191
  const object = decoratorObject(command, "Command");
10897
11192
  const current = property(object, "permission");
10898
- if (current && (!ts7.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
11193
+ if (current && (!ts9.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
10899
11194
  throw new Error("Command permission already exists with a different value");
10900
11195
  }
10901
- content = current ? original : replaceProperty(source, object, "permission", ts7.factory.createStringLiteral(permission));
11196
+ content = current ? original : replaceProperty(source, object, "permission", ts9.factory.createStringLiteral(permission));
10902
11197
  break;
10903
11198
  }
10904
11199
  case "add_route_parameter_binding": {
10905
11200
  const controller = findClass(source, fix.controller);
10906
- const method = unique(controller.members.filter((member) => ts7.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
10907
- const parameter = unique(method.parameters.filter((candidate) => ts7.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
11201
+ const method = unique(controller.members.filter((member) => ts9.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
11202
+ const parameter = unique(method.parameters.filter((candidate) => ts9.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
10908
11203
  const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
10909
11204
  if (!binding)
10910
11205
  throw new Error("Invalid route binding");
10911
- const decorators = ts7.getDecorators(parameter) ?? [];
11206
+ const decorators = ts9.getDecorators(parameter) ?? [];
10912
11207
  if (decorators.length > 0)
10913
11208
  throw new Error("Parameter already has a decorator");
10914
- const framework = unique(source.statements.filter((statement) => ts7.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts7.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
10915
- if (!ts7.isImportDeclaration(framework) || !ts7.isStringLiteral(framework.moduleSpecifier)) {
11209
+ const framework = unique(source.statements.filter((statement) => ts9.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts9.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
11210
+ if (!ts9.isImportDeclaration(framework) || !ts9.isStringLiteral(framework.moduleSpecifier)) {
10916
11211
  throw new Error("Framework import must be static");
10917
11212
  }
10918
11213
  const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
@@ -10938,15 +11233,15 @@ async function applyDiagnosticFix(fix, options = {}) {
10938
11233
  return result;
10939
11234
  }
10940
11235
  function parse3(file, text) {
10941
- const result = ts7.transpileModule(text, {
11236
+ const result = ts9.transpileModule(text, {
10942
11237
  fileName: file,
10943
11238
  reportDiagnostics: true,
10944
- compilerOptions: { target: ts7.ScriptTarget.ESNext, experimentalDecorators: true }
11239
+ compilerOptions: { target: ts9.ScriptTarget.ESNext, experimentalDecorators: true }
10945
11240
  });
10946
- if (result.diagnostics?.some((item) => item.category === ts7.DiagnosticCategory.Error)) {
11241
+ if (result.diagnostics?.some((item) => item.category === ts9.DiagnosticCategory.Error)) {
10947
11242
  throw new Error("Cannot fix syntactically invalid TypeScript");
10948
11243
  }
10949
- return ts7.createSourceFile(file, text, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TS);
11244
+ return ts9.createSourceFile(file, text, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TS);
10950
11245
  }
10951
11246
  function unique(items, description) {
10952
11247
  if (items.length !== 1)
@@ -10960,50 +11255,50 @@ function identifier(value) {
10960
11255
  function nameOf(name) {
10961
11256
  if (!name)
10962
11257
  return "";
10963
- return ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name) ? name.text : "";
11258
+ return ts9.isIdentifier(name) || ts9.isStringLiteral(name) || ts9.isNumericLiteral(name) ? name.text : "";
10964
11259
  }
10965
11260
  function property(object, key) {
10966
- if (object.properties.some((item) => !ts7.isPropertyAssignment(item) || ts7.isComputedPropertyName(item.name))) {
11261
+ if (object.properties.some((item) => !ts9.isPropertyAssignment(item) || ts9.isComputedPropertyName(item.name))) {
10967
11262
  throw new Error("Fix requires explicit static object properties");
10968
11263
  }
10969
- const values = object.properties.filter((item) => ts7.isPropertyAssignment(item) && nameOf(item.name) === key);
11264
+ const values = object.properties.filter((item) => ts9.isPropertyAssignment(item) && nameOf(item.name) === key);
10970
11265
  if (values.length > 1)
10971
11266
  throw new Error(`Duplicate '${key}' property`);
10972
11267
  return values[0];
10973
11268
  }
10974
11269
  function stringProperty(object, key) {
10975
11270
  const value = property(object, key)?.initializer;
10976
- return value && ts7.isStringLiteral(value) ? value.text : undefined;
11271
+ return value && ts9.isStringLiteral(value) ? value.text : undefined;
10977
11272
  }
10978
11273
  function replaceProperty(source, object, key, value) {
10979
11274
  const previous = property(object, key);
10980
- const replacement = ts7.factory.createPropertyAssignment(key, value);
11275
+ const replacement = ts9.factory.createPropertyAssignment(key, value);
10981
11276
  const properties = object.properties.map((item) => item === previous ? replacement : item);
10982
11277
  if (!previous)
10983
11278
  properties.push(replacement);
10984
- const updated = ts7.factory.updateObjectLiteralExpression(object, properties);
10985
- return source.text.slice(0, object.getStart(source)) + ts7.createPrinter().printNode(ts7.EmitHint.Expression, updated, source) + source.text.slice(object.end);
11279
+ const updated = ts9.factory.updateObjectLiteralExpression(object, properties);
11280
+ return source.text.slice(0, object.getStart(source)) + ts9.createPrinter().printNode(ts9.EmitHint.Expression, updated, source) + source.text.slice(object.end);
10986
11281
  }
10987
11282
  function findClass(source, name) {
10988
- return unique(source.statements.filter((statement) => ts7.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
11283
+ return unique(source.statements.filter((statement) => ts9.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
10989
11284
  }
10990
11285
  function decoratorObject(node, name) {
10991
- const decorator = unique((ts7.getDecorators(node) ?? []).filter((item) => ts7.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
10992
- const argument = ts7.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
10993
- if (!argument || !ts7.isObjectLiteralExpression(argument))
11286
+ const decorator = unique((ts9.getDecorators(node) ?? []).filter((item) => ts9.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
11287
+ const argument = ts9.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
11288
+ if (!argument || !ts9.isObjectLiteralExpression(argument))
10994
11289
  throw new Error(`@${name} requires a static object`);
10995
11290
  return argument;
10996
11291
  }
10997
11292
  function moduleObjects(source) {
10998
11293
  const result = [];
10999
11294
  for (const statement of source.statements) {
11000
- if (ts7.isClassDeclaration(statement) && (ts7.getDecorators(statement) ?? []).some((item) => ts7.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
11295
+ if (ts9.isClassDeclaration(statement) && (ts9.getDecorators(statement) ?? []).some((item) => ts9.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
11001
11296
  result.push(decoratorObject(statement, "Module"));
11002
11297
  }
11003
- if (ts7.isVariableStatement(statement)) {
11298
+ if (ts9.isVariableStatement(statement)) {
11004
11299
  for (const declaration of statement.declarationList.declarations) {
11005
11300
  const call = declaration.initializer;
11006
- if (call && ts7.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts7.isObjectLiteralExpression(call.arguments[0])) {
11301
+ if (call && ts9.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts9.isObjectLiteralExpression(call.arguments[0])) {
11007
11302
  result.push(call.arguments[0]);
11008
11303
  }
11009
11304
  }
@@ -11017,19 +11312,19 @@ function importSymbol(source, path, symbol) {
11017
11312
  const target = resolve8(dirname6(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
11018
11313
  if (current === target)
11019
11314
  return source.text;
11020
- const matches = source.statements.filter((item) => ts7.isImportDeclaration(item) && ts7.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
11315
+ const matches = source.statements.filter((item) => ts9.isImportDeclaration(item) && ts9.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
11021
11316
  if (matches.length > 1)
11022
11317
  throw new Error(`Ambiguous imports from '${path}'`);
11023
11318
  const match = matches[0];
11024
- if (match && ts7.isImportDeclaration(match) && match.importClause?.namedBindings && ts7.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
11319
+ if (match && ts9.isImportDeclaration(match) && match.importClause?.namedBindings && ts9.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
11025
11320
  if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
11026
11321
  return source.text;
11027
11322
  const bindings = match.importClause.namedBindings;
11028
- const updated = ts7.factory.updateNamedImports(bindings, [
11323
+ const updated = ts9.factory.updateNamedImports(bindings, [
11029
11324
  ...bindings.elements,
11030
- ts7.factory.createImportSpecifier(false, undefined, ts7.factory.createIdentifier(symbol))
11325
+ ts9.factory.createImportSpecifier(false, undefined, ts9.factory.createIdentifier(symbol))
11031
11326
  ]);
11032
- return source.text.slice(0, bindings.getStart(source)) + ts7.createPrinter().printNode(ts7.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
11327
+ return source.text.slice(0, bindings.getStart(source)) + ts9.createPrinter().printNode(ts9.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
11033
11328
  }
11034
11329
  if (match)
11035
11330
  throw new Error(`Import from '${path}' is not a named value import`);
@@ -11276,7 +11571,7 @@ function formatDeliveryPlan(result) {
11276
11571
  import { mkdir as mkdir3, mkdtemp, readFile as readFile7, realpath as realpath3, rename as rename4, rm as rm2 } from "node:fs/promises";
11277
11572
  import { readFileSync as readFileSync3 } from "node:fs";
11278
11573
  import { dirname as dirname8, join as join8, relative as relative10, resolve as resolve11, sep as sep10 } from "node:path";
11279
- import * as ts9 from "@typescript/typescript6";
11574
+ import * as ts11 from "@typescript/typescript6";
11280
11575
 
11281
11576
  // src/delivery-files.ts
11282
11577
  import { createHash as createHash8 } from "node:crypto";
@@ -11510,19 +11805,19 @@ function renderDeliveryTarget(graph, target, options) {
11510
11805
  import { isBuiltin } from "node:module";
11511
11806
  import { readFile as readFile6 } from "node:fs/promises";
11512
11807
  import { resolve as resolve10 } from "node:path";
11513
- import * as ts8 from "@typescript/typescript6";
11808
+ import * as ts10 from "@typescript/typescript6";
11514
11809
  function checkStaticImports(path, contents) {
11515
11810
  if (!/\.[cm]?[jt]sx?$/.test(path))
11516
11811
  return;
11517
- const source = ts8.createSourceFile(path, new TextDecoder().decode(contents), ts8.ScriptTarget.Latest, true);
11812
+ const source = ts10.createSourceFile(path, new TextDecoder().decode(contents), ts10.ScriptTarget.Latest, true);
11518
11813
  function visit(node) {
11519
- if (ts8.isCallExpression(node) && (node.expression.kind === ts8.SyntaxKind.ImportKeyword || ts8.isIdentifier(node.expression) && node.expression.text === "require")) {
11814
+ if (ts10.isCallExpression(node) && (node.expression.kind === ts10.SyntaxKind.ImportKeyword || ts10.isIdentifier(node.expression) && node.expression.text === "require")) {
11520
11815
  const argument = node.arguments[0];
11521
- if (!argument || !ts8.isStringLiteral(argument) && !ts8.isNoSubstitutionTemplateLiteral(argument)) {
11816
+ if (!argument || !ts10.isStringLiteral(argument) && !ts10.isNoSubstitutionTemplateLiteral(argument)) {
11522
11817
  throw new Error("Computed module loading is not supported in independent delivery bundles.");
11523
11818
  }
11524
11819
  }
11525
- ts8.forEachChild(node, visit);
11820
+ ts10.forEachChild(node, visit);
11526
11821
  }
11527
11822
  visit(source);
11528
11823
  }
@@ -11611,7 +11906,7 @@ async function buildDeliveryProject(options, delivery) {
11611
11906
  const settings = parseDeliveryOptions(delivery);
11612
11907
  if (typeof Bun === "undefined")
11613
11908
  throw new Error("Independent delivery builds require Bun.");
11614
- const configPath = ts9.findConfigFile(resolve11(options.rootDir), ts9.sys.fileExists);
11909
+ const configPath = ts11.findConfigFile(resolve11(options.rootDir), ts11.sys.fileExists);
11615
11910
  if (!configPath)
11616
11911
  throw new Error("Independent delivery builds require a project tsconfig.json.");
11617
11912
  const lexicalProject = dirname8(configPath);
@@ -11627,8 +11922,8 @@ async function buildDeliveryProject(options, delivery) {
11627
11922
  if (inside(generatedRoot, sourceRoot))
11628
11923
  throw new Error("Output must not contain the application source root.");
11629
11924
  const configInputs = new Map;
11630
- const parsedConfig = ts9.getParsedCommandLineOfConfigFile(await realpath3(configPath), {}, {
11631
- ...ts9.sys,
11925
+ const parsedConfig = ts11.getParsedCommandLineOfConfigFile(await realpath3(configPath), {}, {
11926
+ ...ts11.sys,
11632
11927
  readFile(path) {
11633
11928
  const contents = readFileSync3(path, "utf8");
11634
11929
  configInputs.set(resolve11(path), digest(contents));
@@ -11714,7 +12009,7 @@ async function buildDeliveryProject(options, delivery) {
11714
12009
  for (const [name, contents] of Object.entries(generated))
11715
12010
  await writeArtifact(stage, `generated/${name}`, contents);
11716
12011
  {
11717
- const program = ts9.createProgram({
12012
+ const program = ts11.createProgram({
11718
12013
  rootNames: [
11719
12014
  ...parsedConfig.fileNames.filter((path) => !inside(generatedRoot, path)),
11720
12015
  ...Object.keys(generated).map((name) => join8(stage, "generated", name))
@@ -11722,12 +12017,12 @@ async function buildDeliveryProject(options, delivery) {
11722
12017
  options: { ...parsedConfig.options, rootDir: project },
11723
12018
  ...parsedConfig.projectReferences ? { projectReferences: parsedConfig.projectReferences } : {}
11724
12019
  });
11725
- const diagnostics = ts9.getPreEmitDiagnostics(program);
11726
- if (diagnostics.some((item) => item.category === ts9.DiagnosticCategory.Error)) {
11727
- return failed(diagnostics.filter((item) => item.category === ts9.DiagnosticCategory.Error).map((item) => ({
12020
+ const diagnostics = ts11.getPreEmitDiagnostics(program);
12021
+ if (diagnostics.some((item) => item.category === ts11.DiagnosticCategory.Error)) {
12022
+ return failed(diagnostics.filter((item) => item.category === ts11.DiagnosticCategory.Error).map((item) => ({
11728
12023
  severity: "error",
11729
12024
  code: "delivery-generated-type-error",
11730
- message: ts9.flattenDiagnosticMessageText(item.messageText, `
12025
+ message: ts11.flattenDiagnosticMessageText(item.messageText, `
11731
12026
  `),
11732
12027
  ...item.file ? { file: item.file.fileName } : {}
11733
12028
  })));
@@ -11859,7 +12154,7 @@ async function buildDeliveryProject(options, delivery) {
11859
12154
  // src/migrations.ts
11860
12155
  import { rename as rename5, readFile as readFile9, writeFile as writeFile4, rm as rm3 } from "node:fs/promises";
11861
12156
  import { relative as relative11, resolve as resolve13 } from "node:path";
11862
- import * as ts10 from "@typescript/typescript6";
12157
+ import * as ts12 from "@typescript/typescript6";
11863
12158
 
11864
12159
  // src/migration-policy.ts
11865
12160
  import { readFile as readFile8 } from "node:fs/promises";
@@ -11880,7 +12175,7 @@ function migrationDependencies() {
11880
12175
  return {
11881
12176
  "@supacloud/app": "0.14.0",
11882
12177
  "@supacloud/compiler": compilerVersion(),
11883
- "@supacloud/elysia": "0.16.0",
12178
+ "@supacloud/elysia": "0.17.0",
11884
12179
  elysia: "1.4.30",
11885
12180
  typescript: "7.0.2"
11886
12181
  };
@@ -11903,29 +12198,29 @@ async function checkMigrationDependencies(rootDir) {
11903
12198
  // src/migrations.ts
11904
12199
  var ROUTE_DECORATORS2 = new Set(["Get", "Post", "Put", "Patch", "Delete", "Head", "Options"]);
11905
12200
  var MIGRATION_COMPILER_OPTIONS = {
11906
- target: ts10.ScriptTarget.ES2022,
11907
- module: ts10.ModuleKind.ESNext,
11908
- moduleResolution: ts10.ModuleResolutionKind.Bundler,
12201
+ target: ts12.ScriptTarget.ES2022,
12202
+ module: ts12.ModuleKind.ESNext,
12203
+ moduleResolution: ts12.ModuleResolutionKind.Bundler,
11909
12204
  noEmit: true,
11910
12205
  skipLibCheck: true
11911
12206
  };
11912
12207
  function migrationCompilerOptions(rootDir) {
11913
12208
  if (!rootDir)
11914
12209
  return MIGRATION_COMPILER_OPTIONS;
11915
- const configPath = ts10.findConfigFile(rootDir, ts10.sys.fileExists);
12210
+ const configPath = ts12.findConfigFile(rootDir, ts12.sys.fileExists);
11916
12211
  if (!configPath)
11917
12212
  return MIGRATION_COMPILER_OPTIONS;
11918
12213
  const configHost = {
11919
- ...ts10.sys,
12214
+ ...ts12.sys,
11920
12215
  onUnRecoverableConfigFileDiagnostic: (_diagnostic) => {}
11921
12216
  };
11922
- const parsed = ts10.getParsedCommandLineOfConfigFile(configPath, {}, configHost);
12217
+ const parsed = ts12.getParsedCommandLineOfConfigFile(configPath, {}, configHost);
11923
12218
  if (!parsed || parsed.errors.length > 0)
11924
12219
  return MIGRATION_COMPILER_OPTIONS;
11925
12220
  return { ...parsed.options, noEmit: true, skipLibCheck: true };
11926
12221
  }
11927
12222
  function propertyName2(property) {
11928
- if (ts10.isIdentifier(property) || ts10.isStringLiteral(property) || ts10.isNumericLiteral(property))
12223
+ if (ts12.isIdentifier(property) || ts12.isStringLiteral(property) || ts12.isNumericLiteral(property))
11929
12224
  return property.text;
11930
12225
  return;
11931
12226
  }
@@ -11935,7 +12230,7 @@ function lineOf2(sourceFile, node) {
11935
12230
  function resolveSymbol(symbol, checker) {
11936
12231
  if (!symbol)
11937
12232
  return;
11938
- for (let guard = 0;guard < 4 && (symbol.flags & ts10.SymbolFlags.Alias) !== 0; guard += 1) {
12233
+ for (let guard = 0;guard < 4 && (symbol.flags & ts12.SymbolFlags.Alias) !== 0; guard += 1) {
11939
12234
  const aliased = checker.getAliasedSymbol(symbol);
11940
12235
  if (aliased === symbol)
11941
12236
  break;
@@ -11944,12 +12239,12 @@ function resolveSymbol(symbol, checker) {
11944
12239
  return symbol;
11945
12240
  }
11946
12241
  function symbolForExpression(expression, checker) {
11947
- const location = ts10.isIdentifier(expression) ? expression : ts10.isPropertyAccessExpression(expression) ? expression.name : ts10.isElementAccessExpression(expression) && expression.argumentExpression && ts10.isStringLiteral(expression.argumentExpression) ? expression : undefined;
12242
+ const location = ts12.isIdentifier(expression) ? expression : ts12.isPropertyAccessExpression(expression) ? expression.name : ts12.isElementAccessExpression(expression) && expression.argumentExpression && ts12.isStringLiteral(expression.argumentExpression) ? expression : undefined;
11948
12243
  return location ? resolveSymbol(checker.getSymbolAtLocation(location), checker) : undefined;
11949
12244
  }
11950
12245
  function unwrapExpression(expression) {
11951
12246
  let current = expression;
11952
- while (ts10.isAsExpression(current) || ts10.isSatisfiesExpression(current) || ts10.isParenthesizedExpression(current) || ts10.isTypeAssertionExpression(current)) {
12247
+ while (ts12.isAsExpression(current) || ts12.isSatisfiesExpression(current) || ts12.isParenthesizedExpression(current) || ts12.isTypeAssertionExpression(current)) {
11953
12248
  current = current.expression;
11954
12249
  }
11955
12250
  return current;
@@ -11962,7 +12257,7 @@ function isDefineRouteContractCall(node, checker) {
11962
12257
  }
11963
12258
  function isRouteDecoratorCall(node, checker) {
11964
12259
  const name = node.expression.getText(node.getSourceFile());
11965
- if (ts10.isIdentifier(node.expression) && ROUTE_DECORATORS2.has(node.expression.text))
12260
+ if (ts12.isIdentifier(node.expression) && ROUTE_DECORATORS2.has(node.expression.text))
11966
12261
  return true;
11967
12262
  if (ROUTE_DECORATORS2.has(name))
11968
12263
  return true;
@@ -11976,14 +12271,14 @@ function resolveStaticObjectLiteral2(input, checker, seen = new Set) {
11976
12271
  if (seen.has(expression))
11977
12272
  return;
11978
12273
  seen.add(expression);
11979
- if (ts10.isObjectLiteralExpression(expression))
12274
+ if (ts12.isObjectLiteralExpression(expression))
11980
12275
  return expression;
11981
- if (ts10.isCallExpression(expression) && isDefineRouteContractCall(expression, checker)) {
12276
+ if (ts12.isCallExpression(expression) && isDefineRouteContractCall(expression, checker)) {
11982
12277
  return resolveStaticObjectLiteral2(expression.arguments[0], checker, seen);
11983
12278
  }
11984
12279
  const symbol = symbolForExpression(expression, checker);
11985
12280
  for (const declaration of symbol?.declarations ?? []) {
11986
- if (ts10.isVariableDeclaration(declaration) && declaration.initializer) {
12281
+ if (ts12.isVariableDeclaration(declaration) && declaration.initializer) {
11987
12282
  const resolved = resolveStaticObjectLiteral2(declaration.initializer, checker, seen);
11988
12283
  if (resolved)
11989
12284
  return resolved;
@@ -11997,7 +12292,7 @@ function displayFile(rootDir, fileName) {
11997
12292
  }
11998
12293
  function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
11999
12294
  const compilerOptions = migrationCompilerOptions(rootDir);
12000
- const host = ts10.createCompilerHost(compilerOptions);
12295
+ const host = ts12.createCompilerHost(compilerOptions);
12001
12296
  const getSourceFile = host.getSourceFile.bind(host);
12002
12297
  const fileExists = host.fileExists.bind(host);
12003
12298
  const readFile = host.readFile.bind(host);
@@ -12006,16 +12301,16 @@ function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
12006
12301
  host.readFile = (fileName) => sourceOverrides.get(resolve13(fileName)) ?? readFile(fileName);
12007
12302
  host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
12008
12303
  const source = sourceOverrides.get(resolve13(fileName));
12009
- return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts10.createSourceFile(fileName, source, languageVersion, true);
12304
+ return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts12.createSourceFile(fileName, source, languageVersion, true);
12010
12305
  };
12011
12306
  host.getCurrentDirectory = () => rootDir ?? currentDirectory();
12012
- return ts10.createProgram(fileNames, compilerOptions, host);
12307
+ return ts12.createProgram(fileNames, compilerOptions, host);
12013
12308
  }
12014
12309
  function routeResponseProperties(object) {
12015
- const responseProperties = object.properties.filter((property) => ts10.isPropertyAssignment(property) && propertyName2(property.name) === "response");
12310
+ const responseProperties = object.properties.filter((property) => ts12.isPropertyAssignment(property) && propertyName2(property.name) === "response");
12016
12311
  return {
12017
12312
  response: responseProperties[0],
12018
- hasResponses: object.properties.some((property) => (ts10.isPropertyAssignment(property) || ts10.isShorthandPropertyAssignment(property)) && propertyName2(property.name) === "responses"),
12313
+ hasResponses: object.properties.some((property) => (ts12.isPropertyAssignment(property) || ts12.isShorthandPropertyAssignment(property)) && propertyName2(property.name) === "responses"),
12019
12314
  duplicateResponse: responseProperties.length > 1
12020
12315
  };
12021
12316
  }
@@ -12035,7 +12330,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
12035
12330
  if (!includedFiles.has(sourcePath))
12036
12331
  continue;
12037
12332
  const visit = (node) => {
12038
- if (ts10.isCallExpression(node) && isRouteDecoratorCall(node, checker)) {
12333
+ if (ts12.isCallExpression(node) && isRouteDecoratorCall(node, checker)) {
12039
12334
  const options = node.arguments[1];
12040
12335
  const object = options && resolveStaticObjectLiteral2(options, checker);
12041
12336
  if (object) {
@@ -12055,7 +12350,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
12055
12350
  }
12056
12351
  }
12057
12352
  }
12058
- ts10.forEachChild(node, visit);
12353
+ ts12.forEachChild(node, visit);
12059
12354
  };
12060
12355
  visit(sourceFile);
12061
12356
  }
@@ -12215,7 +12510,7 @@ async function migrateProject(options) {
12215
12510
  }
12216
12511
  }
12217
12512
  const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
12218
- const files = ts10.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist", "generated"], include).sort();
12513
+ const files = ts12.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist", "generated"], include).sort();
12219
12514
  const results = [];
12220
12515
  const issues = [];
12221
12516
  const pendingWrites = new Map;
@@ -12827,6 +13122,7 @@ Usage:
12827
13122
  supacloud-compiler openapi-diff <base.json> <current.json> [options]
12828
13123
  supacloud-compiler fix <fix.json> [options]
12829
13124
  supacloud-compiler graphql-schema --url <project-url> --key-env <name> [--token-env <name>]
13125
+ supacloud-compiler database-contracts <config.json> [--check]
12830
13126
 
12831
13127
  Commands:
12832
13128
  compile Compile application modules and generate artifacts
@@ -12878,6 +13174,18 @@ async function run() {
12878
13174
  process.exit(0);
12879
13175
  }
12880
13176
  const command = args[0];
13177
+ if (command === "database-contracts") {
13178
+ const path = args[1];
13179
+ if (!path || path.startsWith("-") || args.slice(2).some((arg) => arg !== "--check")) {
13180
+ throw new Error("database-contracts requires <config.json> and optional --check");
13181
+ }
13182
+ await Promise.resolve().then(() => init_database_contracts());
13183
+ const result = await runDatabaseContractsFile(path, args.includes("--check"));
13184
+ console.log(JSON.stringify(result, null, 2));
13185
+ if (args.includes("--check") && !result.upToDate)
13186
+ process.exitCode = 1;
13187
+ return;
13188
+ }
12881
13189
  if (!command || !["compile", "check", "dev", "graph", "explain", "context", "doctor", "migrate", "fix", "graphql-schema", "plan", "build-delivery", "openapi-export", "openapi-diff"].includes(command)) {
12882
13190
  console.error(`Error: unknown command "${command}"`);
12883
13191
  printUsage();
@@ -13049,7 +13357,7 @@ async function run() {
13049
13357
  const currentPath = openApiDiffPaths[1];
13050
13358
  if (!basePath || !currentPath)
13051
13359
  throw new Error("openapi-diff requires two JSON file paths");
13052
- const result = diffOpenApiDocuments(await readOpenApiJson(resolve16(process.cwd(), basePath)), await readOpenApiJson(resolve16(process.cwd(), currentPath)));
13360
+ const result = diffOpenApiDocuments(await readOpenApiJson(resolve17(process.cwd(), basePath)), await readOpenApiJson(resolve17(process.cwd(), currentPath)));
13053
13361
  console.log(json ? JSON.stringify(result, null, 2) : formatOpenApiDiff(result));
13054
13362
  if (!result.ok)
13055
13363
  process.exitCode = 1;
@@ -13064,8 +13372,8 @@ async function run() {
13064
13372
  if (!modulePath || !outputPath)
13065
13373
  throw new Error("openapi-export requires an OpenAPI module and output path");
13066
13374
  const result = await exportGeneratedOpenApiJson({
13067
- modulePath: resolve16(process.cwd(), modulePath),
13068
- outputPath: resolve16(process.cwd(), outputPath),
13375
+ modulePath: resolve17(process.cwd(), modulePath),
13376
+ outputPath: resolve17(process.cwd(), outputPath),
13069
13377
  ...openApiExportSpace === undefined ? {} : { space: openApiExportSpace }
13070
13378
  });
13071
13379
  console.log(json ? JSON.stringify({ ok: true, ...result }, null, 2) : result.written ? `OpenAPI JSON written: ${result.path}` : `OpenAPI JSON matches: ${result.path}`);
@@ -13073,7 +13381,7 @@ async function run() {
13073
13381
  }
13074
13382
  if (command === "migrate") {
13075
13383
  const result = await migrateProject({
13076
- rootDir: rootDir ? resolve16(process.cwd(), rootDir) : process.cwd(),
13384
+ rootDir: rootDir ? resolve17(process.cwd(), rootDir) : process.cwd(),
13077
13385
  write: !dryRun,
13078
13386
  ...fromVersion === undefined ? {} : { fromVersion },
13079
13387
  ...toVersion === undefined ? {} : { toVersion }
@@ -13101,8 +13409,8 @@ async function run() {
13101
13409
  if (checkSchema && command !== "graphql-schema")
13102
13410
  throw new Error("--check is only supported by graphql-schema");
13103
13411
  const defaults = resolveSupacloudConfig(loadedConfig, process.cwd());
13104
- const resolvedRoot = rootDir ? resolve16(process.cwd(), rootDir) : defaults.rootDir;
13105
- const resolvedOut = outDir ? resolve16(process.cwd(), outDir) : defaults.outDir;
13412
+ const resolvedRoot = rootDir ? resolve17(process.cwd(), rootDir) : defaults.rootDir;
13413
+ const resolvedOut = outDir ? resolve17(process.cwd(), outDir) : defaults.outDir;
13106
13414
  const configured = compileOptionsFromConfig({
13107
13415
  ...loadedConfig,
13108
13416
  root: resolvedRoot,
@@ -13121,7 +13429,7 @@ async function run() {
13121
13429
  let delivery = loadedConfig.delivery;
13122
13430
  if (deliveryPath !== undefined) {
13123
13431
  try {
13124
- delivery = JSON.parse(await readFile12(resolve16(process.cwd(), deliveryPath), "utf8"));
13432
+ delivery = JSON.parse(await readFile13(resolve17(process.cwd(), deliveryPath), "utf8"));
13125
13433
  } catch {
13126
13434
  throw new DeliveryConfigurationError;
13127
13435
  }
@@ -13168,7 +13476,7 @@ ${item.suggestion ?? ""}`).join(`
13168
13476
  } else if (command === "fix") {
13169
13477
  if (!query)
13170
13478
  throw new Error("fix requires a JSON file containing one DiagnosticFix");
13171
- const fix = JSON.parse(await readFile12(resolve16(process.cwd(), query), "utf8"));
13479
+ const fix = JSON.parse(await readFile13(resolve17(process.cwd(), query), "utf8"));
13172
13480
  const result = await applyDiagnosticFix(fix, { rootDir: resolvedRoot, dryRun });
13173
13481
  console.log(JSON.stringify({ ok: true, ...result }, null, 2));
13174
13482
  } else if (command === "compile") {