@supacloud/compiler 0.21.0 → 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/README.md +39 -1
- package/dist/cli.js +677 -363
- package/dist/database-contracts.d.ts +48 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +653 -346
- package/dist/migration-policy.d.ts +1 -1
- package/dist/sql-safety.d.ts +17 -0
- package/dist/static-di.d.ts +4 -0
- package/dist/type-safety.d.ts +8 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -354,7 +354,7 @@ class ModuleGenerator {
|
|
|
354
354
|
this.imports = imports;
|
|
355
355
|
this.pascal = pascalName(module.name);
|
|
356
356
|
if (module.providers.some((provider) => (provider.functionalInjects?.length ?? 0) > 0) || module.controllers.some((controller) => (controller.functionalInjects?.length ?? 0) > 0)) {
|
|
357
|
-
|
|
357
|
+
throw new Error("SC2012: Compiled DI requires constructor injection; property inject() is not supported.");
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
360
|
renderFactories() {
|
|
@@ -388,6 +388,7 @@ class ModuleGenerator {
|
|
|
388
388
|
lines.push(` jobs: ${this.renderJobs()},`);
|
|
389
389
|
if (this.module.aspects && this.module.aspects.length > 0) {
|
|
390
390
|
lines.push(` aspects: ${this.renderAspects(this.module.aspects)},`);
|
|
391
|
+
lines.push(` aspectPipeline: ${this.renderAspectPipeline(this.module.aspects)},`);
|
|
391
392
|
}
|
|
392
393
|
lines.push(`}`);
|
|
393
394
|
return lines.join(`
|
|
@@ -464,6 +465,7 @@ class ModuleGenerator {
|
|
|
464
465
|
}
|
|
465
466
|
if (route.aspects && route.aspects.length > 0) {
|
|
466
467
|
fields.push(`aspects: ${this.renderAspects(route.aspects)}`);
|
|
468
|
+
fields.push(`aspectPipeline: ${this.renderAspectPipeline(route.aspects)}`);
|
|
467
469
|
}
|
|
468
470
|
const invokerArgs = (route.handlerParams ?? []).map((hp) => {
|
|
469
471
|
if (hp.kind === "param") {
|
|
@@ -544,7 +546,7 @@ ${indent(item, 2)}`).join(",")}
|
|
|
544
546
|
`idempotency: ${JSON.stringify(command.idempotency)}`,
|
|
545
547
|
...command.rpc ? [`rpc: ${JSON.stringify(command.rpc)}`] : [],
|
|
546
548
|
...command.standalone ? ["standalone: true"] : [],
|
|
547
|
-
...command.aspects && command.aspects.length > 0 ? [`aspects: ${this.renderAspects(command.aspects)}`] : []
|
|
549
|
+
...command.aspects && command.aspects.length > 0 ? [`aspects: ${this.renderAspects(command.aspects)}`, `aspectPipeline: ${this.renderAspectPipeline(command.aspects)}`] : []
|
|
548
550
|
];
|
|
549
551
|
return `{ ${fields.join(", ")} }`;
|
|
550
552
|
}).join(", ")}]`;
|
|
@@ -577,6 +579,7 @@ ${indent(item, 2)}`).join(",")}
|
|
|
577
579
|
fields.push(`idempotency: ${JSON.stringify(job.idempotency)}`);
|
|
578
580
|
if (job.aspects && job.aspects.length > 0) {
|
|
579
581
|
fields.push(`aspects: ${this.renderAspects(job.aspects)}`);
|
|
582
|
+
fields.push(`aspectPipeline: ${this.renderAspectPipeline(job.aspects)}`);
|
|
580
583
|
}
|
|
581
584
|
return `{ ${fields.join(", ")}, }`;
|
|
582
585
|
}).join(", ")}]`;
|
|
@@ -584,6 +587,24 @@ ${indent(item, 2)}`).join(",")}
|
|
|
584
587
|
renderAspects(aspects) {
|
|
585
588
|
return `[${aspects.map((aspect) => this.imports.add(aspect.name, aspect.importPath, aspect.importModule)).join(", ")}]`;
|
|
586
589
|
}
|
|
590
|
+
renderAspectPipeline(aspects) {
|
|
591
|
+
const lines = [
|
|
592
|
+
`async (context, next, observe) => {`,
|
|
593
|
+
` const state = { active: true };`,
|
|
594
|
+
` const step${aspects.length} = compiledAspectNext(next, state);`
|
|
595
|
+
];
|
|
596
|
+
for (let index = aspects.length - 1;index >= 0; index--) {
|
|
597
|
+
const aspect = aspects[index];
|
|
598
|
+
if (!aspect)
|
|
599
|
+
continue;
|
|
600
|
+
const name = this.imports.add(aspect.name, aspect.importPath, aspect.importModule);
|
|
601
|
+
const stage = JSON.stringify(`aspect[${index}]:${aspect.name}`);
|
|
602
|
+
lines.push(` const step${index} = compiledAspectNext(() => observeCompiledAspect(observe, ${stage}, () => ${name}(context, step${index + 1})), state);`);
|
|
603
|
+
}
|
|
604
|
+
lines.push(` try { return await step0(); } finally { state.active = false; }`, `}`);
|
|
605
|
+
return lines.join(`
|
|
606
|
+
`);
|
|
607
|
+
}
|
|
587
608
|
renderServicesFactory() {
|
|
588
609
|
return [
|
|
589
610
|
`function create${this.pascal}Services(`,
|
|
@@ -698,7 +719,7 @@ ${indent(item, 2)}`).join(",")}
|
|
|
698
719
|
const args = provider.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(provider, dep), `ConstructorParameters<typeof ${useClass}>[${index}]`)).join(", ");
|
|
699
720
|
const local = this.localVar(isMulti ? provider.useClass ?? `${provider.token}Item` : provider.token, kind);
|
|
700
721
|
return {
|
|
701
|
-
constLine: `const ${local} = ${
|
|
722
|
+
constLine: `const ${local} = new ${useClass}(${args});`,
|
|
702
723
|
key,
|
|
703
724
|
expr: local
|
|
704
725
|
};
|
|
@@ -734,32 +755,11 @@ ${indent(item, 2)}`).join(",")}
|
|
|
734
755
|
const key = camelName(controller.className);
|
|
735
756
|
const local = this.localVar(controller.className, kind);
|
|
736
757
|
return {
|
|
737
|
-
constLine: `const ${local} = ${
|
|
758
|
+
constLine: `const ${local} = new ${className}(${args});`,
|
|
738
759
|
key,
|
|
739
760
|
expr: local
|
|
740
761
|
};
|
|
741
762
|
}
|
|
742
|
-
instantiate(className, args, kind, functionalInjects) {
|
|
743
|
-
if (!functionalInjects || functionalInjects.length === 0) {
|
|
744
|
-
return `new ${className}(${args})`;
|
|
745
|
-
}
|
|
746
|
-
const clauses = functionalInjects.map((entry) => {
|
|
747
|
-
const token = this.imports.add(entry.expression, entry.importPath, entry.importModule);
|
|
748
|
-
const value = this.depExpr(entry.token, kind, entry);
|
|
749
|
-
return `if (token === ${token}) return ${value} as T;`;
|
|
750
|
-
});
|
|
751
|
-
const missing = `if (options?.optional) return undefined; throw new Error("Static inject token not available: " + String(token));`;
|
|
752
|
-
const injector = [
|
|
753
|
-
`{`,
|
|
754
|
-
`get<T>(token: unknown, options?: { optional?: boolean; self?: boolean; skipSelf?: boolean; host?: boolean }): T | undefined {`,
|
|
755
|
-
...clauses,
|
|
756
|
-
missing,
|
|
757
|
-
`},`,
|
|
758
|
-
`}`
|
|
759
|
-
].join(`
|
|
760
|
-
`);
|
|
761
|
-
return `runInInjectionContext(${injector}, () => new ${className}(${args}))`;
|
|
762
|
-
}
|
|
763
763
|
localVar(token, kind) {
|
|
764
764
|
const locals = this.locals[kind];
|
|
765
765
|
const existing = locals.get(token);
|
|
@@ -1932,6 +1932,7 @@ var HEADER = "// GENERATED BY @supacloud/compiler — do not edit", INTERFACES =
|
|
|
1932
1932
|
title?: string;
|
|
1933
1933
|
data?: Record<string, unknown>;
|
|
1934
1934
|
aspects?: CompiledAspect[];
|
|
1935
|
+
aspectPipeline?: CompiledAspectPipeline;
|
|
1935
1936
|
invoker?: (
|
|
1936
1937
|
controller: unknown,
|
|
1937
1938
|
request: {
|
|
@@ -1955,6 +1956,7 @@ export interface CompiledCommand {
|
|
|
1955
1956
|
idempotency: "required" | "none";
|
|
1956
1957
|
standalone?: boolean;
|
|
1957
1958
|
aspects?: CompiledAspect[];
|
|
1959
|
+
aspectPipeline?: CompiledAspectPipeline;
|
|
1958
1960
|
}
|
|
1959
1961
|
|
|
1960
1962
|
export interface CompiledJob {
|
|
@@ -1969,6 +1971,7 @@ export interface CompiledJob {
|
|
|
1969
1971
|
maxAttempts?: number;
|
|
1970
1972
|
idempotency?: "required" | "none";
|
|
1971
1973
|
aspects?: CompiledAspect[];
|
|
1974
|
+
aspectPipeline?: CompiledAspectPipeline;
|
|
1972
1975
|
}
|
|
1973
1976
|
|
|
1974
1977
|
export interface CompiledAspectContext {
|
|
@@ -2016,7 +2019,24 @@ export interface CompiledModule {
|
|
|
2016
2019
|
commands: CompiledCommand[];
|
|
2017
2020
|
jobs: CompiledJob[];
|
|
2018
2021
|
aspects?: CompiledAspect[];
|
|
2019
|
-
|
|
2022
|
+
aspectPipeline?: CompiledAspectPipeline;
|
|
2023
|
+
}`, TYPE_GUARDS = `type CompiledAspectObserver = (stage: string, run: () => unknown | Promise<unknown>) => unknown | Promise<unknown>;
|
|
2024
|
+
type CompiledAspectPipeline = (context: CompiledAspectContext, next: () => unknown | Promise<unknown>, observe?: CompiledAspectObserver) => unknown | Promise<unknown>;
|
|
2025
|
+
|
|
2026
|
+
function compiledAspectNext(next: () => unknown | Promise<unknown>, state: { active: boolean }): () => Promise<unknown> {
|
|
2027
|
+
let called = false;
|
|
2028
|
+
return async () => {
|
|
2029
|
+
if (!state.active) throw new Error("Aspect continuation is closed");
|
|
2030
|
+
if (called) throw new Error("Aspect continuation called multiple times");
|
|
2031
|
+
called = true;
|
|
2032
|
+
return await next();
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
function observeCompiledAspect(observe: CompiledAspectObserver | undefined, stage: string, run: () => unknown | Promise<unknown>): unknown | Promise<unknown> {
|
|
2036
|
+
return observe ? observe(stage, run) : run();
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
2020
2040
|
return typeof value === "object" && value !== null;
|
|
2021
2041
|
}
|
|
2022
2042
|
|
|
@@ -2198,7 +2218,7 @@ var init_graphql_options = __esm(() => {
|
|
|
2198
2218
|
|
|
2199
2219
|
// src/graphql-inputs.ts
|
|
2200
2220
|
import { resolve as resolve3 } from "node:path";
|
|
2201
|
-
import * as
|
|
2221
|
+
import * as ts7 from "@typescript/typescript6";
|
|
2202
2222
|
function graphqlInputPaths(options) {
|
|
2203
2223
|
if (!options.graphql)
|
|
2204
2224
|
return [];
|
|
@@ -2209,7 +2229,7 @@ function graphqlInputPaths(options) {
|
|
|
2209
2229
|
}
|
|
2210
2230
|
const root = resolve3(options.rootDir);
|
|
2211
2231
|
const schema = resolve3(root, options.graphql.schema);
|
|
2212
|
-
const documents =
|
|
2232
|
+
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);
|
|
2213
2233
|
return [schema, ...[...new Set(documents)].sort()];
|
|
2214
2234
|
}
|
|
2215
2235
|
var init_graphql_inputs = __esm(() => {
|
|
@@ -2217,7 +2237,7 @@ var init_graphql_inputs = __esm(() => {
|
|
|
2217
2237
|
});
|
|
2218
2238
|
|
|
2219
2239
|
// src/graphql-runtime.ts
|
|
2220
|
-
import * as
|
|
2240
|
+
import * as ts8 from "@typescript/typescript6";
|
|
2221
2241
|
import { resolve as resolve4 } from "node:path";
|
|
2222
2242
|
function renderGraphqlValidators(source, operationNames) {
|
|
2223
2243
|
const fileName = resolve4("/__supacloud_graphql__/contracts.ts");
|
|
@@ -2229,18 +2249,18 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
2229
2249
|
noPropertyAccessFromIndexSignature: true,
|
|
2230
2250
|
noFallthroughCasesInSwitch: true,
|
|
2231
2251
|
skipLibCheck: false,
|
|
2232
|
-
target:
|
|
2252
|
+
target: ts8.ScriptTarget.ES2022,
|
|
2233
2253
|
lib: ["lib.es2022.d.ts"],
|
|
2234
2254
|
types: [],
|
|
2235
2255
|
noEmit: true
|
|
2236
2256
|
};
|
|
2237
|
-
const host =
|
|
2257
|
+
const host = ts8.createCompilerHost(options);
|
|
2238
2258
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
2239
|
-
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => path === fileName ?
|
|
2240
|
-
const program =
|
|
2241
|
-
const diagnostics =
|
|
2259
|
+
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => path === fileName ? ts8.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
|
|
2260
|
+
const program = ts8.createProgram([fileName], options, host);
|
|
2261
|
+
const diagnostics = ts8.getPreEmitDiagnostics(program);
|
|
2242
2262
|
if (diagnostics.length) {
|
|
2243
|
-
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) =>
|
|
2263
|
+
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts8.flattenDiagnosticMessageText(item.messageText, `
|
|
2244
2264
|
`)).join("; ")}`);
|
|
2245
2265
|
}
|
|
2246
2266
|
const checker = program.getTypeChecker();
|
|
@@ -2270,25 +2290,25 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
2270
2290
|
return name;
|
|
2271
2291
|
}
|
|
2272
2292
|
function expression(type) {
|
|
2273
|
-
if (type.flags &
|
|
2293
|
+
if (type.flags & ts8.TypeFlags.Any)
|
|
2274
2294
|
return unsupported(type);
|
|
2275
|
-
if (type.flags &
|
|
2295
|
+
if (type.flags & ts8.TypeFlags.Unknown)
|
|
2276
2296
|
return "true";
|
|
2277
|
-
if (type.flags &
|
|
2297
|
+
if (type.flags & ts8.TypeFlags.Never)
|
|
2278
2298
|
return "false";
|
|
2279
|
-
if (type.flags &
|
|
2299
|
+
if (type.flags & ts8.TypeFlags.Null)
|
|
2280
2300
|
return "value === null";
|
|
2281
|
-
if (type.flags &
|
|
2301
|
+
if (type.flags & ts8.TypeFlags.Undefined)
|
|
2282
2302
|
return "value === undefined";
|
|
2283
2303
|
if (type.isStringLiteral() || type.isNumberLiteral())
|
|
2284
2304
|
return `value === ${JSON.stringify(type.value)}`;
|
|
2285
|
-
if (type.flags &
|
|
2305
|
+
if (type.flags & ts8.TypeFlags.BooleanLiteral)
|
|
2286
2306
|
return `value === ${checker.typeToString(type)}`;
|
|
2287
|
-
if (type.flags &
|
|
2307
|
+
if (type.flags & ts8.TypeFlags.String)
|
|
2288
2308
|
return 'typeof value === "string"';
|
|
2289
|
-
if (type.flags &
|
|
2309
|
+
if (type.flags & ts8.TypeFlags.Number)
|
|
2290
2310
|
return 'typeof value === "number" && Number.isFinite(value)';
|
|
2291
|
-
if (type.flags &
|
|
2311
|
+
if (type.flags & ts8.TypeFlags.Boolean)
|
|
2292
2312
|
return 'typeof value === "boolean"';
|
|
2293
2313
|
if (type.isUnion())
|
|
2294
2314
|
return type.types.map((part) => `${reference(part)}(value)`).join(" || ");
|
|
@@ -2297,16 +2317,16 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
2297
2317
|
if (checker.isTupleType(type))
|
|
2298
2318
|
return unsupported(type);
|
|
2299
2319
|
if (checker.isArrayType(type)) {
|
|
2300
|
-
const item = checker.getIndexTypeOfType(type,
|
|
2320
|
+
const item = checker.getIndexTypeOfType(type, ts8.IndexKind.Number);
|
|
2301
2321
|
if (!item)
|
|
2302
2322
|
return unsupported(type);
|
|
2303
2323
|
return `isGraphqlArray(value) && Array.from(value).every(${reference(item)})`;
|
|
2304
2324
|
}
|
|
2305
|
-
if (type.flags &
|
|
2325
|
+
if (type.flags & ts8.TypeFlags.Object) {
|
|
2306
2326
|
if (type.getCallSignatures().length || type.getConstructSignatures().length)
|
|
2307
2327
|
return unsupported(type);
|
|
2308
2328
|
const indexes = checker.getIndexInfosOfType(type);
|
|
2309
|
-
if (indexes.some((index) => !(index.keyType.flags &
|
|
2329
|
+
if (indexes.some((index) => !(index.keyType.flags & ts8.TypeFlags.String)))
|
|
2310
2330
|
return unsupported(type);
|
|
2311
2331
|
const properties = checker.getPropertiesOfType(type).map((property) => {
|
|
2312
2332
|
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
@@ -2315,7 +2335,7 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
2315
2335
|
const check = reference(checker.getTypeOfSymbolAtLocation(property, declaration));
|
|
2316
2336
|
const key = JSON.stringify(property.name);
|
|
2317
2337
|
const present = `Object.prototype.hasOwnProperty.call(value, ${key})`;
|
|
2318
|
-
return property.flags &
|
|
2338
|
+
return property.flags & ts8.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
|
|
2319
2339
|
});
|
|
2320
2340
|
const indexedValues = indexes.map((index) => `Object.values(value).every(${reference(index.type)})`);
|
|
2321
2341
|
return ["isGraphqlRecord(value)", ...properties, ...indexedValues].join(" && ");
|
|
@@ -2642,10 +2662,155 @@ var init_graphql_schema = __esm(() => {
|
|
|
2642
2662
|
init_graphql_options();
|
|
2643
2663
|
});
|
|
2644
2664
|
|
|
2665
|
+
// src/database-contracts.ts
|
|
2666
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
2667
|
+
import { mkdir as mkdir6, readFile as readFile12 } from "node:fs/promises";
|
|
2668
|
+
import { dirname as dirname11, relative as relative12, resolve as resolve16 } from "node:path";
|
|
2669
|
+
import * as ts13 from "@typescript/typescript6";
|
|
2670
|
+
function hash2(value) {
|
|
2671
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
2672
|
+
}
|
|
2673
|
+
function importPath(out, path) {
|
|
2674
|
+
const value = relative12(out, path).replaceAll("\\", "/").replace(/\.(?:d\.)?[cm]?ts$/, "");
|
|
2675
|
+
return value.startsWith(".") ? value : `./${value}`;
|
|
2676
|
+
}
|
|
2677
|
+
function parseDatabaseContractsOptions(value, directory) {
|
|
2678
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
2679
|
+
throw new TypeError("Expected database contracts configuration");
|
|
2680
|
+
const allowed = ["rootDir", "outDir", "postgrestTypes", "drizzleSchema", "role", "graphql", "migrations"];
|
|
2681
|
+
if (Object.keys(value).some((name) => !allowed.includes(name)))
|
|
2682
|
+
throw new TypeError("Unknown database contracts option");
|
|
2683
|
+
const field = (name) => {
|
|
2684
|
+
const result = Reflect.get(value, name);
|
|
2685
|
+
if (typeof result !== "string" || !result.trim())
|
|
2686
|
+
throw new TypeError(`Missing database contracts ${name}`);
|
|
2687
|
+
return result;
|
|
2688
|
+
};
|
|
2689
|
+
const graphql = Reflect.get(value, "graphql");
|
|
2690
|
+
assertGraphqlOptions(graphql);
|
|
2691
|
+
const migrations = Reflect.get(value, "migrations");
|
|
2692
|
+
if (!Array.isArray(migrations) || !migrations.every((entry) => typeof entry === "string" && entry.endsWith(".sql"))) {
|
|
2693
|
+
throw new TypeError("migrations must be an ordered list of SQL files");
|
|
2694
|
+
}
|
|
2695
|
+
return {
|
|
2696
|
+
rootDir: resolve16(directory, field("rootDir")),
|
|
2697
|
+
outDir: resolve16(directory, field("outDir")),
|
|
2698
|
+
postgrestTypes: resolve16(directory, field("postgrestTypes")),
|
|
2699
|
+
drizzleSchema: resolve16(directory, field("drizzleSchema")),
|
|
2700
|
+
role: field("role"),
|
|
2701
|
+
graphql: { ...graphql, schema: resolve16(directory, graphql.schema) },
|
|
2702
|
+
migrations: migrations.map((file) => resolve16(directory, file))
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
async function generateDatabaseContracts(options, check = false) {
|
|
2706
|
+
const rootDir = resolve16(options.rootDir), outDir = resolve16(options.outDir);
|
|
2707
|
+
const postgrestTypes = resolve16(rootDir, options.postgrestTypes), drizzleSchema = resolve16(rootDir, options.drizzleSchema);
|
|
2708
|
+
const snapshot = await readFile12(postgrestTypes, "utf8");
|
|
2709
|
+
const syntax = ts13.createSourceFile(postgrestTypes, snapshot, ts13.ScriptTarget.Latest, true);
|
|
2710
|
+
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));
|
|
2711
|
+
if (!database)
|
|
2712
|
+
throw new Error("PostgREST snapshot must export Database from the official type generator");
|
|
2713
|
+
const program = ts13.createProgram([postgrestTypes], {
|
|
2714
|
+
strict: true,
|
|
2715
|
+
noEmit: true,
|
|
2716
|
+
skipLibCheck: true,
|
|
2717
|
+
types: [],
|
|
2718
|
+
target: ts13.ScriptTarget.ES2022,
|
|
2719
|
+
module: ts13.ModuleKind.ESNext,
|
|
2720
|
+
moduleResolution: ts13.ModuleResolutionKind.Bundler
|
|
2721
|
+
});
|
|
2722
|
+
if (ts13.getPreEmitDiagnostics(program).length)
|
|
2723
|
+
throw new Error("PostgREST snapshot has TypeScript errors");
|
|
2724
|
+
const artifacts = await renderGraphql({
|
|
2725
|
+
rootDir,
|
|
2726
|
+
outDir,
|
|
2727
|
+
graphql: options.graphql
|
|
2728
|
+
});
|
|
2729
|
+
if (artifacts.diagnostics.some((item) => item.severity === "error")) {
|
|
2730
|
+
throw new Error(artifacts.diagnostics.map((item) => item.message).join(`
|
|
2731
|
+
`));
|
|
2732
|
+
}
|
|
2733
|
+
const inputs = {};
|
|
2734
|
+
const addInput = async (path) => {
|
|
2735
|
+
const absolute = resolve16(rootDir, path);
|
|
2736
|
+
inputs[relative12(rootDir, absolute).replaceAll("\\", "/")] = hash2(await readFile12(absolute, "utf8"));
|
|
2737
|
+
};
|
|
2738
|
+
await addInput(postgrestTypes);
|
|
2739
|
+
await addInput(drizzleSchema);
|
|
2740
|
+
const drizzleProgram = ts13.createProgram([drizzleSchema], {
|
|
2741
|
+
noEmit: true,
|
|
2742
|
+
moduleResolution: ts13.ModuleResolutionKind.Bundler,
|
|
2743
|
+
module: ts13.ModuleKind.ESNext,
|
|
2744
|
+
target: ts13.ScriptTarget.ES2022,
|
|
2745
|
+
types: [],
|
|
2746
|
+
skipLibCheck: true
|
|
2747
|
+
});
|
|
2748
|
+
for (const source of drizzleProgram.getSourceFiles()) {
|
|
2749
|
+
if (!source.isDeclarationFile && !source.fileName.includes("/node_modules/"))
|
|
2750
|
+
await addInput(source.fileName);
|
|
2751
|
+
}
|
|
2752
|
+
await addInput(resolve16(rootDir, options.graphql.schema));
|
|
2753
|
+
if (new Set(options.migrations.map((path) => resolve16(rootDir, path))).size !== options.migrations.length) {
|
|
2754
|
+
throw new Error("Duplicate migration in database contracts configuration");
|
|
2755
|
+
}
|
|
2756
|
+
for (const path of options.migrations)
|
|
2757
|
+
await addInput(path);
|
|
2758
|
+
const files = {
|
|
2759
|
+
...artifacts.files,
|
|
2760
|
+
"database.ts": [
|
|
2761
|
+
"// GENERATED BY @supacloud/compiler database-contracts. Do not edit.",
|
|
2762
|
+
`export type { Database } from ${JSON.stringify(importPath(outDir, postgrestTypes))};`,
|
|
2763
|
+
'export type { QueryData, QueryResult, QueryError } from "@supabase/supabase-js";',
|
|
2764
|
+
`export type DrizzleSchema = typeof import(${JSON.stringify(importPath(outDir, drizzleSchema))});`,
|
|
2765
|
+
'export * from "./graphql";',
|
|
2766
|
+
""
|
|
2767
|
+
].join(`
|
|
2768
|
+
`)
|
|
2769
|
+
};
|
|
2770
|
+
const manifest = {
|
|
2771
|
+
version: 1,
|
|
2772
|
+
role: options.role,
|
|
2773
|
+
inputs: Object.fromEntries(Object.entries(inputs).sort(([a], [b]) => a.localeCompare(b))),
|
|
2774
|
+
migrationOrder: options.migrations.map((path) => relative12(rootDir, resolve16(rootDir, path)).replaceAll("\\", "/")),
|
|
2775
|
+
outputs: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([file, text]) => [file, hash2(text)]))
|
|
2776
|
+
};
|
|
2777
|
+
files["database.manifest.json"] = JSON.stringify(manifest, null, 2) + `
|
|
2778
|
+
`;
|
|
2779
|
+
const mismatches = [];
|
|
2780
|
+
for (const [file, content] of Object.entries(files)) {
|
|
2781
|
+
const path = resolve16(outDir, file);
|
|
2782
|
+
let current;
|
|
2783
|
+
try {
|
|
2784
|
+
current = await readFile12(path, "utf8");
|
|
2785
|
+
} catch (error) {
|
|
2786
|
+
if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
|
|
2787
|
+
throw error;
|
|
2788
|
+
}
|
|
2789
|
+
if (current !== content)
|
|
2790
|
+
mismatches.push(file);
|
|
2791
|
+
}
|
|
2792
|
+
if (!check) {
|
|
2793
|
+
await mkdir6(outDir, { recursive: true });
|
|
2794
|
+
for (const [file, content] of Object.entries(files))
|
|
2795
|
+
await writeFileIfChanged(resolve16(outDir, file), content);
|
|
2796
|
+
}
|
|
2797
|
+
return { upToDate: mismatches.length === 0, mismatches, written: check ? [] : mismatches, manifest };
|
|
2798
|
+
}
|
|
2799
|
+
async function runDatabaseContractsFile(path, check = false) {
|
|
2800
|
+
const absolute = resolve16(path);
|
|
2801
|
+
const value = JSON.parse(await readFile12(absolute, "utf8"));
|
|
2802
|
+
return generateDatabaseContracts(parseDatabaseContractsOptions(value, dirname11(absolute)), check);
|
|
2803
|
+
}
|
|
2804
|
+
var init_database_contracts = __esm(() => {
|
|
2805
|
+
init_graphql();
|
|
2806
|
+
init_generate();
|
|
2807
|
+
init_graphql_options();
|
|
2808
|
+
});
|
|
2809
|
+
|
|
2645
2810
|
// src/analyze.ts
|
|
2646
2811
|
import { createHash as createHash3 } from "node:crypto";
|
|
2647
2812
|
import { relative as relative2, resolve as resolvePath, sep as sep2 } from "node:path";
|
|
2648
|
-
import * as
|
|
2813
|
+
import * as ts4 from "@typescript/typescript6";
|
|
2649
2814
|
|
|
2650
2815
|
// src/program.ts
|
|
2651
2816
|
import { createHash as createHash2 } from "node:crypto";
|
|
@@ -3295,6 +3460,7 @@ var COMPILER_DIAGNOSTIC_CODES = {
|
|
|
3295
3460
|
"missing-token-factory": { code: "SC2009", docsUrl: "https://supacloud.dev/errors/SC2009" },
|
|
3296
3461
|
"provider-type-mismatch": { code: "SC2010", docsUrl: "https://supacloud.dev/errors/SC2010" },
|
|
3297
3462
|
"unsupported-provider-helper": { code: "SC2011", docsUrl: "https://supacloud.dev/errors/SC2011" },
|
|
3463
|
+
"runtime-injection-disallowed": { code: "SC2012", docsUrl: "https://supacloud.dev/errors/SC2012" },
|
|
3298
3464
|
"command-missing-permission": { code: "SC4001", docsUrl: "https://supacloud.dev/errors/SC4001" },
|
|
3299
3465
|
"duplicate-command": { code: "SC4002", docsUrl: "https://supacloud.dev/errors/SC4002" },
|
|
3300
3466
|
"route-command-unresolved": { code: "SC4003", docsUrl: "https://supacloud.dev/errors/SC4003" },
|
|
@@ -3341,6 +3507,20 @@ var COMPILER_DIAGNOSTIC_CODES = {
|
|
|
3341
3507
|
function validateGraph(graph, options = false) {
|
|
3342
3508
|
const strict = typeof options === "boolean" ? options : options.strict ?? false;
|
|
3343
3509
|
const diagnostics = [];
|
|
3510
|
+
for (const module of graph.modules) {
|
|
3511
|
+
for (const owner of [...module.providers, ...module.controllers]) {
|
|
3512
|
+
if (owner.functionalInjects?.length)
|
|
3513
|
+
diagnostics.push({
|
|
3514
|
+
severity: "error",
|
|
3515
|
+
code: "runtime-injection-disallowed",
|
|
3516
|
+
errorCode: "SC2012",
|
|
3517
|
+
docsUrl: "https://supacloud.dev/errors/SC2012",
|
|
3518
|
+
file: owner.file,
|
|
3519
|
+
message: "Property inject() requires runtime token resolution. Compiled applications require constructor injection.",
|
|
3520
|
+
suggestion: "Move injected fields into typed constructor parameters with @Inject(TOKEN) where needed."
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3344
3524
|
let moduleBoundaries;
|
|
3345
3525
|
if (typeof options === "object") {
|
|
3346
3526
|
try {
|
|
@@ -4121,6 +4301,67 @@ function detectOrphanModules(graph) {
|
|
|
4121
4301
|
}
|
|
4122
4302
|
return diagnostics;
|
|
4123
4303
|
}
|
|
4304
|
+
// src/static-di.ts
|
|
4305
|
+
import * as ts3 from "@typescript/typescript6";
|
|
4306
|
+
var runtimeApis = new Set([
|
|
4307
|
+
"inject",
|
|
4308
|
+
"createEnvironmentInjector",
|
|
4309
|
+
"runInInjectionContext",
|
|
4310
|
+
"EnvironmentInjector",
|
|
4311
|
+
"bootstrapBun",
|
|
4312
|
+
"runInScope",
|
|
4313
|
+
"runInRequestContext",
|
|
4314
|
+
"runInJobContext",
|
|
4315
|
+
"runInTransactionContext"
|
|
4316
|
+
]);
|
|
4317
|
+
function scanRuntimeDi(source, file) {
|
|
4318
|
+
const diagnostics = [];
|
|
4319
|
+
const namespaces = new Set;
|
|
4320
|
+
const report = (node) => diagnostics.push({
|
|
4321
|
+
severity: "error",
|
|
4322
|
+
code: "runtime-injection-disallowed",
|
|
4323
|
+
errorCode: "SC2012",
|
|
4324
|
+
docsUrl: "https://supacloud.dev/errors/SC2012",
|
|
4325
|
+
file,
|
|
4326
|
+
line: source.getLineAndCharacterOfPosition(node.getStart()).line + 1,
|
|
4327
|
+
message: "Compiled applications cannot import runtime DI. Use explicit constructors and generated scope factories."
|
|
4328
|
+
});
|
|
4329
|
+
for (const statement of source.statements) {
|
|
4330
|
+
if (!(ts3.isImportDeclaration(statement) || ts3.isExportDeclaration(statement)) || !statement.moduleSpecifier || !ts3.isStringLiteral(statement.moduleSpecifier) || !/^@supacloud\/app(?:\/|$)/.test(statement.moduleSpecifier.text))
|
|
4331
|
+
continue;
|
|
4332
|
+
if (ts3.isImportDeclaration(statement)) {
|
|
4333
|
+
if (statement.importClause?.isTypeOnly)
|
|
4334
|
+
continue;
|
|
4335
|
+
const binding = statement.importClause?.namedBindings;
|
|
4336
|
+
if (binding && ts3.isNamespaceImport(binding))
|
|
4337
|
+
namespaces.add(binding.name.text);
|
|
4338
|
+
if (binding && ts3.isNamedImports(binding))
|
|
4339
|
+
for (const item of binding.elements) {
|
|
4340
|
+
if (!item.isTypeOnly && runtimeApis.has((item.propertyName ?? item.name).text))
|
|
4341
|
+
report(item);
|
|
4342
|
+
}
|
|
4343
|
+
} else if (!statement.isTypeOnly) {
|
|
4344
|
+
if (!statement.exportClause)
|
|
4345
|
+
report(statement);
|
|
4346
|
+
else if (ts3.isNamedExports(statement.exportClause))
|
|
4347
|
+
for (const item of statement.exportClause.elements) {
|
|
4348
|
+
if (!item.isTypeOnly && runtimeApis.has((item.propertyName ?? item.name).text))
|
|
4349
|
+
report(item);
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
const visit = (node) => {
|
|
4354
|
+
if (ts3.isPropertyAccessExpression(node) && ts3.isIdentifier(node.expression) && namespaces.has(node.expression.text) && runtimeApis.has(node.name.text))
|
|
4355
|
+
report(node);
|
|
4356
|
+
if (ts3.isElementAccessExpression(node) && ts3.isIdentifier(node.expression) && namespaces.has(node.expression.text) && (!ts3.isStringLiteral(node.argumentExpression) || runtimeApis.has(node.argumentExpression.text)))
|
|
4357
|
+
report(node);
|
|
4358
|
+
if (ts3.isVariableDeclaration(node) && node.initializer && ts3.isIdentifier(node.initializer) && namespaces.has(node.initializer.text))
|
|
4359
|
+
report(node);
|
|
4360
|
+
ts3.forEachChild(node, visit);
|
|
4361
|
+
};
|
|
4362
|
+
visit(source);
|
|
4363
|
+
return diagnostics;
|
|
4364
|
+
}
|
|
4124
4365
|
|
|
4125
4366
|
// src/analyze.ts
|
|
4126
4367
|
var DEFAULT_INCLUDE = ["**/*.module.ts", "**/*.ts"];
|
|
@@ -4162,26 +4403,26 @@ function lineOf(node) {
|
|
|
4162
4403
|
return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
|
|
4163
4404
|
}
|
|
4164
4405
|
function variableName(decl) {
|
|
4165
|
-
return
|
|
4406
|
+
return ts4.isIdentifier(decl.name) ? decl.name.text : nodeText(decl.name);
|
|
4166
4407
|
}
|
|
4167
4408
|
function propertyName(name) {
|
|
4168
|
-
if (
|
|
4409
|
+
if (ts4.isIdentifier(name) || ts4.isPrivateIdentifier(name))
|
|
4169
4410
|
return name.text;
|
|
4170
|
-
if (
|
|
4411
|
+
if (ts4.isStringLiteral(name) || ts4.isNumericLiteral(name))
|
|
4171
4412
|
return name.text;
|
|
4172
4413
|
return nodeText(name);
|
|
4173
4414
|
}
|
|
4174
4415
|
function parameterName(param) {
|
|
4175
|
-
return
|
|
4416
|
+
return ts4.isIdentifier(param.name) ? param.name.text : nodeText(param.name);
|
|
4176
4417
|
}
|
|
4177
4418
|
function decoratorsOf(node) {
|
|
4178
|
-
return
|
|
4419
|
+
return ts4.canHaveDecorators(node) ? ts4.getDecorators(node) ?? [] : [];
|
|
4179
4420
|
}
|
|
4180
4421
|
function decoratorArguments(dec) {
|
|
4181
|
-
return
|
|
4422
|
+
return ts4.isCallExpression(dec.expression) ? dec.expression.arguments : [];
|
|
4182
4423
|
}
|
|
4183
4424
|
function hasMethod(cls, name) {
|
|
4184
|
-
return cls.members.some((member) => (
|
|
4425
|
+
return cls.members.some((member) => (ts4.isMethodDeclaration(member) || ts4.isGetAccessorDeclaration(member) || ts4.isSetAccessorDeclaration(member)) && member.name !== undefined && propertyName(member.name) === name);
|
|
4185
4426
|
}
|
|
4186
4427
|
function hasDestroyHook(cls) {
|
|
4187
4428
|
return hasMethod(cls, "onDestroy") || hasMethod(cls, "ngOnDestroy");
|
|
@@ -4191,7 +4432,7 @@ function descendantsOfKind(root, predicate) {
|
|
|
4191
4432
|
const visit = (node) => {
|
|
4192
4433
|
if (predicate(node))
|
|
4193
4434
|
result.push(node);
|
|
4194
|
-
|
|
4435
|
+
ts4.forEachChild(node, visit);
|
|
4195
4436
|
};
|
|
4196
4437
|
visit(root);
|
|
4197
4438
|
return result;
|
|
@@ -4200,7 +4441,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
4200
4441
|
const session = cache?.programSession ?? createIncrementalProgramSession(rootDir);
|
|
4201
4442
|
if (cache)
|
|
4202
4443
|
cache.programSession = session;
|
|
4203
|
-
const rootNames =
|
|
4444
|
+
const rootNames = ts4.sys.readDirectory(rootDir, [".ts", ".tsx"], ["node_modules", "dist"], include ?? DEFAULT_INCLUDE);
|
|
4204
4445
|
const update = session.update(rootNames, changedPaths);
|
|
4205
4446
|
const program = update.program;
|
|
4206
4447
|
const checker = program.getTypeChecker();
|
|
@@ -4224,13 +4465,16 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
4224
4465
|
nativeTraitFiles.set(trait.file, kinds);
|
|
4225
4466
|
}
|
|
4226
4467
|
for (const sf of sourceFiles) {
|
|
4468
|
+
if (!/\.(?:test|spec)\.[cm]?tsx?$/.test(sf.fileName)) {
|
|
4469
|
+
ctx.diagnostics.push(...scanRuntimeDi(sf, sourcePath(rootDir, sf.fileName)));
|
|
4470
|
+
}
|
|
4227
4471
|
indexFile(sf, ctx);
|
|
4228
4472
|
}
|
|
4229
4473
|
const candidates = [];
|
|
4230
4474
|
for (const sf of sourceFiles) {
|
|
4231
4475
|
const traits = nativeTraitFiles.get(sf.fileName);
|
|
4232
4476
|
if (!cache || traits?.has("module")) {
|
|
4233
|
-
for (const cls of sf.statements.filter(
|
|
4477
|
+
for (const cls of sf.statements.filter(ts4.isClassDeclaration)) {
|
|
4234
4478
|
const moduleDec = findDecorator(cls, "Module");
|
|
4235
4479
|
if (!moduleDec)
|
|
4236
4480
|
continue;
|
|
@@ -4247,14 +4491,14 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
4247
4491
|
}
|
|
4248
4492
|
}
|
|
4249
4493
|
if (!cache || traits?.has("defineModule") || traits?.has("defineFeatureSlice")) {
|
|
4250
|
-
for (const call of descendantsOfKind(sf,
|
|
4494
|
+
for (const call of descendantsOfKind(sf, ts4.isCallExpression)) {
|
|
4251
4495
|
if (!["defineModule", "defineFeatureSlice"].includes(nodeText(call.expression)))
|
|
4252
4496
|
continue;
|
|
4253
4497
|
const parent = call.parent;
|
|
4254
|
-
if (!parent || !
|
|
4498
|
+
if (!parent || !ts4.isVariableDeclaration(parent))
|
|
4255
4499
|
continue;
|
|
4256
4500
|
const arg = call.arguments[0];
|
|
4257
|
-
if (!arg || !
|
|
4501
|
+
if (!arg || !ts4.isObjectLiteralExpression(arg))
|
|
4258
4502
|
continue;
|
|
4259
4503
|
candidates.push({
|
|
4260
4504
|
node: parent,
|
|
@@ -4398,7 +4642,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
4398
4642
|
const controllerDec = findDecorator(classInfo.decl, "Controller");
|
|
4399
4643
|
if (controllerDec) {
|
|
4400
4644
|
const arg = decoratorArguments(controllerDec)[0];
|
|
4401
|
-
const isStandalone = arg &&
|
|
4645
|
+
const isStandalone = arg && ts4.isObjectLiteralExpression(arg) && booleanProp(arg, "standalone");
|
|
4402
4646
|
if (isStandalone) {
|
|
4403
4647
|
const ctrl = parseController(classInfo.decl, ctx);
|
|
4404
4648
|
if (ctrl)
|
|
@@ -4523,16 +4767,16 @@ function collectModuleSourceClosure(module, ctx) {
|
|
|
4523
4767
|
ownedFiles.add(relativeFile);
|
|
4524
4768
|
for (const statement of sourceFile.statements) {
|
|
4525
4769
|
let moduleName;
|
|
4526
|
-
if (
|
|
4770
|
+
if (ts4.isImportDeclaration(statement) && ts4.isStringLiteral(statement.moduleSpecifier)) {
|
|
4527
4771
|
moduleName = statement.moduleSpecifier.text;
|
|
4528
|
-
} else if (
|
|
4772
|
+
} else if (ts4.isExportDeclaration(statement) && statement.moduleSpecifier && ts4.isStringLiteral(statement.moduleSpecifier)) {
|
|
4529
4773
|
moduleName = statement.moduleSpecifier.text;
|
|
4530
|
-
} else if (
|
|
4774
|
+
} else if (ts4.isImportEqualsDeclaration(statement) && ts4.isExternalModuleReference(statement.moduleReference) && ts4.isStringLiteral(statement.moduleReference.expression)) {
|
|
4531
4775
|
moduleName = statement.moduleReference.expression.text;
|
|
4532
4776
|
}
|
|
4533
4777
|
if (!moduleName || moduleName.startsWith("node:"))
|
|
4534
4778
|
continue;
|
|
4535
|
-
const resolved =
|
|
4779
|
+
const resolved = ts4.resolveModuleName(moduleName, sourceFile.fileName, ctx.program.getCompilerOptions(), ts4.sys).resolvedModule?.resolvedFileName;
|
|
4536
4780
|
if (resolved && isProjectSourcePath(resolved, ctx.rootDir) && !enqueued.has(resolved)) {
|
|
4537
4781
|
enqueued.add(resolved);
|
|
4538
4782
|
queue.push(resolved);
|
|
@@ -4554,15 +4798,15 @@ function isProjectSourceFile(sourceFile, rootDir) {
|
|
|
4554
4798
|
return isProjectSourcePath(sourceFile.fileName, rootDir) && /\.(tsx?|mts|cts)$/.test(sourceFile.fileName);
|
|
4555
4799
|
}
|
|
4556
4800
|
function indexFile(sf, ctx) {
|
|
4557
|
-
for (const cls of sf.statements.filter(
|
|
4801
|
+
for (const cls of sf.statements.filter(ts4.isClassDeclaration)) {
|
|
4558
4802
|
const name = cls.name?.text;
|
|
4559
4803
|
if (name && !ctx.classesByName.has(name)) {
|
|
4560
4804
|
ctx.classesByName.set(name, { name, decl: cls, file: sf.fileName });
|
|
4561
4805
|
}
|
|
4562
4806
|
}
|
|
4563
|
-
for (const statement of sf.statements.filter(
|
|
4807
|
+
for (const statement of sf.statements.filter(ts4.isVariableStatement)) {
|
|
4564
4808
|
for (const decl of statement.declarationList.declarations) {
|
|
4565
|
-
if (
|
|
4809
|
+
if (ts4.isIdentifier(decl.name) && !ctx.variablesByName.has(decl.name.text)) {
|
|
4566
4810
|
ctx.variablesByName.set(decl.name.text, decl);
|
|
4567
4811
|
}
|
|
4568
4812
|
const info = parseTokenVariable(decl, sf.fileName);
|
|
@@ -4574,16 +4818,16 @@ function indexFile(sf, ctx) {
|
|
|
4574
4818
|
}
|
|
4575
4819
|
function parseTokenVariable(decl, file) {
|
|
4576
4820
|
const init = decl.initializer;
|
|
4577
|
-
if (!init || !
|
|
4821
|
+
if (!init || !ts4.isNewExpression(init))
|
|
4578
4822
|
return;
|
|
4579
4823
|
if (nodeText(init.expression) !== "InjectionToken")
|
|
4580
4824
|
return;
|
|
4581
4825
|
const [nameArg, optionsArg] = init.arguments ?? [];
|
|
4582
4826
|
const info = { name: variableName(decl), file, line: lineOf(decl) };
|
|
4583
|
-
if (nameArg &&
|
|
4827
|
+
if (nameArg && ts4.isStringLiteral(nameArg)) {
|
|
4584
4828
|
info.stringName = nameArg.text;
|
|
4585
4829
|
}
|
|
4586
|
-
if (optionsArg &&
|
|
4830
|
+
if (optionsArg && ts4.isObjectLiteralExpression(optionsArg)) {
|
|
4587
4831
|
const scope = stringLiteralProp(optionsArg, "scope");
|
|
4588
4832
|
if (scope && isScope(scope)) {
|
|
4589
4833
|
info.scope = scope;
|
|
@@ -4603,22 +4847,22 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
4603
4847
|
const { options, className, file, line } = candidate;
|
|
4604
4848
|
const name = nameByNode.get(candidate.node) ?? className;
|
|
4605
4849
|
const featureSpec = parseFeatureSpec(getProp(options, "spec"), ctx);
|
|
4606
|
-
const tags = arrayProp(options, "tags").map((el) =>
|
|
4850
|
+
const tags = arrayProp(options, "tags").map((el) => ts4.isStringLiteral(el) ? el.text : nodeText(el).replace(/['"]/g, "")).filter(Boolean);
|
|
4607
4851
|
const aspects = parseAspectRefs(getProp(options, "aspects"), ctx, `module ${name}`);
|
|
4608
4852
|
const imports = arrayProp(options, "imports").map((el) => {
|
|
4609
4853
|
const unwrapped = unwrapForwardRef(el);
|
|
4610
|
-
const decl =
|
|
4854
|
+
const decl = ts4.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
|
|
4611
4855
|
if (decl) {
|
|
4612
4856
|
const known = nameByNode.get(decl);
|
|
4613
4857
|
if (known)
|
|
4614
4858
|
return known;
|
|
4615
|
-
if (
|
|
4859
|
+
if (ts4.isClassDeclaration(decl)) {
|
|
4616
4860
|
const dec = findDecorator(decl, "Module");
|
|
4617
4861
|
const decOptions = dec && decoratorObjectArg(dec);
|
|
4618
4862
|
const decName = decOptions && stringLiteralProp(decOptions, "name");
|
|
4619
4863
|
return decName ?? decl.name?.text ?? nodeText(el);
|
|
4620
4864
|
}
|
|
4621
|
-
if (
|
|
4865
|
+
if (ts4.isVariableDeclaration(decl))
|
|
4622
4866
|
return variableName(decl);
|
|
4623
4867
|
}
|
|
4624
4868
|
return nodeText(el);
|
|
@@ -4632,7 +4876,7 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
4632
4876
|
providers.push(...parsedProviders);
|
|
4633
4877
|
continue;
|
|
4634
4878
|
}
|
|
4635
|
-
if (
|
|
4879
|
+
if (ts4.isCallExpression(el)) {
|
|
4636
4880
|
const helper = nodeText(el.expression).split(".").pop() ?? nodeText(el.expression);
|
|
4637
4881
|
warn(ctx, "unsupported-provider-helper", `无法静态展开 provider helper '${helper}';请改用显式 Provider 或实现编译器支持的 helper`, sourcePath(ctx.rootDir, el.getSourceFile().fileName), lineOf(el));
|
|
4638
4882
|
continue;
|
|
@@ -4642,10 +4886,10 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
4642
4886
|
providers.push(provider);
|
|
4643
4887
|
}
|
|
4644
4888
|
for (const el of arrayProp(options, "jobs")) {
|
|
4645
|
-
if (!
|
|
4889
|
+
if (!ts4.isIdentifier(el))
|
|
4646
4890
|
continue;
|
|
4647
4891
|
const decl = resolveDeclaration(el, ctx)[0];
|
|
4648
|
-
if (!decl || !
|
|
4892
|
+
if (!decl || !ts4.isClassDeclaration(decl))
|
|
4649
4893
|
continue;
|
|
4650
4894
|
const className = decl.name?.text ?? el.text;
|
|
4651
4895
|
const registeredProvider = providers.find((provider) => provider.token === className || provider.useClass === className);
|
|
@@ -4682,18 +4926,18 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
4682
4926
|
const handlerClasses = [];
|
|
4683
4927
|
const seenHandlers = new Set;
|
|
4684
4928
|
const collectHandler = (expr) => {
|
|
4685
|
-
if (!
|
|
4929
|
+
if (!ts4.isIdentifier(expr))
|
|
4686
4930
|
return;
|
|
4687
4931
|
const decl = resolveDeclaration(expr, ctx)[0];
|
|
4688
|
-
if (decl &&
|
|
4932
|
+
if (decl && ts4.isClassDeclaration(decl) && !seenHandlers.has(decl.name?.text ?? "")) {
|
|
4689
4933
|
seenHandlers.add(decl.name?.text ?? "");
|
|
4690
4934
|
handlerClasses.push(decl);
|
|
4691
4935
|
}
|
|
4692
4936
|
};
|
|
4693
4937
|
for (const el of arrayProp(options, "providers")) {
|
|
4694
|
-
if (
|
|
4938
|
+
if (ts4.isIdentifier(el))
|
|
4695
4939
|
collectHandler(el);
|
|
4696
|
-
if (
|
|
4940
|
+
if (ts4.isObjectLiteralExpression(el)) {
|
|
4697
4941
|
const useClass = getProp(el, "useClass");
|
|
4698
4942
|
if (useClass)
|
|
4699
4943
|
collectHandler(useClass);
|
|
@@ -4793,17 +5037,17 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
4793
5037
|
if (seen.has(input))
|
|
4794
5038
|
return;
|
|
4795
5039
|
seen.add(input);
|
|
4796
|
-
if (
|
|
4797
|
-
const local = input.getSourceFile().statements.flatMap((statement) =>
|
|
5040
|
+
if (ts4.isIdentifier(input)) {
|
|
5041
|
+
const local = input.getSourceFile().statements.flatMap((statement) => ts4.isVariableStatement(statement) ? [...statement.declarationList.declarations] : []);
|
|
4798
5042
|
const resolved = resolveDeclaration(input, ctx)[0];
|
|
4799
|
-
const decl = (resolved &&
|
|
4800
|
-
if (decl &&
|
|
5043
|
+
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);
|
|
5044
|
+
if (decl && ts4.isVariableDeclaration(decl))
|
|
4801
5045
|
return parseFeatureSpec(decl.initializer, ctx, seen);
|
|
4802
5046
|
}
|
|
4803
|
-
if (
|
|
5047
|
+
if (ts4.isCallExpression(input) && nodeText(input.expression) === "defineFeatureSpec") {
|
|
4804
5048
|
return parseFeatureSpec(input.arguments[0], ctx, seen);
|
|
4805
5049
|
}
|
|
4806
|
-
if (
|
|
5050
|
+
if (ts4.isAsExpression(input) || ts4.isSatisfiesExpression(input) || ts4.isParenthesizedExpression(input)) {
|
|
4807
5051
|
return parseFeatureSpec(input.expression, ctx, seen);
|
|
4808
5052
|
}
|
|
4809
5053
|
const invalid = () => {
|
|
@@ -4816,28 +5060,28 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
4816
5060
|
});
|
|
4817
5061
|
return;
|
|
4818
5062
|
};
|
|
4819
|
-
if (!
|
|
5063
|
+
if (!ts4.isObjectLiteralExpression(input))
|
|
4820
5064
|
return invalid();
|
|
4821
5065
|
const name = stringLiteralProp(input, "name");
|
|
4822
5066
|
const statesExpr = getProp(input, "states");
|
|
4823
5067
|
const transitionObject = getProp(input, "transitions");
|
|
4824
|
-
if (!name || !statesExpr || !
|
|
5068
|
+
if (!name || !statesExpr || !ts4.isArrayLiteralExpression(statesExpr) || statesExpr.elements.some((state) => !ts4.isStringLiteral(state)) || !transitionObject || !ts4.isObjectLiteralExpression(transitionObject) || input.properties.some((property) => !ts4.isPropertyAssignment(property))) {
|
|
4825
5069
|
return invalid();
|
|
4826
5070
|
}
|
|
4827
5071
|
const states = [];
|
|
4828
5072
|
for (const state of statesExpr.elements) {
|
|
4829
|
-
if (!
|
|
5073
|
+
if (!ts4.isStringLiteral(state))
|
|
4830
5074
|
return invalid();
|
|
4831
5075
|
states.push(state.text);
|
|
4832
5076
|
}
|
|
4833
5077
|
const transitions = [];
|
|
4834
5078
|
for (const property of transitionObject.properties) {
|
|
4835
|
-
if (!
|
|
5079
|
+
if (!ts4.isPropertyAssignment(property) || ts4.isComputedPropertyName(property.name) || !ts4.isObjectLiteralExpression(property.initializer))
|
|
4836
5080
|
return invalid();
|
|
4837
5081
|
const options = property.initializer;
|
|
4838
5082
|
const from = stringLiteralProp(options, "from");
|
|
4839
5083
|
const to = stringLiteralProp(options, "to");
|
|
4840
|
-
if (!from || !to || options.properties.some((prop) => !
|
|
5084
|
+
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))) {
|
|
4841
5085
|
return invalid();
|
|
4842
5086
|
}
|
|
4843
5087
|
const permission = stringLiteralProp(options, "permission");
|
|
@@ -4864,21 +5108,21 @@ function resolveStaticObjectLiteral(input, ctx, seen = new Set) {
|
|
|
4864
5108
|
if (!input || seen.has(input))
|
|
4865
5109
|
return;
|
|
4866
5110
|
seen.add(input);
|
|
4867
|
-
if (
|
|
5111
|
+
if (ts4.isAsExpression(input) || ts4.isSatisfiesExpression(input) || ts4.isParenthesizedExpression(input)) {
|
|
4868
5112
|
return resolveStaticObjectLiteral(input.expression, ctx, seen);
|
|
4869
5113
|
}
|
|
4870
|
-
if (
|
|
4871
|
-
const declaration = resolveDeclaration(input, ctx).find(
|
|
5114
|
+
if (ts4.isIdentifier(input)) {
|
|
5115
|
+
const declaration = resolveDeclaration(input, ctx).find(ts4.isVariableDeclaration);
|
|
4872
5116
|
return declaration?.initializer ? resolveStaticObjectLiteral(declaration.initializer, ctx, seen) : undefined;
|
|
4873
5117
|
}
|
|
4874
|
-
if (
|
|
5118
|
+
if (ts4.isCallExpression(input)) {
|
|
4875
5119
|
const expressionName = nodeText(input.expression);
|
|
4876
5120
|
if (expressionName === "defineRouteContract" || expressionName.endsWith(".defineRouteContract")) {
|
|
4877
5121
|
return resolveStaticObjectLiteral(input.arguments[0], ctx, seen);
|
|
4878
5122
|
}
|
|
4879
5123
|
return;
|
|
4880
5124
|
}
|
|
4881
|
-
return
|
|
5125
|
+
return ts4.isObjectLiteralExpression(input) ? input : undefined;
|
|
4882
5126
|
}
|
|
4883
5127
|
function commandModeProp(object, name) {
|
|
4884
5128
|
const value = stringLiteralProp(object, name);
|
|
@@ -4913,9 +5157,9 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
4913
5157
|
const file = sourcePath(ctx.rootDir, el.getSourceFile().fileName);
|
|
4914
5158
|
const line = lineOf(el);
|
|
4915
5159
|
const unwrappedEl = unwrapForwardRef(el);
|
|
4916
|
-
if (
|
|
5160
|
+
if (ts4.isIdentifier(unwrappedEl)) {
|
|
4917
5161
|
const decl = resolveDeclaration(unwrappedEl, ctx)[0];
|
|
4918
|
-
const cls = decl &&
|
|
5162
|
+
const cls = decl && ts4.isClassDeclaration(decl) ? decl : undefined;
|
|
4919
5163
|
const className = cls?.name?.text ?? unwrappedEl.text;
|
|
4920
5164
|
const { deps, optionalDeps, selfDeps, skipSelfDeps, hostDeps, functionalInjects, missing } = cls ? classDeps(cls, ctx) : { deps: [], optionalDeps: [], selfDeps: [], skipSelfDeps: [], hostDeps: [], functionalInjects: [], missing: false };
|
|
4921
5165
|
const injectable = cls ? parseInjectableOptions(cls, ctx) : undefined;
|
|
@@ -4942,7 +5186,7 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
4942
5186
|
...cls ? { importPath: modulePath(ctx.rootDir, cls.getSourceFile().fileName) } : {}
|
|
4943
5187
|
};
|
|
4944
5188
|
}
|
|
4945
|
-
if (!
|
|
5189
|
+
if (!ts4.isObjectLiteralExpression(el))
|
|
4946
5190
|
return;
|
|
4947
5191
|
const provideExpr = getProp(el, "provide");
|
|
4948
5192
|
if (!provideExpr)
|
|
@@ -4957,8 +5201,8 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
4957
5201
|
const useExistingExpr = getProp(el, "useExisting");
|
|
4958
5202
|
if (useClassExpr) {
|
|
4959
5203
|
const unwrappedClass = unwrapForwardRef(useClassExpr);
|
|
4960
|
-
const decl =
|
|
4961
|
-
const cls = decl &&
|
|
5204
|
+
const decl = ts4.isIdentifier(unwrappedClass) ? resolveDeclaration(unwrappedClass, ctx)[0] : undefined;
|
|
5205
|
+
const cls = decl && ts4.isClassDeclaration(decl) ? decl : undefined;
|
|
4962
5206
|
const useClass = cls?.name?.text ?? nodeText(unwrappedClass);
|
|
4963
5207
|
let deps = explicitDeps;
|
|
4964
5208
|
let optionalDeps = [];
|
|
@@ -5014,7 +5258,7 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
5014
5258
|
}
|
|
5015
5259
|
if (useValueExpr) {
|
|
5016
5260
|
validateProviderCompatibility(provideExpr, useValueExpr, "value", token, ctx, file, line);
|
|
5017
|
-
const importPath =
|
|
5261
|
+
const importPath = ts4.isIdentifier(useValueExpr) ? importPathOf(useValueExpr, ctx) : undefined;
|
|
5018
5262
|
return {
|
|
5019
5263
|
token,
|
|
5020
5264
|
tokenKind,
|
|
@@ -5030,12 +5274,12 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
5030
5274
|
};
|
|
5031
5275
|
}
|
|
5032
5276
|
if (useFactoryExpr) {
|
|
5033
|
-
const factoryName =
|
|
5277
|
+
const factoryName = ts4.isIdentifier(useFactoryExpr) ? (() => {
|
|
5034
5278
|
const decl = resolveDeclaration(useFactoryExpr, ctx)[0];
|
|
5035
|
-
return decl && (
|
|
5279
|
+
return decl && (ts4.isFunctionDeclaration(decl) || ts4.isVariableDeclaration(decl)) ? (ts4.isFunctionDeclaration(decl) ? decl.name?.text : variableName(decl)) ?? useFactoryExpr.text : useFactoryExpr.text;
|
|
5036
5280
|
})() : nodeText(useFactoryExpr);
|
|
5037
5281
|
validateProviderCompatibility(provideExpr, useFactoryExpr, "factory", token, ctx, file, line);
|
|
5038
|
-
const importPath =
|
|
5282
|
+
const importPath = ts4.isIdentifier(useFactoryExpr) ? importPathOf(useFactoryExpr, ctx) : undefined;
|
|
5039
5283
|
return {
|
|
5040
5284
|
token,
|
|
5041
5285
|
tokenKind,
|
|
@@ -5071,20 +5315,20 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
5071
5315
|
function expandProviderExpressions(expressions, ctx, seen = new Set) {
|
|
5072
5316
|
const result = [];
|
|
5073
5317
|
for (const expression of expressions) {
|
|
5074
|
-
if (
|
|
5318
|
+
if (ts4.isSpreadElement(expression)) {
|
|
5075
5319
|
result.push(...expandProviderExpressions([expression.expression], ctx, seen));
|
|
5076
5320
|
continue;
|
|
5077
5321
|
}
|
|
5078
|
-
if (
|
|
5322
|
+
if (ts4.isIdentifier(expression)) {
|
|
5079
5323
|
const declaration = resolveDeclaration(expression, ctx)[0];
|
|
5080
|
-
if (declaration &&
|
|
5324
|
+
if (declaration && ts4.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
5081
5325
|
const key = `${declaration.getSourceFile().fileName}:${declaration.pos}`;
|
|
5082
5326
|
if (seen.has(key))
|
|
5083
5327
|
continue;
|
|
5084
5328
|
const initializer = declaration.initializer;
|
|
5085
|
-
if (
|
|
5329
|
+
if (ts4.isCallExpression(initializer) && isProviderHelper(initializer, "makeEnvironmentProviders")) {
|
|
5086
5330
|
const nested = initializer.arguments[0];
|
|
5087
|
-
if (nested &&
|
|
5331
|
+
if (nested && ts4.isArrayLiteralExpression(nested)) {
|
|
5088
5332
|
seen.add(key);
|
|
5089
5333
|
result.push(...expandProviderExpressions([...nested.elements], ctx, seen));
|
|
5090
5334
|
seen.delete(key);
|
|
@@ -5093,9 +5337,9 @@ function expandProviderExpressions(expressions, ctx, seen = new Set) {
|
|
|
5093
5337
|
}
|
|
5094
5338
|
}
|
|
5095
5339
|
}
|
|
5096
|
-
if (
|
|
5340
|
+
if (ts4.isCallExpression(expression) && isProviderHelper(expression, "makeEnvironmentProviders")) {
|
|
5097
5341
|
const nested = expression.arguments[0];
|
|
5098
|
-
if (nested &&
|
|
5342
|
+
if (nested && ts4.isArrayLiteralExpression(nested)) {
|
|
5099
5343
|
result.push(...expandProviderExpressions([...nested.elements], ctx, seen));
|
|
5100
5344
|
continue;
|
|
5101
5345
|
}
|
|
@@ -5108,7 +5352,7 @@ function isProviderHelper(expression, name) {
|
|
|
5108
5352
|
return nodeText(expression.expression).split(".").pop() === name;
|
|
5109
5353
|
}
|
|
5110
5354
|
function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
5111
|
-
if (!
|
|
5355
|
+
if (!ts4.isCallExpression(expression))
|
|
5112
5356
|
return;
|
|
5113
5357
|
const helper = nodeText(expression.expression).split(".").pop();
|
|
5114
5358
|
const args = expression.arguments;
|
|
@@ -5121,7 +5365,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
5121
5365
|
return [];
|
|
5122
5366
|
const { name: token, kind: tokenKind } = tokenNameOf(tokenExpr, ctx);
|
|
5123
5367
|
validateProviderCompatibility(tokenExpr, valueExpr, "value", token, ctx, file, line);
|
|
5124
|
-
const importPath =
|
|
5368
|
+
const importPath = ts4.isIdentifier(valueExpr) ? importPathOf(valueExpr, ctx) : undefined;
|
|
5125
5369
|
return [{
|
|
5126
5370
|
token,
|
|
5127
5371
|
tokenKind,
|
|
@@ -5140,7 +5384,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
5140
5384
|
if (!initializer)
|
|
5141
5385
|
return [];
|
|
5142
5386
|
const token = helper === "provideAppInitializer" ? "APP_INITIALIZER" : "ENVIRONMENT_INITIALIZER";
|
|
5143
|
-
const importPath =
|
|
5387
|
+
const importPath = ts4.isIdentifier(initializer) ? importPathOf(initializer, ctx) : undefined;
|
|
5144
5388
|
return [{
|
|
5145
5389
|
token,
|
|
5146
5390
|
tokenKind: "injection-token",
|
|
@@ -5159,7 +5403,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
5159
5403
|
const providers = [];
|
|
5160
5404
|
const routes = args[0];
|
|
5161
5405
|
if (routes) {
|
|
5162
|
-
const importPath =
|
|
5406
|
+
const importPath = ts4.isIdentifier(routes) ? importPathOf(routes, ctx) : undefined;
|
|
5163
5407
|
providers.push({
|
|
5164
5408
|
token: "ROUTE_CONFIG",
|
|
5165
5409
|
tokenKind: "injection-token",
|
|
@@ -5174,7 +5418,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
5174
5418
|
});
|
|
5175
5419
|
}
|
|
5176
5420
|
for (const feature of args.slice(1)) {
|
|
5177
|
-
if (!
|
|
5421
|
+
if (!ts4.isCallExpression(feature))
|
|
5178
5422
|
continue;
|
|
5179
5423
|
const featureName = nodeText(feature.expression).split(".").pop();
|
|
5180
5424
|
if (featureName === "withRouterConfig" && feature.arguments[0]) {
|
|
@@ -5191,8 +5435,8 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
5191
5435
|
});
|
|
5192
5436
|
} else if (featureName === "withTitleStrategy" && feature.arguments[0]) {
|
|
5193
5437
|
const strategy = feature.arguments[0];
|
|
5194
|
-
const isClass =
|
|
5195
|
-
const importPath =
|
|
5438
|
+
const isClass = ts4.isIdentifier(strategy) && Boolean(resolveDeclaration(strategy, ctx).find((declaration) => ts4.isClassDeclaration(declaration)));
|
|
5439
|
+
const importPath = ts4.isIdentifier(strategy) ? importPathOf(strategy, ctx) : undefined;
|
|
5196
5440
|
providers.push({
|
|
5197
5441
|
token: "TITLE_STRATEGY",
|
|
5198
5442
|
tokenKind: "injection-token",
|
|
@@ -5224,14 +5468,14 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
5224
5468
|
importModule: "@supacloud/app"
|
|
5225
5469
|
}];
|
|
5226
5470
|
for (const feature of args) {
|
|
5227
|
-
if (!
|
|
5471
|
+
if (!ts4.isCallExpression(feature))
|
|
5228
5472
|
continue;
|
|
5229
5473
|
const featureName = nodeText(feature.expression).split(".").pop();
|
|
5230
5474
|
if (featureName === "withInterceptors") {
|
|
5231
5475
|
for (const interceptorArg of feature.arguments) {
|
|
5232
|
-
const values =
|
|
5476
|
+
const values = ts4.isArrayLiteralExpression(interceptorArg) ? [...interceptorArg.elements] : [interceptorArg];
|
|
5233
5477
|
for (const value of values) {
|
|
5234
|
-
const importPath =
|
|
5478
|
+
const importPath = ts4.isIdentifier(value) ? importPathOf(value, ctx) : undefined;
|
|
5235
5479
|
providers.push({
|
|
5236
5480
|
token: "HTTP_INTERCEPTORS",
|
|
5237
5481
|
tokenKind: "injection-token",
|
|
@@ -5278,9 +5522,9 @@ function providerTokenValueType(expr, ctx) {
|
|
|
5278
5522
|
const typeArguments = typeArgumentsOf(type, ctx);
|
|
5279
5523
|
if (typeArguments.length > 0)
|
|
5280
5524
|
return typeArguments[0];
|
|
5281
|
-
if (
|
|
5525
|
+
if (ts4.isIdentifier(expr)) {
|
|
5282
5526
|
const declaration = resolveDeclaration(expr, ctx)[0];
|
|
5283
|
-
if (declaration &&
|
|
5527
|
+
if (declaration && ts4.isClassDeclaration(declaration)) {
|
|
5284
5528
|
return declaredClassType(declaration, ctx);
|
|
5285
5529
|
}
|
|
5286
5530
|
}
|
|
@@ -5288,9 +5532,9 @@ function providerTokenValueType(expr, ctx) {
|
|
|
5288
5532
|
}
|
|
5289
5533
|
function providerImplementationType(expr, kind, ctx) {
|
|
5290
5534
|
if (kind === "class" || kind === "existing") {
|
|
5291
|
-
if (
|
|
5535
|
+
if (ts4.isIdentifier(expr)) {
|
|
5292
5536
|
const declaration = resolveDeclaration(expr, ctx)[0];
|
|
5293
|
-
if (declaration &&
|
|
5537
|
+
if (declaration && ts4.isClassDeclaration(declaration)) {
|
|
5294
5538
|
return declaredClassType(declaration, ctx);
|
|
5295
5539
|
}
|
|
5296
5540
|
}
|
|
@@ -5300,7 +5544,7 @@ function providerImplementationType(expr, kind, ctx) {
|
|
|
5300
5544
|
}
|
|
5301
5545
|
if (kind === "factory") {
|
|
5302
5546
|
const type = ctx.checker.getTypeAtLocation(expr);
|
|
5303
|
-
const signature = ctx.checker.getSignaturesOfType(type,
|
|
5547
|
+
const signature = ctx.checker.getSignaturesOfType(type, ts4.SignatureKind.Call)[0];
|
|
5304
5548
|
return signature?.getReturnType();
|
|
5305
5549
|
}
|
|
5306
5550
|
return ctx.checker.getTypeAtLocation(expr);
|
|
@@ -5319,16 +5563,16 @@ function isTypeReference(type) {
|
|
|
5319
5563
|
return "target" in type;
|
|
5320
5564
|
}
|
|
5321
5565
|
function isUnknownOrAny(type) {
|
|
5322
|
-
return (type.flags & (
|
|
5566
|
+
return (type.flags & (ts4.TypeFlags.Any | ts4.TypeFlags.Unknown)) !== 0;
|
|
5323
5567
|
}
|
|
5324
5568
|
function parseController(input, ctx) {
|
|
5325
5569
|
let decl;
|
|
5326
|
-
if (
|
|
5570
|
+
if (ts4.isClassDeclaration(input)) {
|
|
5327
5571
|
decl = input;
|
|
5328
5572
|
} else {
|
|
5329
5573
|
const unwrapped = unwrapForwardRef(input);
|
|
5330
|
-
const resolved =
|
|
5331
|
-
if (resolved &&
|
|
5574
|
+
const resolved = ts4.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
|
|
5575
|
+
if (resolved && ts4.isClassDeclaration(resolved)) {
|
|
5332
5576
|
decl = resolved;
|
|
5333
5577
|
}
|
|
5334
5578
|
}
|
|
@@ -5341,9 +5585,9 @@ function parseController(input, ctx) {
|
|
|
5341
5585
|
let standalone;
|
|
5342
5586
|
const pathArg = decoratorArguments(controllerDec)[0];
|
|
5343
5587
|
if (pathArg) {
|
|
5344
|
-
if (
|
|
5588
|
+
if (ts4.isStringLiteral(pathArg)) {
|
|
5345
5589
|
path = pathArg.text;
|
|
5346
|
-
} else if (
|
|
5590
|
+
} else if (ts4.isObjectLiteralExpression(pathArg)) {
|
|
5347
5591
|
const p = stringLiteralProp(pathArg, "path");
|
|
5348
5592
|
if (p)
|
|
5349
5593
|
path = p;
|
|
@@ -5366,7 +5610,7 @@ function parseController(input, ctx) {
|
|
|
5366
5610
|
}
|
|
5367
5611
|
}
|
|
5368
5612
|
}
|
|
5369
|
-
for (const method of decl.members.filter(
|
|
5613
|
+
for (const method of decl.members.filter(ts4.isMethodDeclaration)) {
|
|
5370
5614
|
for (const dec of decoratorsOf(method)) {
|
|
5371
5615
|
const name = decoratorName2(dec);
|
|
5372
5616
|
const httpMethod = name ? ROUTE_DECORATORS[name] : undefined;
|
|
@@ -5374,7 +5618,7 @@ function parseController(input, ctx) {
|
|
|
5374
5618
|
continue;
|
|
5375
5619
|
const args = decoratorArguments(dec);
|
|
5376
5620
|
const pathArg = args[0];
|
|
5377
|
-
const routePath = pathArg &&
|
|
5621
|
+
const routePath = pathArg && ts4.isStringLiteral(pathArg) ? pathArg.text : "/";
|
|
5378
5622
|
const route = {
|
|
5379
5623
|
method: httpMethod,
|
|
5380
5624
|
path: routePath,
|
|
@@ -5445,12 +5689,12 @@ function parseController(input, ctx) {
|
|
|
5445
5689
|
} else if (dName === "Headers") {
|
|
5446
5690
|
hasBindingDecorator = true;
|
|
5447
5691
|
const argument = dArgs[0];
|
|
5448
|
-
const bindingName = argument !== undefined &&
|
|
5692
|
+
const bindingName = argument !== undefined && ts4.isStringLiteral(argument) ? argument.text : undefined;
|
|
5449
5693
|
paramNode = { name: pName, kind: "headers", ...bindingName === undefined ? {} : { bindingName } };
|
|
5450
5694
|
} else if (dName === "Cookie") {
|
|
5451
5695
|
hasBindingDecorator = true;
|
|
5452
5696
|
const argument = dArgs[0];
|
|
5453
|
-
const bindingName = argument !== undefined &&
|
|
5697
|
+
const bindingName = argument !== undefined && ts4.isStringLiteral(argument) ? argument.text : undefined;
|
|
5454
5698
|
paramNode = { name: pName, kind: "cookie", ...bindingName === undefined ? {} : { bindingName } };
|
|
5455
5699
|
}
|
|
5456
5700
|
}
|
|
@@ -5512,20 +5756,20 @@ function parseController(input, ctx) {
|
|
|
5512
5756
|
}
|
|
5513
5757
|
} else if (dName === "Title") {
|
|
5514
5758
|
const tArg = mArgs[0];
|
|
5515
|
-
if (tArg &&
|
|
5759
|
+
if (tArg && ts4.isStringLiteral(tArg)) {
|
|
5516
5760
|
route.title = tArg.text;
|
|
5517
5761
|
}
|
|
5518
5762
|
} else if (dName === "Data") {
|
|
5519
5763
|
const dArg = mArgs[0];
|
|
5520
|
-
if (dArg &&
|
|
5764
|
+
if (dArg && ts4.isObjectLiteralExpression(dArg)) {
|
|
5521
5765
|
route.data = { ...route.data, ...parseObjectLiteralValues(dArg) };
|
|
5522
5766
|
}
|
|
5523
5767
|
} else if (dName === "Resolve") {
|
|
5524
5768
|
const rArg = mArgs[0];
|
|
5525
|
-
if (rArg &&
|
|
5769
|
+
if (rArg && ts4.isObjectLiteralExpression(rArg)) {
|
|
5526
5770
|
const resolvers = route.resolvers ?? {};
|
|
5527
5771
|
for (const prop of rArg.properties) {
|
|
5528
|
-
if (
|
|
5772
|
+
if (ts4.isPropertyAssignment(prop)) {
|
|
5529
5773
|
const rName = propertyName(prop.name);
|
|
5530
5774
|
const init = prop.initializer;
|
|
5531
5775
|
if (init)
|
|
@@ -5556,7 +5800,7 @@ function parseController(input, ctx) {
|
|
|
5556
5800
|
});
|
|
5557
5801
|
}
|
|
5558
5802
|
const contract = getProp(optionsObject, "contract");
|
|
5559
|
-
if (contract &&
|
|
5803
|
+
if (contract && ts4.isObjectLiteralExpression(contract)) {
|
|
5560
5804
|
route.contract = {};
|
|
5561
5805
|
for (const field of ["body", "response", "evidence"]) {
|
|
5562
5806
|
const value = stringLiteralProp(contract, field);
|
|
@@ -5574,15 +5818,15 @@ function parseController(input, ctx) {
|
|
|
5574
5818
|
}
|
|
5575
5819
|
for (const field of ["body", "params", "query", "headers", "cookie", "response"]) {
|
|
5576
5820
|
const schemaExpr = getProp(optionsObject, field);
|
|
5577
|
-
if (schemaExpr &&
|
|
5821
|
+
if (schemaExpr && ts4.isIdentifier(schemaExpr)) {
|
|
5578
5822
|
route[field] = nodeText(schemaExpr);
|
|
5579
5823
|
const importPath = importPathOf(schemaExpr, ctx);
|
|
5580
5824
|
if (importPath)
|
|
5581
5825
|
schemaImports[schemaExpr.text] = importPath;
|
|
5582
5826
|
const declaration = resolveDeclaration(schemaExpr, ctx)[0];
|
|
5583
5827
|
const typeName = ctx.checker.typeToString(ctx.checker.getTypeAtLocation(schemaExpr));
|
|
5584
|
-
const initializer = declaration &&
|
|
5585
|
-
const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer &&
|
|
5828
|
+
const initializer = declaration && ts4.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
|
|
5829
|
+
const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts4.isCallExpression(initializer) && ts4.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
|
|
5586
5830
|
(route.schemaKinds ??= {})[field] = opaque ? "opaque" : "declared";
|
|
5587
5831
|
}
|
|
5588
5832
|
}
|
|
@@ -5591,7 +5835,7 @@ function parseController(input, ctx) {
|
|
|
5591
5835
|
const responses = {};
|
|
5592
5836
|
const selectors = new Map;
|
|
5593
5837
|
for (const property of responsesObject.properties) {
|
|
5594
|
-
if (!
|
|
5838
|
+
if (!ts4.isPropertyAssignment(property) || ts4.isComputedPropertyName(property.name))
|
|
5595
5839
|
continue;
|
|
5596
5840
|
const status = propertyName(property.name);
|
|
5597
5841
|
if (!isRouteResponseSelector(status)) {
|
|
@@ -5623,7 +5867,7 @@ function parseController(input, ctx) {
|
|
|
5623
5867
|
}
|
|
5624
5868
|
selectors.set(canonical, status);
|
|
5625
5869
|
const schemaExpr = property.initializer;
|
|
5626
|
-
if (!
|
|
5870
|
+
if (!ts4.isIdentifier(schemaExpr)) {
|
|
5627
5871
|
ctx.diagnostics.push({
|
|
5628
5872
|
severity: "error",
|
|
5629
5873
|
code: "invalid-route-response-map",
|
|
@@ -5638,8 +5882,8 @@ function parseController(input, ctx) {
|
|
|
5638
5882
|
schemaImports[schemaExpr.text] = importPath;
|
|
5639
5883
|
const declaration = resolveDeclaration(schemaExpr, ctx)[0];
|
|
5640
5884
|
const typeName = ctx.checker.typeToString(ctx.checker.getTypeAtLocation(schemaExpr));
|
|
5641
|
-
const initializer = declaration &&
|
|
5642
|
-
const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer &&
|
|
5885
|
+
const initializer = declaration && ts4.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
|
|
5886
|
+
const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts4.isCallExpression(initializer) && ts4.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
|
|
5643
5887
|
const previousKind = route.schemaKinds?.response;
|
|
5644
5888
|
(route.schemaKinds ??= {}).response = opaque || previousKind === "opaque" ? "opaque" : "declared";
|
|
5645
5889
|
}
|
|
@@ -5647,18 +5891,18 @@ function parseController(input, ctx) {
|
|
|
5647
5891
|
route.responses = responses;
|
|
5648
5892
|
}
|
|
5649
5893
|
const commandExpr = getProp(optionsObject, "command");
|
|
5650
|
-
if (commandExpr &&
|
|
5894
|
+
if (commandExpr && ts4.isIdentifier(commandExpr)) {
|
|
5651
5895
|
const commandDecl = resolveDeclaration(commandExpr, ctx)[0];
|
|
5652
|
-
route.command = commandDecl &&
|
|
5896
|
+
route.command = commandDecl && ts4.isClassDeclaration(commandDecl) ? commandDecl.name?.text ?? commandExpr.text : commandExpr.text;
|
|
5653
5897
|
}
|
|
5654
5898
|
const guardsExpr = getProp(optionsObject, "guards");
|
|
5655
|
-
if (guardsExpr &&
|
|
5899
|
+
if (guardsExpr && ts4.isArrayLiteralExpression(guardsExpr)) {
|
|
5656
5900
|
for (const el of guardsExpr.elements) {
|
|
5657
5901
|
routeGuards.push(tokenText(el, ctx));
|
|
5658
5902
|
}
|
|
5659
5903
|
}
|
|
5660
5904
|
const canMatchExpr = getProp(optionsObject, "canMatch");
|
|
5661
|
-
if (canMatchExpr &&
|
|
5905
|
+
if (canMatchExpr && ts4.isArrayLiteralExpression(canMatchExpr)) {
|
|
5662
5906
|
const canMatchList = [];
|
|
5663
5907
|
for (const el of canMatchExpr.elements) {
|
|
5664
5908
|
canMatchList.push(tokenText(el, ctx));
|
|
@@ -5668,16 +5912,16 @@ function parseController(input, ctx) {
|
|
|
5668
5912
|
}
|
|
5669
5913
|
}
|
|
5670
5914
|
const canDeactivateExpr = getProp(optionsObject, "canDeactivate");
|
|
5671
|
-
if (canDeactivateExpr &&
|
|
5915
|
+
if (canDeactivateExpr && ts4.isArrayLiteralExpression(canDeactivateExpr)) {
|
|
5672
5916
|
for (const el of canDeactivateExpr.elements) {
|
|
5673
5917
|
routeCanDeactivate.push(tokenText(el, ctx));
|
|
5674
5918
|
}
|
|
5675
5919
|
}
|
|
5676
5920
|
const resolversExpr = getProp(optionsObject, "resolvers");
|
|
5677
|
-
if (resolversExpr &&
|
|
5921
|
+
if (resolversExpr && ts4.isObjectLiteralExpression(resolversExpr)) {
|
|
5678
5922
|
const resolvers = {};
|
|
5679
5923
|
for (const prop of resolversExpr.properties) {
|
|
5680
|
-
if (
|
|
5924
|
+
if (ts4.isPropertyAssignment(prop)) {
|
|
5681
5925
|
const rName = propertyName(prop.name);
|
|
5682
5926
|
const init = prop.initializer;
|
|
5683
5927
|
if (init)
|
|
@@ -5689,22 +5933,22 @@ function parseController(input, ctx) {
|
|
|
5689
5933
|
}
|
|
5690
5934
|
}
|
|
5691
5935
|
const redirectToExpr = getProp(optionsObject, "redirectTo");
|
|
5692
|
-
if (redirectToExpr &&
|
|
5936
|
+
if (redirectToExpr && ts4.isStringLiteral(redirectToExpr)) {
|
|
5693
5937
|
route.redirectTo = redirectToExpr.text;
|
|
5694
5938
|
}
|
|
5695
5939
|
const pathMatchExpr = getProp(optionsObject, "pathMatch");
|
|
5696
|
-
if (pathMatchExpr &&
|
|
5940
|
+
if (pathMatchExpr && ts4.isStringLiteral(pathMatchExpr)) {
|
|
5697
5941
|
const val = pathMatchExpr.text;
|
|
5698
5942
|
if (val === "full" || val === "prefix") {
|
|
5699
5943
|
route.pathMatch = val;
|
|
5700
5944
|
}
|
|
5701
5945
|
}
|
|
5702
5946
|
const titleExpr = getProp(optionsObject, "title");
|
|
5703
|
-
if (titleExpr &&
|
|
5947
|
+
if (titleExpr && ts4.isStringLiteral(titleExpr)) {
|
|
5704
5948
|
route.title = titleExpr.text;
|
|
5705
5949
|
}
|
|
5706
5950
|
const dataExpr = getProp(optionsObject, "data");
|
|
5707
|
-
if (dataExpr &&
|
|
5951
|
+
if (dataExpr && ts4.isObjectLiteralExpression(dataExpr)) {
|
|
5708
5952
|
route.data = { ...route.data, ...parseObjectLiteralValues(dataExpr) };
|
|
5709
5953
|
}
|
|
5710
5954
|
const aspects = parseAspectRefs(getProp(optionsObject, "aspects"), ctx, `route ${httpMethod} ${routePath}`);
|
|
@@ -5759,7 +6003,7 @@ function parseJobOptions(meta, owner, ctx) {
|
|
|
5759
6003
|
const expression = getProp(meta, field);
|
|
5760
6004
|
if (!expression)
|
|
5761
6005
|
continue;
|
|
5762
|
-
if (!
|
|
6006
|
+
if (!ts4.isIdentifier(expression)) {
|
|
5763
6007
|
jobOptionError(ctx, "invalid-job-schema", `${owner} 的 ${field} schema 必须是可静态解析的标识符引用,不能使用内联调用或动态表达式`, expression, "SC4019", `将 schema 提取为命名导出,例如 ${field}: ${field === "input" ? "JobInput" : "JobOutput"}。`);
|
|
5764
6008
|
continue;
|
|
5765
6009
|
}
|
|
@@ -5783,7 +6027,7 @@ function parseJobEnum(meta, field, allowed, owner, ctx, code, errorCode) {
|
|
|
5783
6027
|
const expression = getProp(meta, field);
|
|
5784
6028
|
if (!expression)
|
|
5785
6029
|
return;
|
|
5786
|
-
if (!
|
|
6030
|
+
if (!ts4.isStringLiteral(expression) || !allowed.includes(expression.text)) {
|
|
5787
6031
|
jobOptionError(ctx, code, `${owner} 的 ${field} 必须是 ${allowed.map((value) => JSON.stringify(value)).join(" 或 ")} 字符串字面量`, expression, errorCode);
|
|
5788
6032
|
return;
|
|
5789
6033
|
}
|
|
@@ -5793,7 +6037,7 @@ function parseJobInteger(meta, field, min, max, owner, ctx, code, errorCode) {
|
|
|
5793
6037
|
const expression = getProp(meta, field);
|
|
5794
6038
|
if (!expression)
|
|
5795
6039
|
return;
|
|
5796
|
-
const value =
|
|
6040
|
+
const value = ts4.isNumericLiteral(expression) ? Number(expression.text) : Number.NaN;
|
|
5797
6041
|
if (!Number.isSafeInteger(value) || value < min || value > max) {
|
|
5798
6042
|
jobOptionError(ctx, code, `${owner} 的 ${field} 必须是 ${min} 到 ${max} 之间的安全整数`, expression, errorCode);
|
|
5799
6043
|
return;
|
|
@@ -5814,8 +6058,8 @@ function jobOptionError(ctx, code, message, node, errorCode, suggestion) {
|
|
|
5814
6058
|
}
|
|
5815
6059
|
function jobSchemaKind(identifier, declaration, ctx) {
|
|
5816
6060
|
const typeName = ctx.checker.typeToString(ctx.checker.getTypeAtLocation(identifier));
|
|
5817
|
-
const initializer =
|
|
5818
|
-
const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer &&
|
|
6061
|
+
const initializer = ts4.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
|
|
6062
|
+
const opaque = /\bT(?:Unknown|Any)\b/.test(typeName) || initializer && ts4.isCallExpression(initializer) && ts4.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text);
|
|
5819
6063
|
return opaque ? "opaque" : "declared";
|
|
5820
6064
|
}
|
|
5821
6065
|
function checkedRpc(meta, ctx) {
|
|
@@ -5837,7 +6081,7 @@ function checkedRpc(meta, ctx) {
|
|
|
5837
6081
|
}
|
|
5838
6082
|
function classDeps(cls, ctx) {
|
|
5839
6083
|
const injectable = parseInjectableOptions(cls, ctx);
|
|
5840
|
-
const ctor = cls.members.find(
|
|
6084
|
+
const ctor = cls.members.find(ts4.isConstructorDeclaration);
|
|
5841
6085
|
const deps = injectable?.deps ? [...injectable.deps] : [];
|
|
5842
6086
|
const optionalDeps = [];
|
|
5843
6087
|
const selfDeps = [];
|
|
@@ -5871,23 +6115,23 @@ function classDeps(cls, ctx) {
|
|
|
5871
6115
|
}
|
|
5872
6116
|
});
|
|
5873
6117
|
}
|
|
5874
|
-
for (const prop of cls.members.filter(
|
|
6118
|
+
for (const prop of cls.members.filter(ts4.isPropertyDeclaration)) {
|
|
5875
6119
|
const init = prop.initializer;
|
|
5876
|
-
if (init &&
|
|
6120
|
+
if (init && ts4.isCallExpression(init)) {
|
|
5877
6121
|
const callName = nodeText(init.expression).split(".").pop();
|
|
5878
6122
|
if (callName === "inject") {
|
|
5879
6123
|
const [tokenArg, optionsArg] = init.arguments;
|
|
5880
6124
|
if (tokenArg) {
|
|
5881
6125
|
const tokenName = tokenText(tokenArg, ctx);
|
|
5882
6126
|
const unwrappedToken = unwrapForwardRef(tokenArg);
|
|
5883
|
-
const known =
|
|
6127
|
+
const known = ts4.isStringLiteral(unwrappedToken) || ts4.isIdentifier(unwrappedToken) && (ctx.tokensByName.has(tokenName) || ctx.classesByName.has(tokenName));
|
|
5884
6128
|
if (!known) {
|
|
5885
6129
|
missing = true;
|
|
5886
6130
|
continue;
|
|
5887
6131
|
}
|
|
5888
6132
|
if (!deps.includes(tokenName))
|
|
5889
6133
|
deps.push(tokenName);
|
|
5890
|
-
const options = optionsArg &&
|
|
6134
|
+
const options = optionsArg && ts4.isObjectLiteralExpression(optionsArg) ? {
|
|
5891
6135
|
optional: booleanProp(optionsArg, "optional") ?? false,
|
|
5892
6136
|
self: booleanProp(optionsArg, "self") ?? false,
|
|
5893
6137
|
skipSelf: booleanProp(optionsArg, "skipSelf") ?? false,
|
|
@@ -5902,9 +6146,9 @@ function classDeps(cls, ctx) {
|
|
|
5902
6146
|
if (options.host && !hostDeps.includes(tokenName))
|
|
5903
6147
|
hostDeps.push(tokenName);
|
|
5904
6148
|
if (!functionalInjects.some((entry) => entry.token === tokenName)) {
|
|
5905
|
-
const declaration =
|
|
6149
|
+
const declaration = ts4.isIdentifier(unwrappedToken) ? resolveDeclaration(unwrappedToken, ctx)[0] : undefined;
|
|
5906
6150
|
const localFile = declaration && isProjectSourcePath(declaration.getSourceFile().fileName, ctx.rootDir) ? declaration.getSourceFile().fileName : undefined;
|
|
5907
|
-
const importModule = declaration && !localFile &&
|
|
6151
|
+
const importModule = declaration && !localFile && ts4.isIdentifier(unwrappedToken) ? importModuleOf(unwrappedToken, ctx) : undefined;
|
|
5908
6152
|
functionalInjects.push({
|
|
5909
6153
|
token: tokenName,
|
|
5910
6154
|
expression: nodeText(unwrappedToken),
|
|
@@ -5948,7 +6192,7 @@ function parseInjectableOptions(cls, ctx) {
|
|
|
5948
6192
|
}
|
|
5949
6193
|
function parseInjectParams(cls, ctx) {
|
|
5950
6194
|
const result = new Map;
|
|
5951
|
-
const ctor = cls.members.find(
|
|
6195
|
+
const ctor = cls.members.find(ts4.isConstructorDeclaration);
|
|
5952
6196
|
if (!ctor)
|
|
5953
6197
|
return result;
|
|
5954
6198
|
ctor.parameters.forEach((param, index) => {
|
|
@@ -5964,7 +6208,7 @@ function parseInjectParams(cls, ctx) {
|
|
|
5964
6208
|
}
|
|
5965
6209
|
function parseOptionalParams(cls) {
|
|
5966
6210
|
const result = new Set;
|
|
5967
|
-
const ctor = cls.members.find(
|
|
6211
|
+
const ctor = cls.members.find(ts4.isConstructorDeclaration);
|
|
5968
6212
|
if (!ctor)
|
|
5969
6213
|
return result;
|
|
5970
6214
|
ctor.parameters.forEach((param, index) => {
|
|
@@ -5979,7 +6223,7 @@ function parseOptionalParams(cls) {
|
|
|
5979
6223
|
}
|
|
5980
6224
|
function parseModifierParams(cls, modifierName) {
|
|
5981
6225
|
const result = new Set;
|
|
5982
|
-
const ctor = cls.members.find(
|
|
6226
|
+
const ctor = cls.members.find(ts4.isConstructorDeclaration);
|
|
5983
6227
|
if (!ctor)
|
|
5984
6228
|
return result;
|
|
5985
6229
|
ctor.parameters.forEach((param, index) => {
|
|
@@ -5991,13 +6235,13 @@ function parseModifierParams(cls, modifierName) {
|
|
|
5991
6235
|
return result;
|
|
5992
6236
|
}
|
|
5993
6237
|
function unwrapForwardRef(expr) {
|
|
5994
|
-
if (
|
|
6238
|
+
if (ts4.isCallExpression(expr)) {
|
|
5995
6239
|
const exprText = nodeText(expr.expression);
|
|
5996
6240
|
if (exprText === "forwardRef" || exprText.endsWith(".forwardRef")) {
|
|
5997
6241
|
const arg = expr.arguments[0];
|
|
5998
|
-
if (arg && (
|
|
6242
|
+
if (arg && (ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg))) {
|
|
5999
6243
|
const body = arg.body;
|
|
6000
|
-
if (body &&
|
|
6244
|
+
if (body && ts4.isExpression(body)) {
|
|
6001
6245
|
return unwrapForwardRef(body);
|
|
6002
6246
|
}
|
|
6003
6247
|
}
|
|
@@ -6007,13 +6251,13 @@ function unwrapForwardRef(expr) {
|
|
|
6007
6251
|
}
|
|
6008
6252
|
function tokenText(expr, ctx) {
|
|
6009
6253
|
const unwrapped = unwrapForwardRef(expr);
|
|
6010
|
-
if (
|
|
6254
|
+
if (ts4.isStringLiteral(unwrapped))
|
|
6011
6255
|
return unwrapped.text;
|
|
6012
|
-
if (
|
|
6256
|
+
if (ts4.isIdentifier(unwrapped)) {
|
|
6013
6257
|
const decl = resolveDeclaration(unwrapped, ctx)[0];
|
|
6014
|
-
if (decl &&
|
|
6258
|
+
if (decl && ts4.isClassDeclaration(decl))
|
|
6015
6259
|
return decl.name?.text ?? unwrapped.text;
|
|
6016
|
-
if (decl &&
|
|
6260
|
+
if (decl && ts4.isVariableDeclaration(decl))
|
|
6017
6261
|
return variableName(decl);
|
|
6018
6262
|
}
|
|
6019
6263
|
return nodeText(unwrapped);
|
|
@@ -6033,12 +6277,12 @@ function resolveScope(input, ctx) {
|
|
|
6033
6277
|
}
|
|
6034
6278
|
function tokenNameOf(expr, ctx) {
|
|
6035
6279
|
const unwrapped = unwrapForwardRef(expr);
|
|
6036
|
-
if (
|
|
6280
|
+
if (ts4.isIdentifier(unwrapped)) {
|
|
6037
6281
|
const decl = resolveDeclaration(unwrapped, ctx)[0];
|
|
6038
|
-
if (decl &&
|
|
6282
|
+
if (decl && ts4.isClassDeclaration(decl)) {
|
|
6039
6283
|
return { name: decl.name?.text ?? nodeText(expr), kind: "class" };
|
|
6040
6284
|
}
|
|
6041
|
-
if (decl &&
|
|
6285
|
+
if (decl && ts4.isVariableDeclaration(decl)) {
|
|
6042
6286
|
const name = variableName(decl);
|
|
6043
6287
|
return { name, kind: ctx.tokensByName.has(name) ? "injection-token" : "class" };
|
|
6044
6288
|
}
|
|
@@ -6054,10 +6298,10 @@ function resolveDeclaration(id, ctx) {
|
|
|
6054
6298
|
return [];
|
|
6055
6299
|
let declarations = symbol.declarations ?? [];
|
|
6056
6300
|
for (let guard = 0;guard < 4; guard += 1) {
|
|
6057
|
-
const isAlias = declarations.some((d) =>
|
|
6301
|
+
const isAlias = declarations.some((d) => ts4.isImportSpecifier(d) || ts4.isImportClause(d) || ts4.isNamespaceImport(d));
|
|
6058
6302
|
if (!isAlias)
|
|
6059
6303
|
break;
|
|
6060
|
-
if (!(symbol.flags &
|
|
6304
|
+
if (!(symbol.flags & ts4.SymbolFlags.Alias))
|
|
6061
6305
|
break;
|
|
6062
6306
|
const aliased = ctx.checker.getAliasedSymbol(symbol);
|
|
6063
6307
|
symbol = aliased;
|
|
@@ -6077,9 +6321,9 @@ function importModuleOf(id, ctx) {
|
|
|
6077
6321
|
for (const declaration of declarations) {
|
|
6078
6322
|
let current = declaration;
|
|
6079
6323
|
while (current) {
|
|
6080
|
-
if (
|
|
6324
|
+
if (ts4.isImportDeclaration(current)) {
|
|
6081
6325
|
const moduleSpecifier = current.moduleSpecifier;
|
|
6082
|
-
return
|
|
6326
|
+
return ts4.isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : undefined;
|
|
6083
6327
|
}
|
|
6084
6328
|
current = current.parent;
|
|
6085
6329
|
}
|
|
@@ -6091,27 +6335,27 @@ function findDecorator(cls, name) {
|
|
|
6091
6335
|
}
|
|
6092
6336
|
function decoratorName2(dec) {
|
|
6093
6337
|
const expr = dec.expression;
|
|
6094
|
-
if (
|
|
6338
|
+
if (ts4.isCallExpression(expr)) {
|
|
6095
6339
|
return nodeText(expr.expression).split(".").pop();
|
|
6096
6340
|
}
|
|
6097
|
-
if (
|
|
6341
|
+
if (ts4.isIdentifier(expr))
|
|
6098
6342
|
return expr.text;
|
|
6099
6343
|
return;
|
|
6100
6344
|
}
|
|
6101
6345
|
function decoratorObjectArg(dec) {
|
|
6102
6346
|
const expr = dec.expression;
|
|
6103
|
-
if (!
|
|
6347
|
+
if (!ts4.isCallExpression(expr))
|
|
6104
6348
|
return;
|
|
6105
6349
|
const arg = expr.arguments[0];
|
|
6106
|
-
return arg &&
|
|
6350
|
+
return arg && ts4.isObjectLiteralExpression(arg) ? arg : undefined;
|
|
6107
6351
|
}
|
|
6108
6352
|
function getProp(obj, name) {
|
|
6109
|
-
const prop = obj.properties.find((item) => (
|
|
6353
|
+
const prop = obj.properties.find((item) => (ts4.isPropertyAssignment(item) || ts4.isShorthandPropertyAssignment(item)) && propertyName(item.name) === name);
|
|
6110
6354
|
if (!prop)
|
|
6111
6355
|
return;
|
|
6112
|
-
if (
|
|
6356
|
+
if (ts4.isPropertyAssignment(prop))
|
|
6113
6357
|
return prop.initializer;
|
|
6114
|
-
if (
|
|
6358
|
+
if (ts4.isShorthandPropertyAssignment(prop))
|
|
6115
6359
|
return prop.name;
|
|
6116
6360
|
return;
|
|
6117
6361
|
}
|
|
@@ -6119,10 +6363,10 @@ function toCompilerDiagnostic(diagnostic, rootDir) {
|
|
|
6119
6363
|
const file = diagnostic.file;
|
|
6120
6364
|
const position = file && diagnostic.start !== undefined ? file.getLineAndCharacterOfPosition(diagnostic.start) : undefined;
|
|
6121
6365
|
return {
|
|
6122
|
-
severity: diagnostic.category ===
|
|
6366
|
+
severity: diagnostic.category === ts4.DiagnosticCategory.Error ? "error" : "warn",
|
|
6123
6367
|
code: `typescript-${diagnostic.code}`,
|
|
6124
6368
|
errorCode: `TS${diagnostic.code}`,
|
|
6125
|
-
message:
|
|
6369
|
+
message: ts4.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
6126
6370
|
`),
|
|
6127
6371
|
...file ? { file: sourcePath(rootDir, file.fileName) } : {},
|
|
6128
6372
|
...position ? { line: position.line + 1 } : {}
|
|
@@ -6130,16 +6374,16 @@ function toCompilerDiagnostic(diagnostic, rootDir) {
|
|
|
6130
6374
|
}
|
|
6131
6375
|
function stringLiteralProp(obj, name) {
|
|
6132
6376
|
const expr = getProp(obj, name);
|
|
6133
|
-
return expr &&
|
|
6377
|
+
return expr && ts4.isStringLiteral(expr) ? expr.text : undefined;
|
|
6134
6378
|
}
|
|
6135
6379
|
function arrayProp(obj, name) {
|
|
6136
6380
|
const expr = getProp(obj, name);
|
|
6137
|
-
return expr &&
|
|
6381
|
+
return expr && ts4.isArrayLiteralExpression(expr) ? [...expr.elements] : [];
|
|
6138
6382
|
}
|
|
6139
6383
|
function parseAspectRefs(expression, ctx, owner) {
|
|
6140
6384
|
if (!expression)
|
|
6141
6385
|
return [];
|
|
6142
|
-
if (!
|
|
6386
|
+
if (!ts4.isArrayLiteralExpression(expression)) {
|
|
6143
6387
|
ctx.diagnostics.push({
|
|
6144
6388
|
severity: "error",
|
|
6145
6389
|
code: "dynamic-aspect-reference",
|
|
@@ -6154,7 +6398,7 @@ function parseAspectRefs(expression, ctx, owner) {
|
|
|
6154
6398
|
}
|
|
6155
6399
|
const refs = [];
|
|
6156
6400
|
for (const element of expression.elements) {
|
|
6157
|
-
if (
|
|
6401
|
+
if (ts4.isSpreadElement(element) || !ts4.isIdentifier(element)) {
|
|
6158
6402
|
ctx.diagnostics.push({
|
|
6159
6403
|
severity: "error",
|
|
6160
6404
|
code: "dynamic-aspect-reference",
|
|
@@ -6167,7 +6411,7 @@ function parseAspectRefs(expression, ctx, owner) {
|
|
|
6167
6411
|
});
|
|
6168
6412
|
continue;
|
|
6169
6413
|
}
|
|
6170
|
-
const declaration = resolveDeclaration(element, ctx).find((candidate) =>
|
|
6414
|
+
const declaration = resolveDeclaration(element, ctx).find((candidate) => ts4.isFunctionDeclaration(candidate) || ts4.isVariableDeclaration(candidate) && candidate.initializer !== undefined && (ts4.isArrowFunction(candidate.initializer) || ts4.isFunctionExpression(candidate.initializer)));
|
|
6171
6415
|
if (!declaration) {
|
|
6172
6416
|
ctx.diagnostics.push({
|
|
6173
6417
|
severity: "error",
|
|
@@ -6181,7 +6425,7 @@ function parseAspectRefs(expression, ctx, owner) {
|
|
|
6181
6425
|
});
|
|
6182
6426
|
continue;
|
|
6183
6427
|
}
|
|
6184
|
-
const name =
|
|
6428
|
+
const name = ts4.isFunctionDeclaration(declaration) ? declaration.name?.text : ts4.isVariableDeclaration(declaration) ? variableName(declaration) : undefined;
|
|
6185
6429
|
if (!name)
|
|
6186
6430
|
continue;
|
|
6187
6431
|
const declaredFile = declaration.getSourceFile().fileName;
|
|
@@ -6201,9 +6445,9 @@ function booleanProp(obj, name) {
|
|
|
6201
6445
|
const expr = getProp(obj, name);
|
|
6202
6446
|
if (!expr)
|
|
6203
6447
|
return;
|
|
6204
|
-
if (expr.kind ===
|
|
6448
|
+
if (expr.kind === ts4.SyntaxKind.TrueKeyword)
|
|
6205
6449
|
return true;
|
|
6206
|
-
if (expr.kind ===
|
|
6450
|
+
if (expr.kind === ts4.SyntaxKind.FalseKeyword)
|
|
6207
6451
|
return false;
|
|
6208
6452
|
return;
|
|
6209
6453
|
}
|
|
@@ -6217,15 +6461,15 @@ function parseBindingOptions(args, defaultName) {
|
|
|
6217
6461
|
let defaultValue;
|
|
6218
6462
|
const first = args[0];
|
|
6219
6463
|
const second = args[1];
|
|
6220
|
-
if (first &&
|
|
6464
|
+
if (first && ts4.isStringLiteral(first)) {
|
|
6221
6465
|
name = first.text;
|
|
6222
|
-
} else if (first &&
|
|
6466
|
+
} else if (first && ts4.isObjectLiteralExpression(first)) {
|
|
6223
6467
|
const nameProp = getProp(first, "name");
|
|
6224
|
-
if (nameProp &&
|
|
6468
|
+
if (nameProp && ts4.isStringLiteral(nameProp)) {
|
|
6225
6469
|
name = nameProp.text;
|
|
6226
6470
|
}
|
|
6227
6471
|
const trProp = getProp(first, "transform");
|
|
6228
|
-
if (trProp &&
|
|
6472
|
+
if (trProp && ts4.isStringLiteral(trProp)) {
|
|
6229
6473
|
const val = trProp.text;
|
|
6230
6474
|
if (val === "number" || val === "boolean" || val === "string") {
|
|
6231
6475
|
transform = val;
|
|
@@ -6236,9 +6480,9 @@ function parseBindingOptions(args, defaultName) {
|
|
|
6236
6480
|
defaultValue = parseLiteralValue(defProp);
|
|
6237
6481
|
}
|
|
6238
6482
|
}
|
|
6239
|
-
if (second &&
|
|
6483
|
+
if (second && ts4.isObjectLiteralExpression(second)) {
|
|
6240
6484
|
const trProp = getProp(second, "transform");
|
|
6241
|
-
if (trProp &&
|
|
6485
|
+
if (trProp && ts4.isStringLiteral(trProp)) {
|
|
6242
6486
|
const val = trProp.text;
|
|
6243
6487
|
if (val === "number" || val === "boolean" || val === "string") {
|
|
6244
6488
|
transform = val;
|
|
@@ -6252,18 +6496,18 @@ function parseBindingOptions(args, defaultName) {
|
|
|
6252
6496
|
return { name, ...transform ? { transform } : {}, default: defaultValue };
|
|
6253
6497
|
}
|
|
6254
6498
|
function parseLiteralValue(node) {
|
|
6255
|
-
if (
|
|
6499
|
+
if (ts4.isStringLiteral(node))
|
|
6256
6500
|
return node.text;
|
|
6257
|
-
if (
|
|
6501
|
+
if (ts4.isNumericLiteral(node))
|
|
6258
6502
|
return Number(node.text);
|
|
6259
|
-
if (node.kind ===
|
|
6503
|
+
if (node.kind === ts4.SyntaxKind.TrueKeyword)
|
|
6260
6504
|
return true;
|
|
6261
|
-
if (node.kind ===
|
|
6505
|
+
if (node.kind === ts4.SyntaxKind.FalseKeyword)
|
|
6262
6506
|
return false;
|
|
6263
|
-
if (
|
|
6507
|
+
if (ts4.isArrayLiteralExpression(node)) {
|
|
6264
6508
|
return node.elements.map(parseLiteralValue);
|
|
6265
6509
|
}
|
|
6266
|
-
if (
|
|
6510
|
+
if (ts4.isObjectLiteralExpression(node)) {
|
|
6267
6511
|
return parseObjectLiteralValues(node);
|
|
6268
6512
|
}
|
|
6269
6513
|
return;
|
|
@@ -6271,7 +6515,7 @@ function parseLiteralValue(node) {
|
|
|
6271
6515
|
function parseObjectLiteralValues(obj) {
|
|
6272
6516
|
const result = {};
|
|
6273
6517
|
for (const prop of obj.properties) {
|
|
6274
|
-
if (
|
|
6518
|
+
if (ts4.isPropertyAssignment(prop)) {
|
|
6275
6519
|
const name = propertyName(prop.name);
|
|
6276
6520
|
const init = prop.initializer;
|
|
6277
6521
|
if (init) {
|
|
@@ -6307,7 +6551,50 @@ import { join as join4 } from "node:path";
|
|
|
6307
6551
|
// src/type-safety.ts
|
|
6308
6552
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
6309
6553
|
import { dirname as dirname3, join as join3, relative as relative3, resolve as resolve2, sep as sep3 } from "node:path";
|
|
6310
|
-
import * as
|
|
6554
|
+
import * as ts6 from "@typescript/typescript6";
|
|
6555
|
+
|
|
6556
|
+
// src/sql-safety.ts
|
|
6557
|
+
import * as ts5 from "@typescript/typescript6";
|
|
6558
|
+
var SQL_SAFETY_DIAGNOSTIC_CODES = {
|
|
6559
|
+
"sql-result-assertion": { errorCode: "SC6007", docsUrl: "https://supacloud.dev/errors/SC6007" },
|
|
6560
|
+
"sql-raw-dynamic": { errorCode: "SC6008", docsUrl: "https://supacloud.dev/errors/SC6008" }
|
|
6561
|
+
};
|
|
6562
|
+
function scanDrizzleSql(sourceFile, checker, file, strict) {
|
|
6563
|
+
const diagnostics = [];
|
|
6564
|
+
const importedSql = (expression) => {
|
|
6565
|
+
const symbol = checker.getSymbolAtLocation(ts5.isPropertyAccessExpression(expression) ? expression.name : expression);
|
|
6566
|
+
if (!symbol)
|
|
6567
|
+
return false;
|
|
6568
|
+
const target = symbol.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
6569
|
+
return target.name === "sql" && (target.declarations ?? []).some((declaration) => /(?:^|\/)node_modules\/drizzle-orm\//.test(declaration.getSourceFile().fileName.replaceAll("\\", "/")));
|
|
6570
|
+
};
|
|
6571
|
+
const report = (code, node, message) => {
|
|
6572
|
+
diagnostics.push({
|
|
6573
|
+
severity: strict ? "error" : "warn",
|
|
6574
|
+
code,
|
|
6575
|
+
...SQL_SAFETY_DIAGNOSTIC_CODES[code],
|
|
6576
|
+
message,
|
|
6577
|
+
file,
|
|
6578
|
+
line: sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1
|
|
6579
|
+
});
|
|
6580
|
+
};
|
|
6581
|
+
const visit = (node) => {
|
|
6582
|
+
if (ts5.isTaggedTemplateExpression(node) && importedSql(node.tag) && node.typeArguments?.some((type) => type.kind !== ts5.SyntaxKind.UnknownKeyword)) {
|
|
6583
|
+
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.");
|
|
6584
|
+
}
|
|
6585
|
+
if (ts5.isCallExpression(node) && ts5.isPropertyAccessExpression(node.expression) && node.expression.name.text === "raw" && importedSql(node.expression.expression)) {
|
|
6586
|
+
const argument = node.arguments[0];
|
|
6587
|
+
if (!argument || !ts5.isStringLiteral(argument) && !ts5.isNoSubstitutionTemplateLiteral(argument)) {
|
|
6588
|
+
report("sql-raw-dynamic", node, "Dynamic sql.raw bypasses parameter binding. Interpolate values with sql templates; keep reviewed static DDL in migrations.");
|
|
6589
|
+
}
|
|
6590
|
+
}
|
|
6591
|
+
ts5.forEachChild(node, visit);
|
|
6592
|
+
};
|
|
6593
|
+
visit(sourceFile);
|
|
6594
|
+
return diagnostics;
|
|
6595
|
+
}
|
|
6596
|
+
|
|
6597
|
+
// src/type-safety.ts
|
|
6311
6598
|
var DEFAULT_EXCLUDES = [
|
|
6312
6599
|
"**/*.test.ts",
|
|
6313
6600
|
"**/*.spec.ts",
|
|
@@ -6320,6 +6607,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
6320
6607
|
"**/*.d.ts"
|
|
6321
6608
|
];
|
|
6322
6609
|
var TYPE_SAFETY_DIAGNOSTIC_CODES = {
|
|
6610
|
+
...SQL_SAFETY_DIAGNOSTIC_CODES,
|
|
6323
6611
|
"generated-any": { errorCode: "SC6001", docsUrl: "https://supacloud.dev/errors/SC6001" },
|
|
6324
6612
|
"source-any": { errorCode: "SC6002", docsUrl: "https://supacloud.dev/errors/SC6002" },
|
|
6325
6613
|
"source-type-assertion": { errorCode: "SC6003", docsUrl: "https://supacloud.dev/errors/SC6003" },
|
|
@@ -6332,7 +6620,7 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
6332
6620
|
for (const [file, content] of Object.entries(artifacts)) {
|
|
6333
6621
|
if (content === undefined)
|
|
6334
6622
|
continue;
|
|
6335
|
-
const sourceFile =
|
|
6623
|
+
const sourceFile = ts6.createSourceFile(file, content, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TS);
|
|
6336
6624
|
for (const node of descendantsOfKind2(sourceFile, isAnyKeyword)) {
|
|
6337
6625
|
diagnostics.push(makeDiagnostic("generated-any", `生成产物 ${file} 包含 any;严格生成模式要求使用 unknown、具体接口或泛型约束。`, sourceFile, node, strict));
|
|
6338
6626
|
}
|
|
@@ -6341,30 +6629,30 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
6341
6629
|
}
|
|
6342
6630
|
function scanProductionSource(options) {
|
|
6343
6631
|
const rootDir = resolve2(options.rootDir);
|
|
6344
|
-
const configPath =
|
|
6632
|
+
const configPath = ts6.findConfigFile(rootDir, ts6.sys.fileExists) ?? join3(rootDir, "tsconfig.json");
|
|
6345
6633
|
const projectConfig = existsSync2(configPath) ? readProjectConfig2(configPath) : {
|
|
6346
6634
|
options: {
|
|
6347
6635
|
strict: true,
|
|
6348
6636
|
skipLibCheck: true,
|
|
6349
|
-
target:
|
|
6350
|
-
module:
|
|
6351
|
-
moduleResolution:
|
|
6637
|
+
target: ts6.ScriptTarget.ES2022,
|
|
6638
|
+
module: ts6.ModuleKind.ESNext,
|
|
6639
|
+
moduleResolution: ts6.ModuleResolutionKind.Bundler
|
|
6352
6640
|
},
|
|
6353
6641
|
errors: []
|
|
6354
6642
|
};
|
|
6355
6643
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
6356
|
-
const rootNames =
|
|
6644
|
+
const rootNames = ts6.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist"], include).filter((file) => isProductionSourcePath(rootDir, file, [...DEFAULT_EXCLUDES, ...options.exclude ?? []]));
|
|
6357
6645
|
const compilerOptions = { ...projectConfig.options, noEmit: true };
|
|
6358
|
-
const host =
|
|
6646
|
+
const host = ts6.createCompilerHost(compilerOptions);
|
|
6359
6647
|
host.getCurrentDirectory = () => dirname3(configPath);
|
|
6360
|
-
const program =
|
|
6648
|
+
const program = ts6.createProgram(rootNames, compilerOptions, host);
|
|
6361
6649
|
const outDir = options.outDir ? normalizeRelative(rootDir, options.outDir) : undefined;
|
|
6362
6650
|
const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
|
|
6363
6651
|
const sourceFiles = program.getSourceFiles().filter((sourceFile) => isProductionSource(rootDir, sourceFile, excludes, outDir));
|
|
6364
6652
|
const diagnostics = [...projectConfig.errors, ...program.getOptionsDiagnostics()].map((diagnostic) => ({
|
|
6365
6653
|
severity: "error",
|
|
6366
6654
|
code: "source-config",
|
|
6367
|
-
message:
|
|
6655
|
+
message: ts6.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
6368
6656
|
`),
|
|
6369
6657
|
file: diagnostic.file ? normalizeRelative(rootDir, diagnostic.file.fileName) : normalizeRelative(rootDir, configPath),
|
|
6370
6658
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
@@ -6381,7 +6669,7 @@ function scanProductionSource(options) {
|
|
|
6381
6669
|
diagnostics.push({
|
|
6382
6670
|
severity: "error",
|
|
6383
6671
|
code: "source-typescript",
|
|
6384
|
-
message:
|
|
6672
|
+
message: ts6.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
6385
6673
|
`),
|
|
6386
6674
|
...diagnostic.file ? { file: normalizeRelative(rootDir, diagnostic.file.fileName) } : {},
|
|
6387
6675
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
@@ -6390,9 +6678,10 @@ function scanProductionSource(options) {
|
|
|
6390
6678
|
}
|
|
6391
6679
|
for (const sourceFile of sourceFiles) {
|
|
6392
6680
|
scanSourceFile(sourceFile, checker, rootDir, diagnostics, options.strict ?? false);
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6681
|
+
diagnostics.push(...scanDrizzleSql(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), options.strict ?? false));
|
|
6682
|
+
const scanner = ts6.createScanner(ts6.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
|
|
6683
|
+
for (let kind = scanner.scan();kind !== ts6.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
|
|
6684
|
+
if ((kind === ts6.SyntaxKind.SingleLineCommentTrivia || kind === ts6.SyntaxKind.MultiLineCommentTrivia) && /@ts-(?:ignore|nocheck|expect-error)\b/.test(scanner.getTokenText())) {
|
|
6396
6685
|
diagnostics.push({
|
|
6397
6686
|
severity: "error",
|
|
6398
6687
|
code: "source-type-suppression",
|
|
@@ -6412,22 +6701,22 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
6412
6701
|
diagnostics.push(makeDiagnostic("source-any", "生产源码使用了显式 any;请改用 unknown、具体接口或泛型约束。", sourceFile, node, strict, rootDir));
|
|
6413
6702
|
}
|
|
6414
6703
|
for (const node of descendants(sourceFile)) {
|
|
6415
|
-
if (
|
|
6416
|
-
if (
|
|
6704
|
+
if (ts6.isAsExpression(node)) {
|
|
6705
|
+
if (ts6.isAsExpression(node.parent) || ts6.isTypeAssertionExpression(node.parent))
|
|
6417
6706
|
continue;
|
|
6418
6707
|
const assertedType = node.type.getText(sourceFile);
|
|
6419
6708
|
if (assertedType === "const")
|
|
6420
6709
|
continue;
|
|
6421
6710
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
6422
|
-
} else if (
|
|
6423
|
-
if (
|
|
6711
|
+
} else if (ts6.isTypeAssertionExpression(node)) {
|
|
6712
|
+
if (ts6.isAsExpression(node.parent) || ts6.isTypeAssertionExpression(node.parent))
|
|
6424
6713
|
continue;
|
|
6425
6714
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
6426
|
-
} else if (
|
|
6715
|
+
} else if (ts6.isNonNullExpression(node)) {
|
|
6427
6716
|
diagnostics.push(makeDiagnostic("source-non-null-assertion", `生产源码包含非空断言 ${node.getText(sourceFile)};请显式处理 null/undefined。`, sourceFile, node, strict, rootDir));
|
|
6428
6717
|
}
|
|
6429
6718
|
}
|
|
6430
|
-
for (const declaration of descendantsOfKind2(sourceFile,
|
|
6719
|
+
for (const declaration of descendantsOfKind2(sourceFile, ts6.isVariableDeclaration)) {
|
|
6431
6720
|
const initializer = declaration.initializer;
|
|
6432
6721
|
if (!initializer || declaration.type)
|
|
6433
6722
|
continue;
|
|
@@ -6443,11 +6732,11 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
6443
6732
|
if (isLetDeclaration(declaration) && isLiteralSyntax(initializer) && !isLiteralType(declarationType)) {
|
|
6444
6733
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `变量 ${declaration.name.getText(sourceFile)} 的字面量类型从 ${checker.typeToString(initializerType, initializer)} 隐式宽化为 ${checker.typeToString(declarationType, declaration)};请补充类型或使用 const。`, sourceFile, declaration, strict, rootDir));
|
|
6445
6734
|
}
|
|
6446
|
-
if (
|
|
6735
|
+
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))) {
|
|
6447
6736
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `常量对象 ${declaration.name.getText(sourceFile)} 的字面量属性会隐式宽化;请补充对象类型或使用 as const。`, sourceFile, declaration, strict, rootDir));
|
|
6448
6737
|
}
|
|
6449
6738
|
}
|
|
6450
|
-
for (const parameter of descendantsOfKind2(sourceFile,
|
|
6739
|
+
for (const parameter of descendantsOfKind2(sourceFile, ts6.isParameter)) {
|
|
6451
6740
|
if (parameter.type)
|
|
6452
6741
|
continue;
|
|
6453
6742
|
for (const name of bindingNames(parameter.name)) {
|
|
@@ -6458,10 +6747,10 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
6458
6747
|
}
|
|
6459
6748
|
}
|
|
6460
6749
|
function readProjectConfig2(configPath) {
|
|
6461
|
-
const config =
|
|
6750
|
+
const config = ts6.readConfigFile(configPath, (file) => readFileSync2(file, "utf8"));
|
|
6462
6751
|
if (config.error)
|
|
6463
6752
|
return { options: {}, errors: [config.error] };
|
|
6464
|
-
const parsed =
|
|
6753
|
+
const parsed = ts6.parseJsonConfigFileContent(config.config, ts6.sys, dirname3(configPath));
|
|
6465
6754
|
return { options: parsed.options, errors: parsed.errors };
|
|
6466
6755
|
}
|
|
6467
6756
|
function isProductionSource(rootDir, sourceFile, excludes, outDir) {
|
|
@@ -6481,42 +6770,42 @@ function globMatches(value, pattern) {
|
|
|
6481
6770
|
return new RegExp(`^${escaped}$`).test(value);
|
|
6482
6771
|
}
|
|
6483
6772
|
function bindingNames(name) {
|
|
6484
|
-
if (
|
|
6773
|
+
if (ts6.isIdentifier(name))
|
|
6485
6774
|
return [name];
|
|
6486
|
-
return name.elements.flatMap((element) =>
|
|
6775
|
+
return name.elements.flatMap((element) => ts6.isBindingElement(element) ? bindingNames(element.name) : []);
|
|
6487
6776
|
}
|
|
6488
6777
|
function isLiteralExpression(node) {
|
|
6489
6778
|
if (!node)
|
|
6490
6779
|
return false;
|
|
6491
6780
|
return [
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6781
|
+
ts6.SyntaxKind.StringLiteral,
|
|
6782
|
+
ts6.SyntaxKind.NumericLiteral,
|
|
6783
|
+
ts6.SyntaxKind.TrueKeyword,
|
|
6784
|
+
ts6.SyntaxKind.FalseKeyword
|
|
6496
6785
|
].includes(node.kind);
|
|
6497
6786
|
}
|
|
6498
6787
|
function isLiteralSyntax(node) {
|
|
6499
|
-
return
|
|
6788
|
+
return ts6.isStringLiteral(node) || ts6.isNumericLiteral(node) || node.kind === ts6.SyntaxKind.TrueKeyword || node.kind === ts6.SyntaxKind.FalseKeyword;
|
|
6500
6789
|
}
|
|
6501
6790
|
function isLiteralType(type) {
|
|
6502
|
-
return (type.flags & (
|
|
6791
|
+
return (type.flags & (ts6.TypeFlags.StringLiteral | ts6.TypeFlags.NumberLiteral | ts6.TypeFlags.BooleanLiteral | ts6.TypeFlags.BigIntLiteral)) !== 0;
|
|
6503
6792
|
}
|
|
6504
6793
|
function isAnyType(type) {
|
|
6505
|
-
return (type.flags &
|
|
6794
|
+
return (type.flags & ts6.TypeFlags.Any) !== 0;
|
|
6506
6795
|
}
|
|
6507
6796
|
function isLetDeclaration(declaration) {
|
|
6508
|
-
return
|
|
6797
|
+
return ts6.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts6.NodeFlags.Let) !== 0;
|
|
6509
6798
|
}
|
|
6510
6799
|
function isConstDeclaration(declaration) {
|
|
6511
|
-
return
|
|
6800
|
+
return ts6.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts6.NodeFlags.Const) !== 0;
|
|
6512
6801
|
}
|
|
6513
6802
|
function descendants(root) {
|
|
6514
6803
|
const result = [];
|
|
6515
6804
|
const visit = (node) => {
|
|
6516
6805
|
result.push(node);
|
|
6517
|
-
|
|
6806
|
+
ts6.forEachChild(node, visit);
|
|
6518
6807
|
};
|
|
6519
|
-
|
|
6808
|
+
ts6.forEachChild(root, visit);
|
|
6520
6809
|
return result;
|
|
6521
6810
|
}
|
|
6522
6811
|
function descendantsOfKind2(root, predicate) {
|
|
@@ -6524,9 +6813,9 @@ function descendantsOfKind2(root, predicate) {
|
|
|
6524
6813
|
const visit = (node) => {
|
|
6525
6814
|
if (predicate(node))
|
|
6526
6815
|
result.push(node);
|
|
6527
|
-
|
|
6816
|
+
ts6.forEachChild(node, visit);
|
|
6528
6817
|
};
|
|
6529
|
-
|
|
6818
|
+
ts6.forEachChild(root, visit);
|
|
6530
6819
|
return result;
|
|
6531
6820
|
}
|
|
6532
6821
|
function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir) {
|
|
@@ -6547,7 +6836,7 @@ function normalizeRelative(rootDir, filePath) {
|
|
|
6547
6836
|
return relative3(rootDir, filePath).split(sep3).join("/").replace(/^\.\//, "");
|
|
6548
6837
|
}
|
|
6549
6838
|
function isAnyKeyword(node) {
|
|
6550
|
-
return node.kind ===
|
|
6839
|
+
return node.kind === ts6.SyntaxKind.AnyKeyword;
|
|
6551
6840
|
}
|
|
6552
6841
|
|
|
6553
6842
|
// src/route-contracts.ts
|
|
@@ -6640,6 +6929,9 @@ async function compileProject(options) {
|
|
|
6640
6929
|
...graph.diagnostics ?? [],
|
|
6641
6930
|
...validateGraph(graph, options)
|
|
6642
6931
|
];
|
|
6932
|
+
if (diagnostics.some((item) => item.code === "runtime-injection-disallowed")) {
|
|
6933
|
+
return { diagnostics, graph, written: [] };
|
|
6934
|
+
}
|
|
6643
6935
|
if (options.strict) {
|
|
6644
6936
|
for (const diagnostic of diagnostics) {
|
|
6645
6937
|
if (diagnostic.severity === "warn")
|
|
@@ -6698,6 +6990,9 @@ async function checkProject(options) {
|
|
|
6698
6990
|
...graph.diagnostics ?? [],
|
|
6699
6991
|
...validateGraph(graph, options)
|
|
6700
6992
|
];
|
|
6993
|
+
if (diagnostics.some((item) => item.code === "runtime-injection-disallowed")) {
|
|
6994
|
+
return { diagnostics, graph, upToDate: false, mismatches: ["Runtime DI must be migrated to constructor injection."] };
|
|
6995
|
+
}
|
|
6701
6996
|
if (options.strict) {
|
|
6702
6997
|
for (const diagnostic of diagnostics) {
|
|
6703
6998
|
if (diagnostic.severity === "warn")
|
|
@@ -10248,7 +10543,7 @@ function formatDeliveryPlan(result) {
|
|
|
10248
10543
|
import { mkdir as mkdir3, mkdtemp, readFile as readFile5, realpath as realpath2, rename as rename3, rm as rm2 } from "node:fs/promises";
|
|
10249
10544
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
10250
10545
|
import { dirname as dirname5, join as join6, relative as relative6, resolve as resolve7, sep as sep6 } from "node:path";
|
|
10251
|
-
import * as
|
|
10546
|
+
import * as ts10 from "@typescript/typescript6";
|
|
10252
10547
|
|
|
10253
10548
|
// src/delivery-files.ts
|
|
10254
10549
|
import { createHash as createHash7 } from "node:crypto";
|
|
@@ -10482,19 +10777,19 @@ function renderDeliveryTarget(graph, target, options) {
|
|
|
10482
10777
|
import { isBuiltin } from "node:module";
|
|
10483
10778
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
10484
10779
|
import { resolve as resolve6 } from "node:path";
|
|
10485
|
-
import * as
|
|
10780
|
+
import * as ts9 from "@typescript/typescript6";
|
|
10486
10781
|
function checkStaticImports(path, contents) {
|
|
10487
10782
|
if (!/\.[cm]?[jt]sx?$/.test(path))
|
|
10488
10783
|
return;
|
|
10489
|
-
const source =
|
|
10784
|
+
const source = ts9.createSourceFile(path, new TextDecoder().decode(contents), ts9.ScriptTarget.Latest, true);
|
|
10490
10785
|
function visit(node) {
|
|
10491
|
-
if (
|
|
10786
|
+
if (ts9.isCallExpression(node) && (node.expression.kind === ts9.SyntaxKind.ImportKeyword || ts9.isIdentifier(node.expression) && node.expression.text === "require")) {
|
|
10492
10787
|
const argument = node.arguments[0];
|
|
10493
|
-
if (!argument || !
|
|
10788
|
+
if (!argument || !ts9.isStringLiteral(argument) && !ts9.isNoSubstitutionTemplateLiteral(argument)) {
|
|
10494
10789
|
throw new Error("Computed module loading is not supported in independent delivery bundles.");
|
|
10495
10790
|
}
|
|
10496
10791
|
}
|
|
10497
|
-
|
|
10792
|
+
ts9.forEachChild(node, visit);
|
|
10498
10793
|
}
|
|
10499
10794
|
visit(source);
|
|
10500
10795
|
}
|
|
@@ -10583,7 +10878,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
10583
10878
|
const settings = parseDeliveryOptions(delivery);
|
|
10584
10879
|
if (typeof Bun === "undefined")
|
|
10585
10880
|
throw new Error("Independent delivery builds require Bun.");
|
|
10586
|
-
const configPath =
|
|
10881
|
+
const configPath = ts10.findConfigFile(resolve7(options.rootDir), ts10.sys.fileExists);
|
|
10587
10882
|
if (!configPath)
|
|
10588
10883
|
throw new Error("Independent delivery builds require a project tsconfig.json.");
|
|
10589
10884
|
const lexicalProject = dirname5(configPath);
|
|
@@ -10599,8 +10894,8 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
10599
10894
|
if (inside(generatedRoot, sourceRoot))
|
|
10600
10895
|
throw new Error("Output must not contain the application source root.");
|
|
10601
10896
|
const configInputs = new Map;
|
|
10602
|
-
const parsedConfig =
|
|
10603
|
-
...
|
|
10897
|
+
const parsedConfig = ts10.getParsedCommandLineOfConfigFile(await realpath2(configPath), {}, {
|
|
10898
|
+
...ts10.sys,
|
|
10604
10899
|
readFile(path) {
|
|
10605
10900
|
const contents = readFileSync3(path, "utf8");
|
|
10606
10901
|
configInputs.set(resolve7(path), digest(contents));
|
|
@@ -10686,7 +10981,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
10686
10981
|
for (const [name, contents] of Object.entries(generated))
|
|
10687
10982
|
await writeArtifact(stage, `generated/${name}`, contents);
|
|
10688
10983
|
{
|
|
10689
|
-
const program =
|
|
10984
|
+
const program = ts10.createProgram({
|
|
10690
10985
|
rootNames: [
|
|
10691
10986
|
...parsedConfig.fileNames.filter((path) => !inside(generatedRoot, path)),
|
|
10692
10987
|
...Object.keys(generated).map((name) => join6(stage, "generated", name))
|
|
@@ -10694,12 +10989,12 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
10694
10989
|
options: { ...parsedConfig.options, rootDir: project },
|
|
10695
10990
|
...parsedConfig.projectReferences ? { projectReferences: parsedConfig.projectReferences } : {}
|
|
10696
10991
|
});
|
|
10697
|
-
const diagnostics =
|
|
10698
|
-
if (diagnostics.some((item) => item.category ===
|
|
10699
|
-
return failed(diagnostics.filter((item) => item.category ===
|
|
10992
|
+
const diagnostics = ts10.getPreEmitDiagnostics(program);
|
|
10993
|
+
if (diagnostics.some((item) => item.category === ts10.DiagnosticCategory.Error)) {
|
|
10994
|
+
return failed(diagnostics.filter((item) => item.category === ts10.DiagnosticCategory.Error).map((item) => ({
|
|
10700
10995
|
severity: "error",
|
|
10701
10996
|
code: "delivery-generated-type-error",
|
|
10702
|
-
message:
|
|
10997
|
+
message: ts10.flattenDiagnosticMessageText(item.messageText, `
|
|
10703
10998
|
`),
|
|
10704
10999
|
...item.file ? { file: item.file.fileName } : {}
|
|
10705
11000
|
})));
|
|
@@ -10831,7 +11126,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
10831
11126
|
import { randomUUID } from "node:crypto";
|
|
10832
11127
|
import { lstat as lstat2, readFile as readFile6, realpath as realpath3, rename as rename4, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
10833
11128
|
import { dirname as dirname6, isAbsolute as isAbsolute2, relative as relative7, resolve as resolve8, sep as sep7 } from "node:path";
|
|
10834
|
-
import * as
|
|
11129
|
+
import * as ts11 from "@typescript/typescript6";
|
|
10835
11130
|
async function applyDiagnosticFix(fix, options = {}) {
|
|
10836
11131
|
if (!fix || typeof fix.targetFile !== "string")
|
|
10837
11132
|
throw new Error("Invalid DiagnosticFix");
|
|
@@ -10856,7 +11151,7 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
10856
11151
|
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
10857
11152
|
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
10858
11153
|
}
|
|
10859
|
-
content = replaceProperty(source, object, fix.property,
|
|
11154
|
+
content = replaceProperty(source, object, fix.property, ts11.factory.createStringLiteral(fix.value));
|
|
10860
11155
|
break;
|
|
10861
11156
|
}
|
|
10862
11157
|
case "add_module_import": {
|
|
@@ -10867,15 +11162,15 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
10867
11162
|
source = parse3(file, withImport);
|
|
10868
11163
|
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
10869
11164
|
const imports = property(object, "imports");
|
|
10870
|
-
if (imports && !
|
|
11165
|
+
if (imports && !ts11.isArrayLiteralExpression(imports.initializer)) {
|
|
10871
11166
|
throw new Error("Module imports must be a static array");
|
|
10872
11167
|
}
|
|
10873
|
-
const values = imports &&
|
|
10874
|
-
if (values.some(
|
|
11168
|
+
const values = imports && ts11.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
11169
|
+
if (values.some(ts11.isSpreadElement))
|
|
10875
11170
|
throw new Error("Module imports cannot contain spread elements");
|
|
10876
|
-
content = values.some((value) =>
|
|
11171
|
+
content = values.some((value) => ts11.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts11.factory.createArrayLiteralExpression([
|
|
10877
11172
|
...values,
|
|
10878
|
-
|
|
11173
|
+
ts11.factory.createIdentifier(fix.symbol)
|
|
10879
11174
|
]));
|
|
10880
11175
|
break;
|
|
10881
11176
|
}
|
|
@@ -10887,24 +11182,24 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
10887
11182
|
const command = findClass(source, fix.command);
|
|
10888
11183
|
const object = decoratorObject(command, "Command");
|
|
10889
11184
|
const current = property(object, "permission");
|
|
10890
|
-
if (current && (!
|
|
11185
|
+
if (current && (!ts11.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
10891
11186
|
throw new Error("Command permission already exists with a different value");
|
|
10892
11187
|
}
|
|
10893
|
-
content = current ? original : replaceProperty(source, object, "permission",
|
|
11188
|
+
content = current ? original : replaceProperty(source, object, "permission", ts11.factory.createStringLiteral(permission));
|
|
10894
11189
|
break;
|
|
10895
11190
|
}
|
|
10896
11191
|
case "add_route_parameter_binding": {
|
|
10897
11192
|
const controller = findClass(source, fix.controller);
|
|
10898
|
-
const method = unique(controller.members.filter((member) =>
|
|
10899
|
-
const parameter = unique(method.parameters.filter((candidate) =>
|
|
11193
|
+
const method = unique(controller.members.filter((member) => ts11.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
|
|
11194
|
+
const parameter = unique(method.parameters.filter((candidate) => ts11.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
|
|
10900
11195
|
const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
|
|
10901
11196
|
if (!binding)
|
|
10902
11197
|
throw new Error("Invalid route binding");
|
|
10903
|
-
const decorators =
|
|
11198
|
+
const decorators = ts11.getDecorators(parameter) ?? [];
|
|
10904
11199
|
if (decorators.length > 0)
|
|
10905
11200
|
throw new Error("Parameter already has a decorator");
|
|
10906
|
-
const framework = unique(source.statements.filter((statement) =>
|
|
10907
|
-
if (!
|
|
11201
|
+
const framework = unique(source.statements.filter((statement) => ts11.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts11.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
|
|
11202
|
+
if (!ts11.isImportDeclaration(framework) || !ts11.isStringLiteral(framework.moduleSpecifier)) {
|
|
10908
11203
|
throw new Error("Framework import must be static");
|
|
10909
11204
|
}
|
|
10910
11205
|
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
@@ -10930,15 +11225,15 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
10930
11225
|
return result;
|
|
10931
11226
|
}
|
|
10932
11227
|
function parse3(file, text) {
|
|
10933
|
-
const result =
|
|
11228
|
+
const result = ts11.transpileModule(text, {
|
|
10934
11229
|
fileName: file,
|
|
10935
11230
|
reportDiagnostics: true,
|
|
10936
|
-
compilerOptions: { target:
|
|
11231
|
+
compilerOptions: { target: ts11.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
10937
11232
|
});
|
|
10938
|
-
if (result.diagnostics?.some((item) => item.category ===
|
|
11233
|
+
if (result.diagnostics?.some((item) => item.category === ts11.DiagnosticCategory.Error)) {
|
|
10939
11234
|
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
10940
11235
|
}
|
|
10941
|
-
return
|
|
11236
|
+
return ts11.createSourceFile(file, text, ts11.ScriptTarget.Latest, true, ts11.ScriptKind.TS);
|
|
10942
11237
|
}
|
|
10943
11238
|
function unique(items, description) {
|
|
10944
11239
|
if (items.length !== 1)
|
|
@@ -10952,50 +11247,50 @@ function identifier(value) {
|
|
|
10952
11247
|
function nameOf(name) {
|
|
10953
11248
|
if (!name)
|
|
10954
11249
|
return "";
|
|
10955
|
-
return
|
|
11250
|
+
return ts11.isIdentifier(name) || ts11.isStringLiteral(name) || ts11.isNumericLiteral(name) ? name.text : "";
|
|
10956
11251
|
}
|
|
10957
11252
|
function property(object, key) {
|
|
10958
|
-
if (object.properties.some((item) => !
|
|
11253
|
+
if (object.properties.some((item) => !ts11.isPropertyAssignment(item) || ts11.isComputedPropertyName(item.name))) {
|
|
10959
11254
|
throw new Error("Fix requires explicit static object properties");
|
|
10960
11255
|
}
|
|
10961
|
-
const values = object.properties.filter((item) =>
|
|
11256
|
+
const values = object.properties.filter((item) => ts11.isPropertyAssignment(item) && nameOf(item.name) === key);
|
|
10962
11257
|
if (values.length > 1)
|
|
10963
11258
|
throw new Error(`Duplicate '${key}' property`);
|
|
10964
11259
|
return values[0];
|
|
10965
11260
|
}
|
|
10966
11261
|
function stringProperty(object, key) {
|
|
10967
11262
|
const value = property(object, key)?.initializer;
|
|
10968
|
-
return value &&
|
|
11263
|
+
return value && ts11.isStringLiteral(value) ? value.text : undefined;
|
|
10969
11264
|
}
|
|
10970
11265
|
function replaceProperty(source, object, key, value) {
|
|
10971
11266
|
const previous = property(object, key);
|
|
10972
|
-
const replacement =
|
|
11267
|
+
const replacement = ts11.factory.createPropertyAssignment(key, value);
|
|
10973
11268
|
const properties = object.properties.map((item) => item === previous ? replacement : item);
|
|
10974
11269
|
if (!previous)
|
|
10975
11270
|
properties.push(replacement);
|
|
10976
|
-
const updated =
|
|
10977
|
-
return source.text.slice(0, object.getStart(source)) +
|
|
11271
|
+
const updated = ts11.factory.updateObjectLiteralExpression(object, properties);
|
|
11272
|
+
return source.text.slice(0, object.getStart(source)) + ts11.createPrinter().printNode(ts11.EmitHint.Expression, updated, source) + source.text.slice(object.end);
|
|
10978
11273
|
}
|
|
10979
11274
|
function findClass(source, name) {
|
|
10980
|
-
return unique(source.statements.filter((statement) =>
|
|
11275
|
+
return unique(source.statements.filter((statement) => ts11.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
10981
11276
|
}
|
|
10982
11277
|
function decoratorObject(node, name) {
|
|
10983
|
-
const decorator = unique((
|
|
10984
|
-
const argument =
|
|
10985
|
-
if (!argument || !
|
|
11278
|
+
const decorator = unique((ts11.getDecorators(node) ?? []).filter((item) => ts11.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
|
|
11279
|
+
const argument = ts11.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
|
|
11280
|
+
if (!argument || !ts11.isObjectLiteralExpression(argument))
|
|
10986
11281
|
throw new Error(`@${name} requires a static object`);
|
|
10987
11282
|
return argument;
|
|
10988
11283
|
}
|
|
10989
11284
|
function moduleObjects(source) {
|
|
10990
11285
|
const result = [];
|
|
10991
11286
|
for (const statement of source.statements) {
|
|
10992
|
-
if (
|
|
11287
|
+
if (ts11.isClassDeclaration(statement) && (ts11.getDecorators(statement) ?? []).some((item) => ts11.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
|
|
10993
11288
|
result.push(decoratorObject(statement, "Module"));
|
|
10994
11289
|
}
|
|
10995
|
-
if (
|
|
11290
|
+
if (ts11.isVariableStatement(statement)) {
|
|
10996
11291
|
for (const declaration of statement.declarationList.declarations) {
|
|
10997
11292
|
const call = declaration.initializer;
|
|
10998
|
-
if (call &&
|
|
11293
|
+
if (call && ts11.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts11.isObjectLiteralExpression(call.arguments[0])) {
|
|
10999
11294
|
result.push(call.arguments[0]);
|
|
11000
11295
|
}
|
|
11001
11296
|
}
|
|
@@ -11009,19 +11304,19 @@ function importSymbol(source, path, symbol) {
|
|
|
11009
11304
|
const target = resolve8(dirname6(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
11010
11305
|
if (current === target)
|
|
11011
11306
|
return source.text;
|
|
11012
|
-
const matches = source.statements.filter((item) =>
|
|
11307
|
+
const matches = source.statements.filter((item) => ts11.isImportDeclaration(item) && ts11.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
|
|
11013
11308
|
if (matches.length > 1)
|
|
11014
11309
|
throw new Error(`Ambiguous imports from '${path}'`);
|
|
11015
11310
|
const match = matches[0];
|
|
11016
|
-
if (match &&
|
|
11311
|
+
if (match && ts11.isImportDeclaration(match) && match.importClause?.namedBindings && ts11.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
|
|
11017
11312
|
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
11018
11313
|
return source.text;
|
|
11019
11314
|
const bindings = match.importClause.namedBindings;
|
|
11020
|
-
const updated =
|
|
11315
|
+
const updated = ts11.factory.updateNamedImports(bindings, [
|
|
11021
11316
|
...bindings.elements,
|
|
11022
|
-
|
|
11317
|
+
ts11.factory.createImportSpecifier(false, undefined, ts11.factory.createIdentifier(symbol))
|
|
11023
11318
|
]);
|
|
11024
|
-
return source.text.slice(0, bindings.getStart(source)) +
|
|
11319
|
+
return source.text.slice(0, bindings.getStart(source)) + ts11.createPrinter().printNode(ts11.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
|
|
11025
11320
|
}
|
|
11026
11321
|
if (match)
|
|
11027
11322
|
throw new Error(`Import from '${path}' is not a named value import`);
|
|
@@ -11436,29 +11731,35 @@ function watchProject(options) {
|
|
|
11436
11731
|
// src/migrations.ts
|
|
11437
11732
|
import { rename as rename5, readFile as readFile9, writeFile as writeFile4, rm as rm3 } from "node:fs/promises";
|
|
11438
11733
|
import { relative as relative10, resolve as resolve12 } from "node:path";
|
|
11439
|
-
import * as
|
|
11734
|
+
import * as ts12 from "@typescript/typescript6";
|
|
11440
11735
|
|
|
11441
11736
|
// src/migration-policy.ts
|
|
11442
11737
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
11443
11738
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
11444
11739
|
import { resolve as resolve11 } from "node:path";
|
|
11740
|
+
var cachedCompilerVersion;
|
|
11445
11741
|
function compilerVersion() {
|
|
11742
|
+
if (cachedCompilerVersion !== undefined)
|
|
11743
|
+
return cachedCompilerVersion;
|
|
11446
11744
|
const manifest = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8"));
|
|
11447
11745
|
if (!manifest || typeof manifest !== "object" || !("version" in manifest) || typeof manifest.version !== "string") {
|
|
11448
11746
|
throw new Error("Cannot determine executing compiler version");
|
|
11449
11747
|
}
|
|
11450
|
-
|
|
11748
|
+
cachedCompilerVersion = manifest.version;
|
|
11749
|
+
return cachedCompilerVersion;
|
|
11750
|
+
}
|
|
11751
|
+
function migrationDependencies() {
|
|
11752
|
+
return {
|
|
11753
|
+
"@supacloud/app": "0.14.0",
|
|
11754
|
+
"@supacloud/compiler": compilerVersion(),
|
|
11755
|
+
"@supacloud/elysia": "0.17.0",
|
|
11756
|
+
elysia: "1.4.30",
|
|
11757
|
+
typescript: "7.0.2"
|
|
11758
|
+
};
|
|
11451
11759
|
}
|
|
11452
|
-
var migrationDependencies = {
|
|
11453
|
-
"@supacloud/app": "0.14.0",
|
|
11454
|
-
"@supacloud/compiler": compilerVersion(),
|
|
11455
|
-
"@supacloud/elysia": "0.16.0",
|
|
11456
|
-
elysia: "1.4.30",
|
|
11457
|
-
typescript: "7.0.2"
|
|
11458
|
-
};
|
|
11459
11760
|
async function checkMigrationDependencies(rootDir) {
|
|
11460
11761
|
const problems = [];
|
|
11461
|
-
for (const [name, expected] of Object.entries(migrationDependencies)) {
|
|
11762
|
+
for (const [name, expected] of Object.entries(migrationDependencies())) {
|
|
11462
11763
|
try {
|
|
11463
11764
|
const manifest = JSON.parse(await readFile8(resolve11(rootDir, "node_modules", name, "package.json"), "utf8"));
|
|
11464
11765
|
if (!manifest || typeof manifest !== "object" || !("name" in manifest) || manifest.name !== name || !("version" in manifest) || manifest.version !== expected) {
|
|
@@ -11474,29 +11775,29 @@ async function checkMigrationDependencies(rootDir) {
|
|
|
11474
11775
|
// src/migrations.ts
|
|
11475
11776
|
var ROUTE_DECORATORS2 = new Set(["Get", "Post", "Put", "Patch", "Delete", "Head", "Options"]);
|
|
11476
11777
|
var MIGRATION_COMPILER_OPTIONS = {
|
|
11477
|
-
target:
|
|
11478
|
-
module:
|
|
11479
|
-
moduleResolution:
|
|
11778
|
+
target: ts12.ScriptTarget.ES2022,
|
|
11779
|
+
module: ts12.ModuleKind.ESNext,
|
|
11780
|
+
moduleResolution: ts12.ModuleResolutionKind.Bundler,
|
|
11480
11781
|
noEmit: true,
|
|
11481
11782
|
skipLibCheck: true
|
|
11482
11783
|
};
|
|
11483
11784
|
function migrationCompilerOptions(rootDir) {
|
|
11484
11785
|
if (!rootDir)
|
|
11485
11786
|
return MIGRATION_COMPILER_OPTIONS;
|
|
11486
|
-
const configPath =
|
|
11787
|
+
const configPath = ts12.findConfigFile(rootDir, ts12.sys.fileExists);
|
|
11487
11788
|
if (!configPath)
|
|
11488
11789
|
return MIGRATION_COMPILER_OPTIONS;
|
|
11489
11790
|
const configHost = {
|
|
11490
|
-
...
|
|
11791
|
+
...ts12.sys,
|
|
11491
11792
|
onUnRecoverableConfigFileDiagnostic: (_diagnostic) => {}
|
|
11492
11793
|
};
|
|
11493
|
-
const parsed =
|
|
11794
|
+
const parsed = ts12.getParsedCommandLineOfConfigFile(configPath, {}, configHost);
|
|
11494
11795
|
if (!parsed || parsed.errors.length > 0)
|
|
11495
11796
|
return MIGRATION_COMPILER_OPTIONS;
|
|
11496
11797
|
return { ...parsed.options, noEmit: true, skipLibCheck: true };
|
|
11497
11798
|
}
|
|
11498
11799
|
function propertyName2(property) {
|
|
11499
|
-
if (
|
|
11800
|
+
if (ts12.isIdentifier(property) || ts12.isStringLiteral(property) || ts12.isNumericLiteral(property))
|
|
11500
11801
|
return property.text;
|
|
11501
11802
|
return;
|
|
11502
11803
|
}
|
|
@@ -11506,7 +11807,7 @@ function lineOf2(sourceFile, node) {
|
|
|
11506
11807
|
function resolveSymbol(symbol, checker) {
|
|
11507
11808
|
if (!symbol)
|
|
11508
11809
|
return;
|
|
11509
|
-
for (let guard = 0;guard < 4 && (symbol.flags &
|
|
11810
|
+
for (let guard = 0;guard < 4 && (symbol.flags & ts12.SymbolFlags.Alias) !== 0; guard += 1) {
|
|
11510
11811
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
11511
11812
|
if (aliased === symbol)
|
|
11512
11813
|
break;
|
|
@@ -11515,12 +11816,12 @@ function resolveSymbol(symbol, checker) {
|
|
|
11515
11816
|
return symbol;
|
|
11516
11817
|
}
|
|
11517
11818
|
function symbolForExpression(expression, checker) {
|
|
11518
|
-
const location =
|
|
11819
|
+
const location = ts12.isIdentifier(expression) ? expression : ts12.isPropertyAccessExpression(expression) ? expression.name : ts12.isElementAccessExpression(expression) && expression.argumentExpression && ts12.isStringLiteral(expression.argumentExpression) ? expression : undefined;
|
|
11519
11820
|
return location ? resolveSymbol(checker.getSymbolAtLocation(location), checker) : undefined;
|
|
11520
11821
|
}
|
|
11521
11822
|
function unwrapExpression(expression) {
|
|
11522
11823
|
let current = expression;
|
|
11523
|
-
while (
|
|
11824
|
+
while (ts12.isAsExpression(current) || ts12.isSatisfiesExpression(current) || ts12.isParenthesizedExpression(current) || ts12.isTypeAssertionExpression(current)) {
|
|
11524
11825
|
current = current.expression;
|
|
11525
11826
|
}
|
|
11526
11827
|
return current;
|
|
@@ -11533,7 +11834,7 @@ function isDefineRouteContractCall(node, checker) {
|
|
|
11533
11834
|
}
|
|
11534
11835
|
function isRouteDecoratorCall(node, checker) {
|
|
11535
11836
|
const name = node.expression.getText(node.getSourceFile());
|
|
11536
|
-
if (
|
|
11837
|
+
if (ts12.isIdentifier(node.expression) && ROUTE_DECORATORS2.has(node.expression.text))
|
|
11537
11838
|
return true;
|
|
11538
11839
|
if (ROUTE_DECORATORS2.has(name))
|
|
11539
11840
|
return true;
|
|
@@ -11547,14 +11848,14 @@ function resolveStaticObjectLiteral2(input, checker, seen = new Set) {
|
|
|
11547
11848
|
if (seen.has(expression))
|
|
11548
11849
|
return;
|
|
11549
11850
|
seen.add(expression);
|
|
11550
|
-
if (
|
|
11851
|
+
if (ts12.isObjectLiteralExpression(expression))
|
|
11551
11852
|
return expression;
|
|
11552
|
-
if (
|
|
11853
|
+
if (ts12.isCallExpression(expression) && isDefineRouteContractCall(expression, checker)) {
|
|
11553
11854
|
return resolveStaticObjectLiteral2(expression.arguments[0], checker, seen);
|
|
11554
11855
|
}
|
|
11555
11856
|
const symbol = symbolForExpression(expression, checker);
|
|
11556
11857
|
for (const declaration of symbol?.declarations ?? []) {
|
|
11557
|
-
if (
|
|
11858
|
+
if (ts12.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
11558
11859
|
const resolved = resolveStaticObjectLiteral2(declaration.initializer, checker, seen);
|
|
11559
11860
|
if (resolved)
|
|
11560
11861
|
return resolved;
|
|
@@ -11568,7 +11869,7 @@ function displayFile(rootDir, fileName) {
|
|
|
11568
11869
|
}
|
|
11569
11870
|
function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
11570
11871
|
const compilerOptions = migrationCompilerOptions(rootDir);
|
|
11571
|
-
const host =
|
|
11872
|
+
const host = ts12.createCompilerHost(compilerOptions);
|
|
11572
11873
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
11573
11874
|
const fileExists = host.fileExists.bind(host);
|
|
11574
11875
|
const readFile = host.readFile.bind(host);
|
|
@@ -11577,16 +11878,16 @@ function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
|
11577
11878
|
host.readFile = (fileName) => sourceOverrides.get(resolve12(fileName)) ?? readFile(fileName);
|
|
11578
11879
|
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
11579
11880
|
const source = sourceOverrides.get(resolve12(fileName));
|
|
11580
|
-
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) :
|
|
11881
|
+
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts12.createSourceFile(fileName, source, languageVersion, true);
|
|
11581
11882
|
};
|
|
11582
11883
|
host.getCurrentDirectory = () => rootDir ?? currentDirectory();
|
|
11583
|
-
return
|
|
11884
|
+
return ts12.createProgram(fileNames, compilerOptions, host);
|
|
11584
11885
|
}
|
|
11585
11886
|
function routeResponseProperties(object) {
|
|
11586
|
-
const responseProperties = object.properties.filter((property) =>
|
|
11887
|
+
const responseProperties = object.properties.filter((property) => ts12.isPropertyAssignment(property) && propertyName2(property.name) === "response");
|
|
11587
11888
|
return {
|
|
11588
11889
|
response: responseProperties[0],
|
|
11589
|
-
hasResponses: object.properties.some((property) => (
|
|
11890
|
+
hasResponses: object.properties.some((property) => (ts12.isPropertyAssignment(property) || ts12.isShorthandPropertyAssignment(property)) && propertyName2(property.name) === "responses"),
|
|
11590
11891
|
duplicateResponse: responseProperties.length > 1
|
|
11591
11892
|
};
|
|
11592
11893
|
}
|
|
@@ -11606,7 +11907,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
11606
11907
|
if (!includedFiles.has(sourcePath))
|
|
11607
11908
|
continue;
|
|
11608
11909
|
const visit = (node) => {
|
|
11609
|
-
if (
|
|
11910
|
+
if (ts12.isCallExpression(node) && isRouteDecoratorCall(node, checker)) {
|
|
11610
11911
|
const options = node.arguments[1];
|
|
11611
11912
|
const object = options && resolveStaticObjectLiteral2(options, checker);
|
|
11612
11913
|
if (object) {
|
|
@@ -11626,7 +11927,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
11626
11927
|
}
|
|
11627
11928
|
}
|
|
11628
11929
|
}
|
|
11629
|
-
|
|
11930
|
+
ts12.forEachChild(node, visit);
|
|
11630
11931
|
};
|
|
11631
11932
|
visit(sourceFile);
|
|
11632
11933
|
}
|
|
@@ -11786,7 +12087,7 @@ async function migrateProject(options) {
|
|
|
11786
12087
|
}
|
|
11787
12088
|
}
|
|
11788
12089
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
11789
|
-
const files =
|
|
12090
|
+
const files = ts12.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist", "generated"], include).sort();
|
|
11790
12091
|
const results = [];
|
|
11791
12092
|
const issues = [];
|
|
11792
12093
|
const pendingWrites = new Map;
|
|
@@ -12787,6 +13088,7 @@ function compileOptionsFromConfig(config, cwd = process.cwd()) {
|
|
|
12787
13088
|
|
|
12788
13089
|
// src/index.ts
|
|
12789
13090
|
init_graphql_schema();
|
|
13091
|
+
init_database_contracts();
|
|
12790
13092
|
export {
|
|
12791
13093
|
ANGULAR_ENTERPRISE_RULES,
|
|
12792
13094
|
CLEAN_ARCHITECTURE_RULES,
|
|
@@ -12803,6 +13105,7 @@ export {
|
|
|
12803
13105
|
MODULE_BOUNDARY_PROFILES,
|
|
12804
13106
|
ModuleDependencyGraph,
|
|
12805
13107
|
OpenApiDocumentError,
|
|
13108
|
+
SQL_SAFETY_DIAGNOSTIC_CODES,
|
|
12806
13109
|
SUPACLOUD_MIGRATIONS,
|
|
12807
13110
|
TYPE_SAFETY_DIAGNOSTIC_CODES,
|
|
12808
13111
|
TraitCompiler,
|
|
@@ -12831,6 +13134,7 @@ export {
|
|
|
12831
13134
|
formatGraph,
|
|
12832
13135
|
formatOpenApiDiff,
|
|
12833
13136
|
generateApplication,
|
|
13137
|
+
generateDatabaseContracts,
|
|
12834
13138
|
generateFeatureSource,
|
|
12835
13139
|
getModuleBoundaryPreset,
|
|
12836
13140
|
getModuleBoundaryProfile,
|
|
@@ -12839,6 +13143,7 @@ export {
|
|
|
12839
13143
|
loadSupacloudConfig,
|
|
12840
13144
|
migrateProject,
|
|
12841
13145
|
migrateRouteResponse,
|
|
13146
|
+
parseDatabaseContractsOptions,
|
|
12842
13147
|
parseDeliveryBuildManifest,
|
|
12843
13148
|
parseDeliveryBuildResult,
|
|
12844
13149
|
parseDeliveryOptions,
|
|
@@ -12852,6 +13157,8 @@ export {
|
|
|
12852
13157
|
renderOpenApi,
|
|
12853
13158
|
resolveModuleBoundaries,
|
|
12854
13159
|
resolveSupacloudConfig,
|
|
13160
|
+
runDatabaseContractsFile,
|
|
13161
|
+
scanDrizzleSql,
|
|
12855
13162
|
scanGeneratedArtifacts,
|
|
12856
13163
|
scanProductionSource,
|
|
12857
13164
|
serializeOpenApiJson,
|