@supacloud/compiler 0.28.0 → 0.30.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/LICENSE +202 -661
- package/NOTICE +8 -13
- package/README.md +1 -1
- package/dist/api-source.d.ts +11 -0
- package/dist/cli.js +1122 -667
- package/dist/diagnostics.d.ts +61 -0
- package/dist/diagnostics.js +333 -0
- package/dist/fixes.d.ts +3 -0
- package/dist/http-provider-migration.d.ts +6 -0
- package/dist/index.js +1040 -659
- package/dist/inspect.d.ts +6 -0
- package/dist/reactive-analysis.d.ts +4 -0
- package/dist/types.d.ts +8 -0
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -1662,6 +1662,12 @@ class ModuleGenerator {
|
|
|
1662
1662
|
}
|
|
1663
1663
|
renderFactories() {
|
|
1664
1664
|
const sections = [this.renderServicesFactory()];
|
|
1665
|
+
if (this.hasApplicationLifecycle("init")) {
|
|
1666
|
+
sections.push(this.renderApplicationLifecycle("init"));
|
|
1667
|
+
}
|
|
1668
|
+
if (this.hasApplicationLifecycle("destroy")) {
|
|
1669
|
+
sections.push(this.renderApplicationLifecycle("destroy"));
|
|
1670
|
+
}
|
|
1665
1671
|
if (this.hasFactoryContent("request")) {
|
|
1666
1672
|
sections.push(this.renderScopeFactory("request"));
|
|
1667
1673
|
sections.push(this.renderScopeDestroyer("request"));
|
|
@@ -1678,6 +1684,12 @@ class ModuleGenerator {
|
|
|
1678
1684
|
` name: ${JSON.stringify(this.module.name)} as const,`,
|
|
1679
1685
|
` createServices: create${this.pascal}Services,`
|
|
1680
1686
|
];
|
|
1687
|
+
if (this.hasApplicationLifecycle("init")) {
|
|
1688
|
+
lines.push(` initializeServices: initialize${this.pascal}Services,`);
|
|
1689
|
+
}
|
|
1690
|
+
if (this.hasApplicationLifecycle("destroy")) {
|
|
1691
|
+
lines.push(` destroyServices: destroy${this.pascal}Services,`);
|
|
1692
|
+
}
|
|
1681
1693
|
if (this.hasFactoryContent("request")) {
|
|
1682
1694
|
lines.push(` createRequestScope: create${this.pascal}RequestScope,`);
|
|
1683
1695
|
lines.push(` destroyRequestScope: destroy${this.pascal}RequestScope,`);
|
|
@@ -1700,6 +1712,40 @@ class ModuleGenerator {
|
|
|
1700
1712
|
hasFactoryContent(kind) {
|
|
1701
1713
|
return this.module.providers.some((p) => factoryOfScope(p.scope) === kind) || this.module.controllers.some((c) => factoryOfScope(c.scope) === kind);
|
|
1702
1714
|
}
|
|
1715
|
+
hasApplicationLifecycle(kind) {
|
|
1716
|
+
return this.applicationLifecyclePlan(kind).length > 0;
|
|
1717
|
+
}
|
|
1718
|
+
applicationLifecyclePlan(kind) {
|
|
1719
|
+
const result = [];
|
|
1720
|
+
const multiIndices = new Map;
|
|
1721
|
+
for (const provider of orderProviders(this.module.providers.filter((p) => factoryOfScope(p.scope) === "services"))) {
|
|
1722
|
+
const index = provider.multi ? multiIndices.get(provider.token) ?? 0 : undefined;
|
|
1723
|
+
if (index !== undefined)
|
|
1724
|
+
multiIndices.set(provider.token, index + 1);
|
|
1725
|
+
const owned = provider.kind !== "existing";
|
|
1726
|
+
const selected = kind === "init" ? provider.hasOnInit : provider.hasOnDestroy;
|
|
1727
|
+
if (owned && selected)
|
|
1728
|
+
result.push({ key: camelName(provider.token), ...index === undefined ? {} : { index } });
|
|
1729
|
+
}
|
|
1730
|
+
for (const controller of this.module.controllers) {
|
|
1731
|
+
if (factoryOfScope(controller.scope) !== "services")
|
|
1732
|
+
continue;
|
|
1733
|
+
const selected = kind === "init" ? controller.hasOnInit : controller.hasOnDestroy;
|
|
1734
|
+
if (selected)
|
|
1735
|
+
result.push({ key: camelName(controller.className) });
|
|
1736
|
+
}
|
|
1737
|
+
return result;
|
|
1738
|
+
}
|
|
1739
|
+
renderApplicationLifecycle(kind) {
|
|
1740
|
+
const suffix = kind === "init" ? "initialize" : "destroy";
|
|
1741
|
+
const helper = kind === "init" ? "initializeServiceInstances" : "destroyServiceInstances";
|
|
1742
|
+
return [
|
|
1743
|
+
`async function ${suffix}${this.pascal}Services(services: Record<string, unknown>): Promise<void> {`,
|
|
1744
|
+
` await ${helper}(services, ${JSON.stringify(this.applicationLifecyclePlan(kind))});`,
|
|
1745
|
+
`}`
|
|
1746
|
+
].join(`
|
|
1747
|
+
`);
|
|
1748
|
+
}
|
|
1703
1749
|
renderControllers() {
|
|
1704
1750
|
if (this.module.controllers.length === 0)
|
|
1705
1751
|
return "[]";
|
|
@@ -3418,6 +3464,10 @@ export interface CompiledModule {
|
|
|
3418
3464
|
deps: Record<string, unknown>,
|
|
3419
3465
|
imported: Record<string, Record<string, unknown>>,
|
|
3420
3466
|
): Record<string, unknown>;
|
|
3467
|
+
/** Initializes application-scoped instances owned by this module. */
|
|
3468
|
+
initializeServices?(services: Record<string, unknown>): Promise<void>;
|
|
3469
|
+
/** Destroys application-scoped instances owned by this module. */
|
|
3470
|
+
destroyServices?(services: Record<string, unknown>): Promise<void>;
|
|
3421
3471
|
createRequestScope?(
|
|
3422
3472
|
services: Record<string, unknown>,
|
|
3423
3473
|
ctx: unknown,
|
|
@@ -3501,7 +3551,54 @@ function destroyScopeInstances(
|
|
|
3501
3551
|
});
|
|
3502
3552
|
scopeDestructions.set(scope, destruction);
|
|
3503
3553
|
return destruction;
|
|
3504
|
-
}
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
type CompiledServiceLifecycleEntry = { key: string; index?: number };
|
|
3557
|
+
|
|
3558
|
+
async function initializeServiceInstances(
|
|
3559
|
+
services: Record<string, unknown>,
|
|
3560
|
+
plan: readonly CompiledServiceLifecycleEntry[],
|
|
3561
|
+
): Promise<void> {
|
|
3562
|
+
const seen = new Set<unknown>();
|
|
3563
|
+
for (const entry of plan) {
|
|
3564
|
+
const value = services[entry.key];
|
|
3565
|
+
const instance = entry.index === undefined
|
|
3566
|
+
? value
|
|
3567
|
+
: Array.isArray(value) ? value[entry.index] : undefined;
|
|
3568
|
+
if (seen.has(instance)) continue;
|
|
3569
|
+
seen.add(instance);
|
|
3570
|
+
if (!isRecord(instance) || !isFunction(instance.onInit)) continue;
|
|
3571
|
+
await instance.onInit();
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3575
|
+
async function destroyServiceInstances(
|
|
3576
|
+
services: Record<string, unknown>,
|
|
3577
|
+
plan: readonly CompiledServiceLifecycleEntry[],
|
|
3578
|
+
): Promise<void> {
|
|
3579
|
+
const errors: unknown[] = [];
|
|
3580
|
+
const seen = new Set<unknown>();
|
|
3581
|
+
for (const entry of [...plan].reverse()) {
|
|
3582
|
+
const value = services[entry.key];
|
|
3583
|
+
const instance = entry.index === undefined
|
|
3584
|
+
? value
|
|
3585
|
+
: Array.isArray(value) ? value[entry.index] : undefined;
|
|
3586
|
+
if (seen.has(instance)) continue;
|
|
3587
|
+
seen.add(instance);
|
|
3588
|
+
if (!isRecord(instance)) continue;
|
|
3589
|
+
const hook = isFunction(instance.onDestroy)
|
|
3590
|
+
? instance.onDestroy
|
|
3591
|
+
: isFunction(instance.ngOnDestroy) ? instance.ngOnDestroy : undefined;
|
|
3592
|
+
if (!hook) continue;
|
|
3593
|
+
try {
|
|
3594
|
+
await hook.call(instance);
|
|
3595
|
+
} catch (error) {
|
|
3596
|
+
errors.push(error);
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
if (errors.length > 0) throw new AggregateError(errors, "Application service destruction failed");
|
|
3600
|
+
}
|
|
3601
|
+
`;
|
|
3505
3602
|
var init_generate = __esm(() => {
|
|
3506
3603
|
init_contract_manifest();
|
|
3507
3604
|
});
|
|
@@ -3723,8 +3820,8 @@ var init_graphql_options = __esm(() => {
|
|
|
3723
3820
|
});
|
|
3724
3821
|
|
|
3725
3822
|
// src/graphql-inputs.ts
|
|
3726
|
-
import { resolve as
|
|
3727
|
-
import * as
|
|
3823
|
+
import { resolve as resolve4 } from "node:path";
|
|
3824
|
+
import * as ts10 from "@typescript/typescript6";
|
|
3728
3825
|
function graphqlInputPaths(options) {
|
|
3729
3826
|
if (!options.graphql)
|
|
3730
3827
|
return [];
|
|
@@ -3733,9 +3830,9 @@ function graphqlInputPaths(options) {
|
|
|
3733
3830
|
} catch {
|
|
3734
3831
|
return [];
|
|
3735
3832
|
}
|
|
3736
|
-
const root =
|
|
3737
|
-
const schema =
|
|
3738
|
-
const documents =
|
|
3833
|
+
const root = resolve4(options.rootDir);
|
|
3834
|
+
const schema = resolve4(root, options.graphql.schema);
|
|
3835
|
+
const documents = ts10.sys.readDirectory(root, [".graphql", ".gql"], ["**/node_modules/**", "**/.git/**", resolve4(options.outDir)], options.graphql.documents ?? ["**/*.graphql", "**/*.gql"]).map((path) => resolve4(path)).filter((path) => path !== schema);
|
|
3739
3836
|
return [schema, ...[...new Set(documents)].sort()];
|
|
3740
3837
|
}
|
|
3741
3838
|
var init_graphql_inputs = __esm(() => {
|
|
@@ -3743,10 +3840,10 @@ var init_graphql_inputs = __esm(() => {
|
|
|
3743
3840
|
});
|
|
3744
3841
|
|
|
3745
3842
|
// src/graphql-runtime.ts
|
|
3746
|
-
import * as
|
|
3747
|
-
import { resolve as
|
|
3843
|
+
import * as ts11 from "@typescript/typescript6";
|
|
3844
|
+
import { resolve as resolve5 } from "node:path";
|
|
3748
3845
|
function renderGraphqlValidators(source, operationNames) {
|
|
3749
|
-
const fileName =
|
|
3846
|
+
const fileName = resolve5("/__supacloud_graphql__/contracts.ts");
|
|
3750
3847
|
const options = {
|
|
3751
3848
|
strict: true,
|
|
3752
3849
|
noUncheckedIndexedAccess: true,
|
|
@@ -3755,18 +3852,18 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
3755
3852
|
noPropertyAccessFromIndexSignature: true,
|
|
3756
3853
|
noFallthroughCasesInSwitch: true,
|
|
3757
3854
|
skipLibCheck: false,
|
|
3758
|
-
target:
|
|
3855
|
+
target: ts11.ScriptTarget.ES2022,
|
|
3759
3856
|
lib: ["lib.es2022.d.ts"],
|
|
3760
3857
|
types: [],
|
|
3761
3858
|
noEmit: true
|
|
3762
3859
|
};
|
|
3763
|
-
const host =
|
|
3860
|
+
const host = ts11.createCompilerHost(options);
|
|
3764
3861
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
3765
|
-
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) =>
|
|
3766
|
-
const program =
|
|
3767
|
-
const diagnostics =
|
|
3862
|
+
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve5(path) === fileName ? ts11.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
|
|
3863
|
+
const program = ts11.createProgram([fileName], options, host);
|
|
3864
|
+
const diagnostics = ts11.getPreEmitDiagnostics(program);
|
|
3768
3865
|
if (diagnostics.length) {
|
|
3769
|
-
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) =>
|
|
3866
|
+
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts11.flattenDiagnosticMessageText(item.messageText, `
|
|
3770
3867
|
`)).join("; ")}`);
|
|
3771
3868
|
}
|
|
3772
3869
|
const checker = program.getTypeChecker();
|
|
@@ -3796,25 +3893,25 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
3796
3893
|
return name;
|
|
3797
3894
|
}
|
|
3798
3895
|
function expression(type) {
|
|
3799
|
-
if (type.flags &
|
|
3896
|
+
if (type.flags & ts11.TypeFlags.Any)
|
|
3800
3897
|
return unsupported(type);
|
|
3801
|
-
if (type.flags &
|
|
3898
|
+
if (type.flags & ts11.TypeFlags.Unknown)
|
|
3802
3899
|
return "true";
|
|
3803
|
-
if (type.flags &
|
|
3900
|
+
if (type.flags & ts11.TypeFlags.Never)
|
|
3804
3901
|
return "false";
|
|
3805
|
-
if (type.flags &
|
|
3902
|
+
if (type.flags & ts11.TypeFlags.Null)
|
|
3806
3903
|
return "value === null";
|
|
3807
|
-
if (type.flags &
|
|
3904
|
+
if (type.flags & ts11.TypeFlags.Undefined)
|
|
3808
3905
|
return "value === undefined";
|
|
3809
3906
|
if (type.isStringLiteral() || type.isNumberLiteral())
|
|
3810
3907
|
return `value === ${JSON.stringify(type.value)}`;
|
|
3811
|
-
if (type.flags &
|
|
3908
|
+
if (type.flags & ts11.TypeFlags.BooleanLiteral)
|
|
3812
3909
|
return `value === ${checker.typeToString(type)}`;
|
|
3813
|
-
if (type.flags &
|
|
3910
|
+
if (type.flags & ts11.TypeFlags.String)
|
|
3814
3911
|
return 'typeof value === "string"';
|
|
3815
|
-
if (type.flags &
|
|
3912
|
+
if (type.flags & ts11.TypeFlags.Number)
|
|
3816
3913
|
return 'typeof value === "number" && Number.isFinite(value)';
|
|
3817
|
-
if (type.flags &
|
|
3914
|
+
if (type.flags & ts11.TypeFlags.Boolean)
|
|
3818
3915
|
return 'typeof value === "boolean"';
|
|
3819
3916
|
if (type.isUnion())
|
|
3820
3917
|
return type.types.map((part) => `${reference(part)}(value)`).join(" || ");
|
|
@@ -3823,16 +3920,16 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
3823
3920
|
if (checker.isTupleType(type))
|
|
3824
3921
|
return unsupported(type);
|
|
3825
3922
|
if (checker.isArrayType(type)) {
|
|
3826
|
-
const item = checker.getIndexTypeOfType(type,
|
|
3923
|
+
const item = checker.getIndexTypeOfType(type, ts11.IndexKind.Number);
|
|
3827
3924
|
if (!item)
|
|
3828
3925
|
return unsupported(type);
|
|
3829
3926
|
return `isGraphqlArray(value) && Array.from(value).every(${reference(item)})`;
|
|
3830
3927
|
}
|
|
3831
|
-
if (type.flags &
|
|
3928
|
+
if (type.flags & ts11.TypeFlags.Object) {
|
|
3832
3929
|
if (type.getCallSignatures().length || type.getConstructSignatures().length)
|
|
3833
3930
|
return unsupported(type);
|
|
3834
3931
|
const indexes = checker.getIndexInfosOfType(type);
|
|
3835
|
-
if (indexes.some((index) => !(index.keyType.flags &
|
|
3932
|
+
if (indexes.some((index) => !(index.keyType.flags & ts11.TypeFlags.String)))
|
|
3836
3933
|
return unsupported(type);
|
|
3837
3934
|
const properties = checker.getPropertiesOfType(type).map((property) => {
|
|
3838
3935
|
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
@@ -3841,7 +3938,7 @@ function renderGraphqlValidators(source, operationNames) {
|
|
|
3841
3938
|
const check = reference(checker.getTypeOfSymbolAtLocation(property, declaration));
|
|
3842
3939
|
const key = JSON.stringify(property.name);
|
|
3843
3940
|
const present = `Object.prototype.hasOwnProperty.call(value, ${key})`;
|
|
3844
|
-
return property.flags &
|
|
3941
|
+
return property.flags & ts11.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
|
|
3845
3942
|
});
|
|
3846
3943
|
const indexedValues = indexes.map((index) => `Object.values(value).every(${reference(index.type)})`);
|
|
3847
3944
|
return ["isGraphqlRecord(value)", ...properties, ...indexedValues].join(" && ");
|
|
@@ -14210,7 +14307,7 @@ var init_delivery_schema = __esm(() => {
|
|
|
14210
14307
|
import { createHash as createHash7 } from "node:crypto";
|
|
14211
14308
|
import { constants } from "node:fs";
|
|
14212
14309
|
import { lstat, mkdir as mkdir2, open, readFile as readFile3, readdir, realpath, rename as rename2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
14213
|
-
import { dirname as dirname4, isAbsolute, join as join5, relative as relative5, resolve as
|
|
14310
|
+
import { dirname as dirname4, isAbsolute, join as join5, relative as relative5, resolve as resolve7, sep as sep5 } from "node:path";
|
|
14214
14311
|
function canonical2(value) {
|
|
14215
14312
|
return JSON.stringify(value, (_key, item) => item !== null && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.entries(item).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) : item);
|
|
14216
14313
|
}
|
|
@@ -14273,7 +14370,7 @@ async function reserveOutput(project, requested) {
|
|
|
14273
14370
|
if (!inside(project, requested))
|
|
14274
14371
|
throw new Error("Delivery output must be inside the application project.");
|
|
14275
14372
|
const base = await realpath(project);
|
|
14276
|
-
const path =
|
|
14373
|
+
const path = resolve7(base, relative5(project, requested));
|
|
14277
14374
|
if (relative5(base, path).split(sep5).some((part) => part === ".git" || part === "node_modules")) {
|
|
14278
14375
|
throw new Error("Delivery output cannot use repository or dependency internals.");
|
|
14279
14376
|
}
|
|
@@ -14576,6 +14673,12 @@ function createContextPack(graph, subject) {
|
|
|
14576
14673
|
routeContracts: inspectRouteContracts({ ...graph, modules }),
|
|
14577
14674
|
...graphql ? { graphql } : {},
|
|
14578
14675
|
diagnostics: (graph.diagnostics ?? []).filter((diagnostic) => diagnostic.file === undefined || files.includes(diagnostic.file)),
|
|
14676
|
+
conventions: {
|
|
14677
|
+
singleResult: "async-await",
|
|
14678
|
+
eventComposition: "rxjs",
|
|
14679
|
+
angularHost: "@supacloud/app/angular",
|
|
14680
|
+
cancellation: "explicit-owner-signal"
|
|
14681
|
+
},
|
|
14579
14682
|
relatedModules: {
|
|
14580
14683
|
imports: subjectModule.imports.filter((name) => selected.has(name)),
|
|
14581
14684
|
importedBy: graph.modules.filter((module) => module.imports.includes(subjectModule.name)).map((module) => module.name).sort()
|
|
@@ -15334,9 +15437,9 @@ var init_delivery_files2 = __esm(() => {
|
|
|
15334
15437
|
|
|
15335
15438
|
// node_modules/@supacloud/delivery/src/delivery-artifact.ts
|
|
15336
15439
|
import { readdir as readdir2, realpath as realpath2 } from "node:fs/promises";
|
|
15337
|
-
import { basename, dirname as dirname6, join as join8, resolve as
|
|
15440
|
+
import { basename, dirname as dirname6, join as join8, resolve as resolve9 } from "node:path";
|
|
15338
15441
|
async function readDeliveryManifest(manifestPath) {
|
|
15339
|
-
const selected =
|
|
15442
|
+
const selected = resolve9(manifestPath);
|
|
15340
15443
|
const root = await realpath2(dirname6(selected));
|
|
15341
15444
|
const manifest = parseDeliveryBuildManifest(JSON.parse((await readBoundedOwned(root, join8(root, basename(selected)), JSON_LIMIT)).toString("utf8")));
|
|
15342
15445
|
return { root, manifest };
|
|
@@ -15642,6 +15745,213 @@ var init_delivery_migration_archive2 = __esm(() => {
|
|
|
15642
15745
|
init_src();
|
|
15643
15746
|
});
|
|
15644
15747
|
|
|
15748
|
+
// src/fixes.ts
|
|
15749
|
+
import { createHash as createHash8, randomUUID } from "node:crypto";
|
|
15750
|
+
import { lstat as lstat2, readFile as readFile6, realpath as realpath4, rename as rename4, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
15751
|
+
import { dirname as dirname8, isAbsolute as isAbsolute3, relative as relative8, resolve as resolve12, sep as sep8 } from "node:path";
|
|
15752
|
+
import * as ts15 from "@typescript/typescript6";
|
|
15753
|
+
async function applyDiagnosticFix(fix, options = {}) {
|
|
15754
|
+
if (!fix || typeof fix.targetFile !== "string")
|
|
15755
|
+
throw new Error("Invalid DiagnosticFix");
|
|
15756
|
+
const root = await realpath4(options.rootDir ?? process.cwd());
|
|
15757
|
+
const file = resolve12(root, fix.targetFile);
|
|
15758
|
+
const stat = await lstat2(file);
|
|
15759
|
+
const resolved = await realpath4(file);
|
|
15760
|
+
const relativePath = relative8(root, resolved);
|
|
15761
|
+
if (stat.isSymbolicLink() || !stat.isFile() || isAbsolute3(relativePath) || relativePath === ".." || relativePath.startsWith(`..${sep8}`)) {
|
|
15762
|
+
throw new Error("Fix target must be a regular file inside rootDir");
|
|
15763
|
+
}
|
|
15764
|
+
const original = await readFile6(file, "utf8");
|
|
15765
|
+
const sourceHash = createHash8("sha256").update(original).digest("hex");
|
|
15766
|
+
if (options.expectedSourceHash !== undefined && options.expectedSourceHash !== sourceHash) {
|
|
15767
|
+
throw new Error("Fix source changed since preview; analyze the project again");
|
|
15768
|
+
}
|
|
15769
|
+
let source = parse5(file, original);
|
|
15770
|
+
let content;
|
|
15771
|
+
switch (fix.type) {
|
|
15772
|
+
case "set_command_mode": {
|
|
15773
|
+
if (fix.property !== "transaction" && fix.property !== "idempotency" || fix.value !== "required" && fix.value !== "none") {
|
|
15774
|
+
throw new Error("Command mode fix requires an explicit property and policy value");
|
|
15775
|
+
}
|
|
15776
|
+
const object = decoratorObject(findClass(source, fix.command), "Command");
|
|
15777
|
+
const current = property(object, fix.property);
|
|
15778
|
+
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
15779
|
+
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
15780
|
+
}
|
|
15781
|
+
content = replaceProperty(source, object, fix.property, ts15.factory.createStringLiteral(fix.value));
|
|
15782
|
+
break;
|
|
15783
|
+
}
|
|
15784
|
+
case "add_module_import": {
|
|
15785
|
+
if (!fix.importPath || !fix.symbol)
|
|
15786
|
+
throw new Error("Module fix requires importPath and symbol");
|
|
15787
|
+
identifier2(fix.symbol);
|
|
15788
|
+
const withImport = importSymbol(source, fix.importPath, fix.symbol);
|
|
15789
|
+
source = parse5(file, withImport);
|
|
15790
|
+
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
15791
|
+
const imports = property(object, "imports");
|
|
15792
|
+
if (imports && !ts15.isArrayLiteralExpression(imports.initializer)) {
|
|
15793
|
+
throw new Error("Module imports must be a static array");
|
|
15794
|
+
}
|
|
15795
|
+
const values = imports && ts15.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
15796
|
+
if (values.some(ts15.isSpreadElement))
|
|
15797
|
+
throw new Error("Module imports cannot contain spread elements");
|
|
15798
|
+
content = values.some((value) => ts15.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts15.factory.createArrayLiteralExpression([
|
|
15799
|
+
...values,
|
|
15800
|
+
ts15.factory.createIdentifier(fix.symbol)
|
|
15801
|
+
]));
|
|
15802
|
+
break;
|
|
15803
|
+
}
|
|
15804
|
+
case "add_command_permission": {
|
|
15805
|
+
const permission = options.permission ?? fix.permission;
|
|
15806
|
+
if (!permission?.trim()) {
|
|
15807
|
+
throw new Error("Permission fix requires an explicit permission; privileges are never inferred");
|
|
15808
|
+
}
|
|
15809
|
+
const command = findClass(source, fix.command);
|
|
15810
|
+
const object = decoratorObject(command, "Command");
|
|
15811
|
+
const current = property(object, "permission");
|
|
15812
|
+
if (current && (!ts15.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
15813
|
+
throw new Error("Command permission already exists with a different value");
|
|
15814
|
+
}
|
|
15815
|
+
content = current ? original : replaceProperty(source, object, "permission", ts15.factory.createStringLiteral(permission));
|
|
15816
|
+
break;
|
|
15817
|
+
}
|
|
15818
|
+
case "add_route_parameter_binding": {
|
|
15819
|
+
const controller = findClass(source, fix.controller);
|
|
15820
|
+
const method = unique(controller.members.filter((member) => ts15.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
|
|
15821
|
+
const parameter = unique(method.parameters.filter((candidate) => ts15.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
|
|
15822
|
+
const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
|
|
15823
|
+
if (!binding)
|
|
15824
|
+
throw new Error("Invalid route binding");
|
|
15825
|
+
const decorators = ts15.getDecorators(parameter) ?? [];
|
|
15826
|
+
if (decorators.length > 0)
|
|
15827
|
+
throw new Error("Parameter already has a decorator");
|
|
15828
|
+
const framework = unique(source.statements.filter((statement) => ts15.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts15.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
|
|
15829
|
+
if (!ts15.isImportDeclaration(framework) || !ts15.isStringLiteral(framework.moduleSpecifier)) {
|
|
15830
|
+
throw new Error("Framework import must be static");
|
|
15831
|
+
}
|
|
15832
|
+
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
15833
|
+
content = importSymbol(parse5(file, edited), framework.moduleSpecifier.text, binding);
|
|
15834
|
+
break;
|
|
15835
|
+
}
|
|
15836
|
+
default:
|
|
15837
|
+
throw new Error(`Diagnostic fix '${fix.type}' requires a manual semantic decision; no files changed`);
|
|
15838
|
+
}
|
|
15839
|
+
parse5(file, content);
|
|
15840
|
+
const result = { file, changed: content !== original, content, sourceHash };
|
|
15841
|
+
if (options.dryRun === false && result.changed) {
|
|
15842
|
+
const temporary = `${file}.supacloud-fix-${randomUUID()}`;
|
|
15843
|
+
try {
|
|
15844
|
+
await writeFile3(temporary, content, { encoding: "utf8", flag: "wx", mode: stat.mode });
|
|
15845
|
+
if (await readFile6(file, "utf8") !== original)
|
|
15846
|
+
throw new Error("Target changed while preparing the fix");
|
|
15847
|
+
await rename4(temporary, file);
|
|
15848
|
+
} finally {
|
|
15849
|
+
await unlink2(temporary).catch(() => {});
|
|
15850
|
+
}
|
|
15851
|
+
}
|
|
15852
|
+
return result;
|
|
15853
|
+
}
|
|
15854
|
+
function parse5(file, text) {
|
|
15855
|
+
const result = ts15.transpileModule(text, {
|
|
15856
|
+
fileName: file,
|
|
15857
|
+
reportDiagnostics: true,
|
|
15858
|
+
compilerOptions: { target: ts15.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
15859
|
+
});
|
|
15860
|
+
if (result.diagnostics?.some((item) => item.category === ts15.DiagnosticCategory.Error)) {
|
|
15861
|
+
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
15862
|
+
}
|
|
15863
|
+
return ts15.createSourceFile(file, text, ts15.ScriptTarget.Latest, true, ts15.ScriptKind.TS);
|
|
15864
|
+
}
|
|
15865
|
+
function unique(items, description) {
|
|
15866
|
+
if (items.length !== 1)
|
|
15867
|
+
throw new Error(`Expected exactly one ${description}; found ${items.length}`);
|
|
15868
|
+
return items[0];
|
|
15869
|
+
}
|
|
15870
|
+
function identifier2(value) {
|
|
15871
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(value))
|
|
15872
|
+
throw new Error(`Invalid identifier '${value}'`);
|
|
15873
|
+
}
|
|
15874
|
+
function nameOf(name) {
|
|
15875
|
+
if (!name)
|
|
15876
|
+
return "";
|
|
15877
|
+
return ts15.isIdentifier(name) || ts15.isStringLiteral(name) || ts15.isNumericLiteral(name) ? name.text : "";
|
|
15878
|
+
}
|
|
15879
|
+
function property(object, key) {
|
|
15880
|
+
if (object.properties.some((item) => !ts15.isPropertyAssignment(item) || ts15.isComputedPropertyName(item.name))) {
|
|
15881
|
+
throw new Error("Fix requires explicit static object properties");
|
|
15882
|
+
}
|
|
15883
|
+
const values = object.properties.filter((item) => ts15.isPropertyAssignment(item) && nameOf(item.name) === key);
|
|
15884
|
+
if (values.length > 1)
|
|
15885
|
+
throw new Error(`Duplicate '${key}' property`);
|
|
15886
|
+
return values[0];
|
|
15887
|
+
}
|
|
15888
|
+
function stringProperty(object, key) {
|
|
15889
|
+
const value = property(object, key)?.initializer;
|
|
15890
|
+
return value && ts15.isStringLiteral(value) ? value.text : undefined;
|
|
15891
|
+
}
|
|
15892
|
+
function replaceProperty(source, object, key, value) {
|
|
15893
|
+
const previous = property(object, key);
|
|
15894
|
+
const replacement = ts15.factory.createPropertyAssignment(key, value);
|
|
15895
|
+
const properties = object.properties.map((item) => item === previous ? replacement : item);
|
|
15896
|
+
if (!previous)
|
|
15897
|
+
properties.push(replacement);
|
|
15898
|
+
const updated = ts15.factory.updateObjectLiteralExpression(object, properties);
|
|
15899
|
+
return source.text.slice(0, object.getStart(source)) + ts15.createPrinter().printNode(ts15.EmitHint.Expression, updated, source) + source.text.slice(object.end);
|
|
15900
|
+
}
|
|
15901
|
+
function findClass(source, name) {
|
|
15902
|
+
return unique(source.statements.filter((statement) => ts15.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
15903
|
+
}
|
|
15904
|
+
function decoratorObject(node, name) {
|
|
15905
|
+
const decorator = unique((ts15.getDecorators(node) ?? []).filter((item) => ts15.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
|
|
15906
|
+
const argument = ts15.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
|
|
15907
|
+
if (!argument || !ts15.isObjectLiteralExpression(argument))
|
|
15908
|
+
throw new Error(`@${name} requires a static object`);
|
|
15909
|
+
return argument;
|
|
15910
|
+
}
|
|
15911
|
+
function moduleObjects(source) {
|
|
15912
|
+
const result = [];
|
|
15913
|
+
for (const statement of source.statements) {
|
|
15914
|
+
if (ts15.isClassDeclaration(statement) && (ts15.getDecorators(statement) ?? []).some((item) => ts15.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
|
|
15915
|
+
result.push(decoratorObject(statement, "Module"));
|
|
15916
|
+
}
|
|
15917
|
+
if (ts15.isVariableStatement(statement)) {
|
|
15918
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
15919
|
+
const call = declaration.initializer;
|
|
15920
|
+
if (call && ts15.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts15.isObjectLiteralExpression(call.arguments[0])) {
|
|
15921
|
+
result.push(call.arguments[0]);
|
|
15922
|
+
}
|
|
15923
|
+
}
|
|
15924
|
+
}
|
|
15925
|
+
}
|
|
15926
|
+
return result;
|
|
15927
|
+
}
|
|
15928
|
+
function importSymbol(source, path, symbol) {
|
|
15929
|
+
identifier2(symbol);
|
|
15930
|
+
const current = resolve12(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
|
|
15931
|
+
const target = resolve12(dirname8(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
15932
|
+
if (current === target)
|
|
15933
|
+
return source.text;
|
|
15934
|
+
const matches = source.statements.filter((item) => ts15.isImportDeclaration(item) && ts15.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
|
|
15935
|
+
if (matches.length > 1)
|
|
15936
|
+
throw new Error(`Ambiguous imports from '${path}'`);
|
|
15937
|
+
const match = matches[0];
|
|
15938
|
+
if (match && ts15.isImportDeclaration(match) && match.importClause?.namedBindings && ts15.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
|
|
15939
|
+
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
15940
|
+
return source.text;
|
|
15941
|
+
const bindings = match.importClause.namedBindings;
|
|
15942
|
+
const updated = ts15.factory.updateNamedImports(bindings, [
|
|
15943
|
+
...bindings.elements,
|
|
15944
|
+
ts15.factory.createImportSpecifier(false, undefined, ts15.factory.createIdentifier(symbol))
|
|
15945
|
+
]);
|
|
15946
|
+
return source.text.slice(0, bindings.getStart(source)) + ts15.createPrinter().printNode(ts15.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
|
|
15947
|
+
}
|
|
15948
|
+
if (match)
|
|
15949
|
+
throw new Error(`Import from '${path}' is not a named value import`);
|
|
15950
|
+
return `import { ${symbol} } from ${JSON.stringify(path)};
|
|
15951
|
+
${source.text}`;
|
|
15952
|
+
}
|
|
15953
|
+
var init_fixes = () => {};
|
|
15954
|
+
|
|
15645
15955
|
// src/execution-context.ts
|
|
15646
15956
|
import { open as open2 } from "node:fs/promises";
|
|
15647
15957
|
import { constants as constants2 } from "node:fs";
|
|
@@ -16095,8 +16405,8 @@ var init_release_evidence = __esm(() => {
|
|
|
16095
16405
|
|
|
16096
16406
|
// src/graphql-schema.ts
|
|
16097
16407
|
import { mkdir as mkdir5, readFile as readFile12 } from "node:fs/promises";
|
|
16098
|
-
import { createHash as
|
|
16099
|
-
import { dirname as dirname11, resolve as
|
|
16408
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
16409
|
+
import { dirname as dirname11, resolve as resolve20 } from "node:path";
|
|
16100
16410
|
async function pullGraphqlSchema(options) {
|
|
16101
16411
|
assertGraphqlOptions({ schema: options.output });
|
|
16102
16412
|
const endpoint = new URL(options.url);
|
|
@@ -16136,7 +16446,7 @@ async function pullGraphqlSchema(options) {
|
|
|
16136
16446
|
throw new Error("GraphQL schema export failed. Verify caller grants and enable introspection only in the intended development environment.");
|
|
16137
16447
|
}
|
|
16138
16448
|
const schema = lexicographicSortSchema(buildClientSchema(data));
|
|
16139
|
-
const path =
|
|
16449
|
+
const path = resolve20(options.output);
|
|
16140
16450
|
const content = path.endsWith(".json") ? JSON.stringify(introspectionFromSchema(schema), null, 2) + `
|
|
16141
16451
|
` : `# GENERATED BY supacloud-compiler graphql-schema. DO NOT EDIT.
|
|
16142
16452
|
# Database First: change database declarations, apply migrations, then re-export for the intended role.
|
|
@@ -16150,7 +16460,7 @@ async function pullGraphqlSchema(options) {
|
|
|
16150
16460
|
throw error;
|
|
16151
16461
|
}
|
|
16152
16462
|
const upToDate = previous === content;
|
|
16153
|
-
const schemaHash =
|
|
16463
|
+
const schemaHash = createHash11("sha256").update(content).digest("hex");
|
|
16154
16464
|
if (options.check)
|
|
16155
16465
|
return { path, schemaHash, upToDate, written: false };
|
|
16156
16466
|
await mkdir5(dirname11(path), { recursive: true });
|
|
@@ -16163,12 +16473,12 @@ var init_graphql_schema = __esm(() => {
|
|
|
16163
16473
|
});
|
|
16164
16474
|
|
|
16165
16475
|
// src/database-contracts.ts
|
|
16166
|
-
import { createHash as
|
|
16476
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
16167
16477
|
import { mkdir as mkdir6, readFile as readFile13 } from "node:fs/promises";
|
|
16168
|
-
import { dirname as dirname12, relative as relative12, resolve as
|
|
16169
|
-
import * as
|
|
16478
|
+
import { dirname as dirname12, relative as relative12, resolve as resolve21 } from "node:path";
|
|
16479
|
+
import * as ts17 from "@typescript/typescript6";
|
|
16170
16480
|
function hash3(value) {
|
|
16171
|
-
return
|
|
16481
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
16172
16482
|
}
|
|
16173
16483
|
function importPath(out, path) {
|
|
16174
16484
|
const value = relative12(out, path).replaceAll("\\", "/").replace(/\.(?:d\.)?[cm]?ts$/, "");
|
|
@@ -16193,33 +16503,33 @@ function parseDatabaseContractsOptions(value, directory) {
|
|
|
16193
16503
|
throw new TypeError("migrations must be an ordered list of SQL files");
|
|
16194
16504
|
}
|
|
16195
16505
|
return {
|
|
16196
|
-
rootDir:
|
|
16197
|
-
outDir:
|
|
16198
|
-
postgrestTypes:
|
|
16199
|
-
drizzleSchema:
|
|
16506
|
+
rootDir: resolve21(directory, field("rootDir")),
|
|
16507
|
+
outDir: resolve21(directory, field("outDir")),
|
|
16508
|
+
postgrestTypes: resolve21(directory, field("postgrestTypes")),
|
|
16509
|
+
drizzleSchema: resolve21(directory, field("drizzleSchema")),
|
|
16200
16510
|
role: field("role"),
|
|
16201
|
-
graphql: { ...graphql, schema:
|
|
16202
|
-
migrations: migrations.map((file) =>
|
|
16511
|
+
graphql: { ...graphql, schema: resolve21(directory, graphql.schema) },
|
|
16512
|
+
migrations: migrations.map((file) => resolve21(directory, file))
|
|
16203
16513
|
};
|
|
16204
16514
|
}
|
|
16205
16515
|
async function generateDatabaseContracts(options, check = false) {
|
|
16206
|
-
const rootDir =
|
|
16207
|
-
const postgrestTypes =
|
|
16516
|
+
const rootDir = resolve21(options.rootDir), outDir = resolve21(options.outDir);
|
|
16517
|
+
const postgrestTypes = resolve21(rootDir, options.postgrestTypes), drizzleSchema = resolve21(rootDir, options.drizzleSchema);
|
|
16208
16518
|
const snapshot = await readFile13(postgrestTypes, "utf8");
|
|
16209
|
-
const syntax =
|
|
16210
|
-
const database = syntax.statements.find((node) => (
|
|
16519
|
+
const syntax = ts17.createSourceFile(postgrestTypes, snapshot, ts17.ScriptTarget.Latest, true);
|
|
16520
|
+
const database = syntax.statements.find((node) => (ts17.isTypeAliasDeclaration(node) || ts17.isInterfaceDeclaration(node)) && node.name.text === "Database" && node.modifiers?.some((modifier) => modifier.kind === ts17.SyntaxKind.ExportKeyword));
|
|
16211
16521
|
if (!database)
|
|
16212
16522
|
throw new Error("PostgREST snapshot must export Database from the official type generator");
|
|
16213
|
-
const program =
|
|
16523
|
+
const program = ts17.createProgram([postgrestTypes], {
|
|
16214
16524
|
strict: true,
|
|
16215
16525
|
noEmit: true,
|
|
16216
16526
|
skipLibCheck: true,
|
|
16217
16527
|
types: [],
|
|
16218
|
-
target:
|
|
16219
|
-
module:
|
|
16220
|
-
moduleResolution:
|
|
16528
|
+
target: ts17.ScriptTarget.ES2022,
|
|
16529
|
+
module: ts17.ModuleKind.ESNext,
|
|
16530
|
+
moduleResolution: ts17.ModuleResolutionKind.Bundler
|
|
16221
16531
|
});
|
|
16222
|
-
if (
|
|
16532
|
+
if (ts17.getPreEmitDiagnostics(program).length)
|
|
16223
16533
|
throw new Error("PostgREST snapshot has TypeScript errors");
|
|
16224
16534
|
const artifacts = await renderGraphql({
|
|
16225
16535
|
rootDir,
|
|
@@ -16232,16 +16542,16 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
16232
16542
|
}
|
|
16233
16543
|
const inputs = {};
|
|
16234
16544
|
const addInput = async (path) => {
|
|
16235
|
-
const absolute =
|
|
16545
|
+
const absolute = resolve21(rootDir, path);
|
|
16236
16546
|
inputs[relative12(rootDir, absolute).replaceAll("\\", "/")] = hash3(await readFile13(absolute, "utf8"));
|
|
16237
16547
|
};
|
|
16238
16548
|
await addInput(postgrestTypes);
|
|
16239
16549
|
await addInput(drizzleSchema);
|
|
16240
|
-
const drizzleProgram =
|
|
16550
|
+
const drizzleProgram = ts17.createProgram([drizzleSchema], {
|
|
16241
16551
|
noEmit: true,
|
|
16242
|
-
moduleResolution:
|
|
16243
|
-
module:
|
|
16244
|
-
target:
|
|
16552
|
+
moduleResolution: ts17.ModuleResolutionKind.Bundler,
|
|
16553
|
+
module: ts17.ModuleKind.ESNext,
|
|
16554
|
+
target: ts17.ScriptTarget.ES2022,
|
|
16245
16555
|
types: [],
|
|
16246
16556
|
skipLibCheck: true
|
|
16247
16557
|
});
|
|
@@ -16249,8 +16559,8 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
16249
16559
|
if (!source.isDeclarationFile && !source.fileName.includes("/node_modules/"))
|
|
16250
16560
|
await addInput(source.fileName);
|
|
16251
16561
|
}
|
|
16252
|
-
await addInput(
|
|
16253
|
-
if (new Set(options.migrations.map((path) =>
|
|
16562
|
+
await addInput(resolve21(rootDir, options.graphql.schema));
|
|
16563
|
+
if (new Set(options.migrations.map((path) => resolve21(rootDir, path))).size !== options.migrations.length) {
|
|
16254
16564
|
throw new Error("Duplicate migration in database contracts configuration");
|
|
16255
16565
|
}
|
|
16256
16566
|
for (const path of options.migrations)
|
|
@@ -16271,14 +16581,14 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
16271
16581
|
version: 1,
|
|
16272
16582
|
role: options.role,
|
|
16273
16583
|
inputs: Object.fromEntries(Object.entries(inputs).sort(([a], [b]) => a.localeCompare(b))),
|
|
16274
|
-
migrationOrder: options.migrations.map((path) => relative12(rootDir,
|
|
16584
|
+
migrationOrder: options.migrations.map((path) => relative12(rootDir, resolve21(rootDir, path)).replaceAll("\\", "/")),
|
|
16275
16585
|
outputs: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([file, text]) => [file, hash3(text)]))
|
|
16276
16586
|
};
|
|
16277
16587
|
files["database.manifest.json"] = JSON.stringify(manifest, null, 2) + `
|
|
16278
16588
|
`;
|
|
16279
16589
|
const mismatches = [];
|
|
16280
16590
|
for (const [file, content] of Object.entries(files)) {
|
|
16281
|
-
const path =
|
|
16591
|
+
const path = resolve21(outDir, file);
|
|
16282
16592
|
let current;
|
|
16283
16593
|
try {
|
|
16284
16594
|
current = await readFile13(path, "utf8");
|
|
@@ -16292,12 +16602,12 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
16292
16602
|
if (!check) {
|
|
16293
16603
|
await mkdir6(outDir, { recursive: true });
|
|
16294
16604
|
for (const [file, content] of Object.entries(files))
|
|
16295
|
-
await writeFileIfChanged(
|
|
16605
|
+
await writeFileIfChanged(resolve21(outDir, file), content);
|
|
16296
16606
|
}
|
|
16297
16607
|
return { upToDate: mismatches.length === 0, mismatches, written: check ? [] : mismatches, manifest };
|
|
16298
16608
|
}
|
|
16299
16609
|
async function runDatabaseContractsFile(path, check = false) {
|
|
16300
|
-
const absolute =
|
|
16610
|
+
const absolute = resolve21(path);
|
|
16301
16611
|
const value = JSON.parse(await readFile13(absolute, "utf8"));
|
|
16302
16612
|
return generateDatabaseContracts(parseDatabaseContractsOptions(value, dirname12(absolute)), check);
|
|
16303
16613
|
}
|
|
@@ -16310,7 +16620,7 @@ var init_database_contracts = __esm(() => {
|
|
|
16310
16620
|
// src/analyze.ts
|
|
16311
16621
|
import { createHash as createHash3 } from "node:crypto";
|
|
16312
16622
|
import { relative as relative2, resolve as resolvePath, sep as sep2 } from "node:path";
|
|
16313
|
-
import * as
|
|
16623
|
+
import * as ts7 from "@typescript/typescript6";
|
|
16314
16624
|
|
|
16315
16625
|
// src/program.ts
|
|
16316
16626
|
import { createHash as createHash2 } from "node:crypto";
|
|
@@ -16646,12 +16956,258 @@ function readProjectConfig(rootDir) {
|
|
|
16646
16956
|
init_validate();
|
|
16647
16957
|
|
|
16648
16958
|
// src/static-di.ts
|
|
16959
|
+
import * as ts6 from "@typescript/typescript6";
|
|
16960
|
+
|
|
16961
|
+
// src/reactive-analysis.ts
|
|
16962
|
+
import * as ts4 from "@typescript/typescript6";
|
|
16963
|
+
|
|
16964
|
+
// src/api-source.ts
|
|
16649
16965
|
import * as ts3 from "@typescript/typescript6";
|
|
16966
|
+
import { resolve as resolve2 } from "node:path";
|
|
16967
|
+
function bindApiSource(source) {
|
|
16968
|
+
const file = resolve2(source.fileName);
|
|
16969
|
+
const bound = ts3.createSourceFile(file, source.text, ts3.ScriptTarget.Latest, true);
|
|
16970
|
+
const options = { noLib: true, noResolve: true, target: ts3.ScriptTarget.ES2022 };
|
|
16971
|
+
const host = {
|
|
16972
|
+
getSourceFile: (name) => resolve2(name) === file ? bound : undefined,
|
|
16973
|
+
getDefaultLibFileName: () => "",
|
|
16974
|
+
writeFile: () => {},
|
|
16975
|
+
getCurrentDirectory: () => process.cwd(),
|
|
16976
|
+
getDirectories: () => [],
|
|
16977
|
+
fileExists: (name) => resolve2(name) === file,
|
|
16978
|
+
readFile: (name) => resolve2(name) === file ? source.text : undefined,
|
|
16979
|
+
getCanonicalFileName: (name) => name,
|
|
16980
|
+
useCaseSensitiveFileNames: () => true,
|
|
16981
|
+
getNewLine: () => `
|
|
16982
|
+
`
|
|
16983
|
+
};
|
|
16984
|
+
const program = ts3.createProgram([file], options, host);
|
|
16985
|
+
return { source: bound, checker: program.getTypeChecker() };
|
|
16986
|
+
}
|
|
16987
|
+
function importedFrom(node) {
|
|
16988
|
+
let current = node;
|
|
16989
|
+
while (current && !ts3.isImportDeclaration(current))
|
|
16990
|
+
current = current.parent;
|
|
16991
|
+
return current && ts3.isImportDeclaration(current) && ts3.isStringLiteral(current.moduleSpecifier) ? current.moduleSpecifier.text : undefined;
|
|
16992
|
+
}
|
|
16993
|
+
function apiOrigin(expression, checker, seen = new Set) {
|
|
16994
|
+
if (seen.has(expression))
|
|
16995
|
+
return;
|
|
16996
|
+
seen.add(expression);
|
|
16997
|
+
if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isSatisfiesExpression(expression) || ts3.isTypeAssertionExpression(expression)) {
|
|
16998
|
+
return apiOrigin(expression.expression, checker, seen);
|
|
16999
|
+
}
|
|
17000
|
+
if (ts3.isPropertyAccessExpression(expression) || ts3.isElementAccessExpression(expression)) {
|
|
17001
|
+
const name = ts3.isPropertyAccessExpression(expression) ? expression.name.text : ts3.isStringLiteral(expression.argumentExpression) ? expression.argumentExpression.text : undefined;
|
|
17002
|
+
const namespace = apiOrigin(expression.expression, checker, seen);
|
|
17003
|
+
return namespace?.name === "*" && name ? { module: namespace.module, name } : undefined;
|
|
17004
|
+
}
|
|
17005
|
+
if (!ts3.isIdentifier(expression))
|
|
17006
|
+
return;
|
|
17007
|
+
const symbol = checker.getSymbolAtLocation(expression);
|
|
17008
|
+
for (const declaration of symbol?.declarations ?? []) {
|
|
17009
|
+
if (ts3.isImportSpecifier(declaration) && !declaration.isTypeOnly && !declaration.parent.parent.isTypeOnly) {
|
|
17010
|
+
const module = importedFrom(declaration);
|
|
17011
|
+
if (module)
|
|
17012
|
+
return { module, name: (declaration.propertyName ?? declaration.name).text };
|
|
17013
|
+
}
|
|
17014
|
+
if (ts3.isNamespaceImport(declaration) && !declaration.parent.isTypeOnly) {
|
|
17015
|
+
const module = importedFrom(declaration);
|
|
17016
|
+
if (module)
|
|
17017
|
+
return { module, name: "*" };
|
|
17018
|
+
}
|
|
17019
|
+
if (ts3.isVariableDeclaration(declaration) && declaration.initializer && ts3.isVariableDeclarationList(declaration.parent) && declaration.parent.flags & ts3.NodeFlags.Const) {
|
|
17020
|
+
return apiOrigin(declaration.initializer, checker, seen);
|
|
17021
|
+
}
|
|
17022
|
+
}
|
|
17023
|
+
return;
|
|
17024
|
+
}
|
|
17025
|
+
|
|
17026
|
+
// src/reactive-analysis.ts
|
|
17027
|
+
var angularState = new Set(["@angular/core", "@supacloud/app/angular"]);
|
|
17028
|
+
var signalBridges = new Set(["@angular/core/rxjs-interop", "@supacloud/app/angular", "@supacloud/app/rxjs"]);
|
|
17029
|
+
function scanReactiveSource(input, file) {
|
|
17030
|
+
if (!input.statements.some((node) => ts4.isImportDeclaration(node) && ts4.isStringLiteral(node.moduleSpecifier) && (angularState.has(node.moduleSpecifier.text) || signalBridges.has(node.moduleSpecifier.text))))
|
|
17031
|
+
return [];
|
|
17032
|
+
const { source, checker } = bindApiSource(input);
|
|
17033
|
+
const diagnostics = [];
|
|
17034
|
+
const reported = new Set;
|
|
17035
|
+
const visit = (node, reactive) => {
|
|
17036
|
+
if (ts4.isCallExpression(node)) {
|
|
17037
|
+
const origin = apiOrigin(node.expression, checker);
|
|
17038
|
+
if (reactive && origin && signalBridges.has(origin.module) && ["toSignal", "toScopedSignal", "rxResource"].includes(origin.name) && !reported.has(node.pos)) {
|
|
17039
|
+
reported.add(node.pos);
|
|
17040
|
+
const start = source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
17041
|
+
const end = source.getLineAndCharacterOfPosition(node.end);
|
|
17042
|
+
diagnostics.push({
|
|
17043
|
+
severity: "error",
|
|
17044
|
+
code: "reactive-subscription-in-computation",
|
|
17045
|
+
file,
|
|
17046
|
+
line: start.line + 1,
|
|
17047
|
+
column: start.character,
|
|
17048
|
+
endLine: end.line + 1,
|
|
17049
|
+
endColumn: end.character,
|
|
17050
|
+
message: `${origin.name} creates a subscription inside a reactive computation.`,
|
|
17051
|
+
suggestion: "Create the subscription once in its explicit owner scope, then derive state with computed. Hoisting requires ownership review; no automatic edit is safe.",
|
|
17052
|
+
docsUrl: "https://supacloud.dev/errors/reactive-subscription-in-computation"
|
|
17053
|
+
});
|
|
17054
|
+
}
|
|
17055
|
+
if (origin && angularState.has(origin.module) && ["computed", "effect", "untracked"].includes(origin.name)) {
|
|
17056
|
+
const callback = node.arguments[0];
|
|
17057
|
+
if (callback && (ts4.isArrowFunction(callback) || ts4.isFunctionExpression(callback))) {
|
|
17058
|
+
visit(callback.body, origin.name === "untracked" ? false : true);
|
|
17059
|
+
for (const argument of node.arguments.slice(1))
|
|
17060
|
+
visit(argument, reactive);
|
|
17061
|
+
return;
|
|
17062
|
+
}
|
|
17063
|
+
}
|
|
17064
|
+
let expression = node.expression;
|
|
17065
|
+
while (ts4.isParenthesizedExpression(expression))
|
|
17066
|
+
expression = expression.expression;
|
|
17067
|
+
if (ts4.isArrowFunction(expression) || ts4.isFunctionExpression(expression))
|
|
17068
|
+
visit(expression.body, reactive);
|
|
17069
|
+
}
|
|
17070
|
+
if (ts4.isFunctionLike(node)) {
|
|
17071
|
+
if (!reactive)
|
|
17072
|
+
ts4.forEachChild(node, (child) => visit(child, false));
|
|
17073
|
+
return;
|
|
17074
|
+
}
|
|
17075
|
+
ts4.forEachChild(node, (child) => visit(child, reactive));
|
|
17076
|
+
};
|
|
17077
|
+
visit(source, false);
|
|
17078
|
+
return diagnostics;
|
|
17079
|
+
}
|
|
17080
|
+
|
|
17081
|
+
// src/http-provider-migration.ts
|
|
17082
|
+
import * as ts5 from "@typescript/typescript6";
|
|
17083
|
+
function providerArgument(node, checker) {
|
|
17084
|
+
let current = node;
|
|
17085
|
+
while (ts5.isParenthesizedExpression(current.parent))
|
|
17086
|
+
current = current.parent;
|
|
17087
|
+
if (!ts5.isCallExpression(current.parent) || current.parent.expression !== current)
|
|
17088
|
+
return false;
|
|
17089
|
+
current = current.parent;
|
|
17090
|
+
while (ts5.isParenthesizedExpression(current.parent))
|
|
17091
|
+
current = current.parent;
|
|
17092
|
+
const parent = current.parent;
|
|
17093
|
+
if (!ts5.isCallExpression(parent) || !parent.arguments.some((argument) => argument === current))
|
|
17094
|
+
return false;
|
|
17095
|
+
const owner = apiOrigin(parent.expression, checker);
|
|
17096
|
+
return owner?.name === "provideHttpClient" && ["@supacloud/app", "@supacloud/app/http"].includes(owner.module);
|
|
17097
|
+
}
|
|
17098
|
+
function migrateHttpProviderImports(source, fileName) {
|
|
17099
|
+
const bound = bindApiSource(ts5.createSourceFile(fileName, source, ts5.ScriptTarget.Latest, true));
|
|
17100
|
+
const { source: sf, checker } = bound;
|
|
17101
|
+
const edits = [];
|
|
17102
|
+
const issues = [];
|
|
17103
|
+
const printer = ts5.createPrinter({ newLine: source.includes(`\r
|
|
17104
|
+
`) ? ts5.NewLineKind.CarriageReturnLineFeed : ts5.NewLineKind.LineFeed });
|
|
17105
|
+
const newline = source.includes(`\r
|
|
17106
|
+
`) ? `\r
|
|
17107
|
+
` : `
|
|
17108
|
+
`;
|
|
17109
|
+
for (const statement of sf.statements) {
|
|
17110
|
+
if (!ts5.isImportDeclaration(statement) || !ts5.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@supacloud/app" || !statement.importClause || statement.importClause.isTypeOnly)
|
|
17111
|
+
continue;
|
|
17112
|
+
const named = statement.importClause.namedBindings;
|
|
17113
|
+
if (!named || !ts5.isNamedImports(named))
|
|
17114
|
+
continue;
|
|
17115
|
+
const specifier = named.elements.find((item) => !item.isTypeOnly && (item.propertyName ?? item.name).text === "withInterceptors");
|
|
17116
|
+
if (!specifier)
|
|
17117
|
+
continue;
|
|
17118
|
+
const symbol = checker.getSymbolAtLocation(specifier.name);
|
|
17119
|
+
if (!symbol)
|
|
17120
|
+
continue;
|
|
17121
|
+
const uses = [];
|
|
17122
|
+
const visit = (node) => {
|
|
17123
|
+
if (ts5.isImportDeclaration(node))
|
|
17124
|
+
return;
|
|
17125
|
+
if (ts5.isIdentifier(node) && checker.getSymbolAtLocation(node) === symbol)
|
|
17126
|
+
uses.push(node);
|
|
17127
|
+
ts5.forEachChild(node, visit);
|
|
17128
|
+
};
|
|
17129
|
+
visit(sf);
|
|
17130
|
+
if (!uses.some((node) => providerArgument(node, checker)))
|
|
17131
|
+
continue;
|
|
17132
|
+
if (!uses.every((node) => providerArgument(node, checker)) || statement.attributes) {
|
|
17133
|
+
issues.push({
|
|
17134
|
+
code: "http-provider-migration-ambiguous",
|
|
17135
|
+
file: fileName,
|
|
17136
|
+
line: sf.getLineAndCharacterOfPosition(specifier.getStart(sf)).line + 1,
|
|
17137
|
+
message: "withInterceptors also has non-provider uses; split the bindings manually before migration."
|
|
17138
|
+
});
|
|
17139
|
+
continue;
|
|
17140
|
+
}
|
|
17141
|
+
const remaining = named.elements.filter((item) => item !== specifier);
|
|
17142
|
+
if (remaining.length === 0 && !statement.importClause.name) {
|
|
17143
|
+
edits.push({ start: statement.moduleSpecifier.getStart(sf), end: statement.moduleSpecifier.end, text: '"@supacloud/app/http"' });
|
|
17144
|
+
} else {
|
|
17145
|
+
const clause = ts5.factory.updateImportClause(statement.importClause, false, statement.importClause.name, remaining.length ? ts5.factory.updateNamedImports(named, remaining) : undefined);
|
|
17146
|
+
const updated = ts5.factory.updateImportDeclaration(statement, statement.modifiers, clause, statement.moduleSpecifier, statement.attributes);
|
|
17147
|
+
const text = printer.printNode(ts5.EmitHint.Unspecified, updated, sf).trimStart() + newline + `import { ${specifier.getText(sf)} } from "@supacloud/app/http";`;
|
|
17148
|
+
const withoutLeading = text.replace(/^(?:\/\/[^\n]*\n|\/\*[\s\S]*?\*\/\s*)+/, "");
|
|
17149
|
+
edits.push({ start: statement.getStart(sf), end: statement.end, text: withoutLeading });
|
|
17150
|
+
}
|
|
17151
|
+
}
|
|
17152
|
+
const checkNamespace = (node) => {
|
|
17153
|
+
if ((ts5.isPropertyAccessExpression(node) || ts5.isElementAccessExpression(node)) && providerArgument(node, checker)) {
|
|
17154
|
+
const origin = apiOrigin(node, checker);
|
|
17155
|
+
if (origin?.module === "@supacloud/app" && origin.name === "withInterceptors")
|
|
17156
|
+
issues.push({
|
|
17157
|
+
code: "http-provider-migration-namespace",
|
|
17158
|
+
file: fileName,
|
|
17159
|
+
line: sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1,
|
|
17160
|
+
message: "Use a dedicated named import from @supacloud/app/http; namespace rewrites require manual review."
|
|
17161
|
+
});
|
|
17162
|
+
}
|
|
17163
|
+
ts5.forEachChild(node, checkNamespace);
|
|
17164
|
+
};
|
|
17165
|
+
checkNamespace(sf);
|
|
17166
|
+
if (issues.length)
|
|
17167
|
+
return { changed: false, content: source, replacements: 0, issues };
|
|
17168
|
+
let content = source;
|
|
17169
|
+
for (const edit of edits.sort((a, b) => b.start - a.start))
|
|
17170
|
+
content = content.slice(0, edit.start) + edit.text + content.slice(edit.end);
|
|
17171
|
+
return { changed: edits.length > 0, content, replacements: edits.length, issues: [] };
|
|
17172
|
+
}
|
|
17173
|
+
function scanHttpProviderImports(source, file) {
|
|
17174
|
+
if (!source.text.includes("@supacloud/app"))
|
|
17175
|
+
return [];
|
|
17176
|
+
const { source: sf, checker } = bindApiSource(source);
|
|
17177
|
+
const diagnostics = [];
|
|
17178
|
+
const visit = (node) => {
|
|
17179
|
+
if (ts5.isCallExpression(node)) {
|
|
17180
|
+
const origin = apiOrigin(node.expression, checker);
|
|
17181
|
+
if (origin?.module === "@supacloud/app" && origin.name === "withInterceptors" && providerArgument(node.expression, checker)) {
|
|
17182
|
+
const start = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
17183
|
+
const end = sf.getLineAndCharacterOfPosition(node.end);
|
|
17184
|
+
diagnostics.push({
|
|
17185
|
+
severity: "error",
|
|
17186
|
+
code: "http-provider-import-mismatch",
|
|
17187
|
+
file,
|
|
17188
|
+
line: start.line + 1,
|
|
17189
|
+
column: start.character,
|
|
17190
|
+
endLine: end.line + 1,
|
|
17191
|
+
endColumn: end.character,
|
|
17192
|
+
message: "The root withInterceptors returns an interceptor array, not a provideHttpClient feature.",
|
|
17193
|
+
suggestion: "Import withInterceptors from @supacloud/app/http. Preview the http-provider-entrypoint source migration; mixed/namespace uses require manual review.",
|
|
17194
|
+
docsUrl: "https://supacloud.dev/errors/http-provider-import-mismatch"
|
|
17195
|
+
});
|
|
17196
|
+
}
|
|
17197
|
+
}
|
|
17198
|
+
ts5.forEachChild(node, visit);
|
|
17199
|
+
};
|
|
17200
|
+
visit(sf);
|
|
17201
|
+
return diagnostics;
|
|
17202
|
+
}
|
|
17203
|
+
|
|
17204
|
+
// src/static-di.ts
|
|
16650
17205
|
var runtimeApis = new Set([
|
|
16651
17206
|
"inject",
|
|
16652
17207
|
"createEnvironmentInjector",
|
|
16653
17208
|
"runInInjectionContext",
|
|
16654
17209
|
"EnvironmentInjector",
|
|
17210
|
+
"Injector",
|
|
16655
17211
|
"bootstrapBun",
|
|
16656
17212
|
"runInScope",
|
|
16657
17213
|
"runInRequestContext",
|
|
@@ -16661,25 +17217,33 @@ var runtimeApis = new Set([
|
|
|
16661
17217
|
function scanRuntimeDi(source, file) {
|
|
16662
17218
|
const diagnostics = [];
|
|
16663
17219
|
const namespaces = new Set;
|
|
16664
|
-
const report = (node) =>
|
|
16665
|
-
|
|
16666
|
-
|
|
16667
|
-
|
|
16668
|
-
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
|
|
17220
|
+
const report = (node) => {
|
|
17221
|
+
const start = source.getLineAndCharacterOfPosition(node.getStart());
|
|
17222
|
+
const end = source.getLineAndCharacterOfPosition(node.end);
|
|
17223
|
+
diagnostics.push({
|
|
17224
|
+
severity: "error",
|
|
17225
|
+
code: "runtime-injection-disallowed",
|
|
17226
|
+
errorCode: "SC2012",
|
|
17227
|
+
docsUrl: "https://supacloud.dev/errors/SC2012",
|
|
17228
|
+
file,
|
|
17229
|
+
line: start.line + 1,
|
|
17230
|
+
column: start.character,
|
|
17231
|
+
endLine: end.line + 1,
|
|
17232
|
+
endColumn: end.character,
|
|
17233
|
+
message: "Compiled applications cannot import runtime DI. Use explicit constructors and generated scope factories.",
|
|
17234
|
+
suggestion: "Use constructor dependencies and generated request/job factories. Keep Angular runtime services outside the compiled application source root."
|
|
17235
|
+
});
|
|
17236
|
+
};
|
|
16673
17237
|
for (const statement of source.statements) {
|
|
16674
|
-
if (!(
|
|
17238
|
+
if (!(ts6.isImportDeclaration(statement) || ts6.isExportDeclaration(statement)) || !statement.moduleSpecifier || !ts6.isStringLiteral(statement.moduleSpecifier) || !(/^@supacloud\/app(?:\/|$)/.test(statement.moduleSpecifier.text) || statement.moduleSpecifier.text === "@angular/core"))
|
|
16675
17239
|
continue;
|
|
16676
|
-
if (
|
|
17240
|
+
if (ts6.isImportDeclaration(statement)) {
|
|
16677
17241
|
if (statement.importClause?.isTypeOnly)
|
|
16678
17242
|
continue;
|
|
16679
17243
|
const binding = statement.importClause?.namedBindings;
|
|
16680
|
-
if (binding &&
|
|
17244
|
+
if (binding && ts6.isNamespaceImport(binding))
|
|
16681
17245
|
namespaces.add(binding.name.text);
|
|
16682
|
-
if (binding &&
|
|
17246
|
+
if (binding && ts6.isNamedImports(binding))
|
|
16683
17247
|
for (const item of binding.elements) {
|
|
16684
17248
|
if (!item.isTypeOnly && runtimeApis.has((item.propertyName ?? item.name).text))
|
|
16685
17249
|
report(item);
|
|
@@ -16687,24 +17251,29 @@ function scanRuntimeDi(source, file) {
|
|
|
16687
17251
|
} else if (!statement.isTypeOnly) {
|
|
16688
17252
|
if (!statement.exportClause)
|
|
16689
17253
|
report(statement);
|
|
16690
|
-
else if (
|
|
17254
|
+
else if (ts6.isNamedExports(statement.exportClause))
|
|
16691
17255
|
for (const item of statement.exportClause.elements) {
|
|
16692
17256
|
if (!item.isTypeOnly && runtimeApis.has((item.propertyName ?? item.name).text))
|
|
16693
17257
|
report(item);
|
|
16694
17258
|
}
|
|
16695
17259
|
}
|
|
16696
17260
|
}
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16700
|
-
|
|
16701
|
-
|
|
16702
|
-
|
|
16703
|
-
|
|
16704
|
-
|
|
16705
|
-
|
|
16706
|
-
|
|
16707
|
-
|
|
17261
|
+
if (namespaces.size > 0) {
|
|
17262
|
+
const bound = bindApiSource(source);
|
|
17263
|
+
const protectedNamespace = (expression) => {
|
|
17264
|
+
const origin = apiOrigin(expression, bound.checker);
|
|
17265
|
+
return origin?.name === "*" && (origin.module === "@angular/core" || /^@supacloud\/app(?:\/|$)/.test(origin.module));
|
|
17266
|
+
};
|
|
17267
|
+
const visit = (node) => {
|
|
17268
|
+
if (ts6.isPropertyAccessExpression(node) && protectedNamespace(node.expression) && runtimeApis.has(node.name.text))
|
|
17269
|
+
report(node);
|
|
17270
|
+
if (ts6.isElementAccessExpression(node) && protectedNamespace(node.expression) && (!ts6.isStringLiteral(node.argumentExpression) || runtimeApis.has(node.argumentExpression.text)))
|
|
17271
|
+
report(node);
|
|
17272
|
+
ts6.forEachChild(node, visit);
|
|
17273
|
+
};
|
|
17274
|
+
visit(bound.source);
|
|
17275
|
+
}
|
|
17276
|
+
return [...diagnostics, ...scanReactiveSource(source, file), ...scanHttpProviderImports(source, file)];
|
|
16708
17277
|
}
|
|
16709
17278
|
|
|
16710
17279
|
// src/analyze.ts
|
|
@@ -16755,36 +17324,39 @@ function lineOf(node) {
|
|
|
16755
17324
|
return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
|
|
16756
17325
|
}
|
|
16757
17326
|
function variableName(decl) {
|
|
16758
|
-
return
|
|
17327
|
+
return ts7.isIdentifier(decl.name) ? decl.name.text : nodeText(decl.name);
|
|
16759
17328
|
}
|
|
16760
17329
|
function propertyName(name) {
|
|
16761
|
-
if (
|
|
17330
|
+
if (ts7.isIdentifier(name) || ts7.isPrivateIdentifier(name))
|
|
16762
17331
|
return name.text;
|
|
16763
|
-
if (
|
|
17332
|
+
if (ts7.isStringLiteral(name) || ts7.isNumericLiteral(name))
|
|
16764
17333
|
return name.text;
|
|
16765
17334
|
return nodeText(name);
|
|
16766
17335
|
}
|
|
16767
17336
|
function parameterName(param) {
|
|
16768
|
-
return
|
|
17337
|
+
return ts7.isIdentifier(param.name) ? param.name.text : nodeText(param.name);
|
|
16769
17338
|
}
|
|
16770
17339
|
function decoratorsOf(node) {
|
|
16771
|
-
return
|
|
17340
|
+
return ts7.canHaveDecorators(node) ? ts7.getDecorators(node) ?? [] : [];
|
|
16772
17341
|
}
|
|
16773
17342
|
function decoratorArguments(dec) {
|
|
16774
|
-
return
|
|
17343
|
+
return ts7.isCallExpression(dec.expression) ? dec.expression.arguments : [];
|
|
16775
17344
|
}
|
|
16776
17345
|
function hasMethod(cls, name) {
|
|
16777
|
-
return cls.members.some((member) => (
|
|
17346
|
+
return cls.members.some((member) => (ts7.isMethodDeclaration(member) || ts7.isGetAccessorDeclaration(member) || ts7.isSetAccessorDeclaration(member)) && member.name !== undefined && propertyName(member.name) === name);
|
|
16778
17347
|
}
|
|
16779
17348
|
function hasDestroyHook(cls) {
|
|
16780
17349
|
return hasMethod(cls, "onDestroy") || hasMethod(cls, "ngOnDestroy");
|
|
16781
17350
|
}
|
|
17351
|
+
function hasInitHook(cls) {
|
|
17352
|
+
return hasMethod(cls, "onInit");
|
|
17353
|
+
}
|
|
16782
17354
|
function descendantsOfKind(root, predicate) {
|
|
16783
17355
|
const result = [];
|
|
16784
17356
|
const visit = (node) => {
|
|
16785
17357
|
if (predicate(node))
|
|
16786
17358
|
result.push(node);
|
|
16787
|
-
|
|
17359
|
+
ts7.forEachChild(node, visit);
|
|
16788
17360
|
};
|
|
16789
17361
|
visit(root);
|
|
16790
17362
|
return result;
|
|
@@ -16793,7 +17365,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
16793
17365
|
const session = cache?.programSession ?? createIncrementalProgramSession(rootDir);
|
|
16794
17366
|
if (cache)
|
|
16795
17367
|
cache.programSession = session;
|
|
16796
|
-
const rootNames =
|
|
17368
|
+
const rootNames = ts7.sys.readDirectory(rootDir, [".ts", ".tsx"], ["node_modules", "dist"], include ?? DEFAULT_INCLUDE);
|
|
16797
17369
|
const update = session.update(rootNames, changedPaths);
|
|
16798
17370
|
const program = update.program;
|
|
16799
17371
|
const checker = program.getTypeChecker();
|
|
@@ -16829,7 +17401,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
16829
17401
|
for (const sf of sourceFiles) {
|
|
16830
17402
|
const traits = nativeTraitFiles.get(sf.fileName);
|
|
16831
17403
|
if (!cache || traits?.has("module")) {
|
|
16832
|
-
for (const cls of sf.statements.filter(
|
|
17404
|
+
for (const cls of sf.statements.filter(ts7.isClassDeclaration)) {
|
|
16833
17405
|
const moduleDec = findDecorator(cls, "Module");
|
|
16834
17406
|
if (!moduleDec)
|
|
16835
17407
|
continue;
|
|
@@ -16846,14 +17418,14 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
16846
17418
|
}
|
|
16847
17419
|
}
|
|
16848
17420
|
if (!cache || traits?.has("defineModule") || traits?.has("defineFeatureSlice")) {
|
|
16849
|
-
for (const call of descendantsOfKind(sf,
|
|
17421
|
+
for (const call of descendantsOfKind(sf, ts7.isCallExpression)) {
|
|
16850
17422
|
if (!["defineModule", "defineFeatureSlice"].includes(nodeText(call.expression)))
|
|
16851
17423
|
continue;
|
|
16852
17424
|
const parent = call.parent;
|
|
16853
|
-
if (!parent || !
|
|
17425
|
+
if (!parent || !ts7.isVariableDeclaration(parent))
|
|
16854
17426
|
continue;
|
|
16855
17427
|
const arg = call.arguments[0];
|
|
16856
|
-
if (!arg || !
|
|
17428
|
+
if (!arg || !ts7.isObjectLiteralExpression(arg))
|
|
16857
17429
|
continue;
|
|
16858
17430
|
candidates.push({
|
|
16859
17431
|
node: parent,
|
|
@@ -16989,6 +17561,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
16989
17561
|
...functionalInjects.length > 0 ? { functionalInjects } : {},
|
|
16990
17562
|
providedIn: "root",
|
|
16991
17563
|
...hasDestroyHook(classInfo.decl) ? { hasOnDestroy: true } : {},
|
|
17564
|
+
...hasInitHook(classInfo.decl) ? { hasOnInit: true } : {},
|
|
16992
17565
|
exported: true,
|
|
16993
17566
|
file,
|
|
16994
17567
|
line,
|
|
@@ -17000,7 +17573,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths) {
|
|
|
17000
17573
|
const controllerDec = findDecorator(classInfo.decl, "Controller");
|
|
17001
17574
|
if (controllerDec) {
|
|
17002
17575
|
const arg = decoratorArguments(controllerDec)[0];
|
|
17003
|
-
const isStandalone = arg &&
|
|
17576
|
+
const isStandalone = arg && ts7.isObjectLiteralExpression(arg) && booleanProp(arg, "standalone");
|
|
17004
17577
|
if (isStandalone) {
|
|
17005
17578
|
const ctrl = parseController(classInfo.decl, ctx);
|
|
17006
17579
|
if (ctrl)
|
|
@@ -17160,16 +17733,16 @@ function collectModuleSourceClosure(module, ctx) {
|
|
|
17160
17733
|
ownedFiles.add(relativeFile);
|
|
17161
17734
|
for (const statement of sourceFile.statements) {
|
|
17162
17735
|
let moduleName;
|
|
17163
|
-
if (
|
|
17736
|
+
if (ts7.isImportDeclaration(statement) && ts7.isStringLiteral(statement.moduleSpecifier)) {
|
|
17164
17737
|
moduleName = statement.moduleSpecifier.text;
|
|
17165
|
-
} else if (
|
|
17738
|
+
} else if (ts7.isExportDeclaration(statement) && statement.moduleSpecifier && ts7.isStringLiteral(statement.moduleSpecifier)) {
|
|
17166
17739
|
moduleName = statement.moduleSpecifier.text;
|
|
17167
|
-
} else if (
|
|
17740
|
+
} else if (ts7.isImportEqualsDeclaration(statement) && ts7.isExternalModuleReference(statement.moduleReference) && ts7.isStringLiteral(statement.moduleReference.expression)) {
|
|
17168
17741
|
moduleName = statement.moduleReference.expression.text;
|
|
17169
17742
|
}
|
|
17170
17743
|
if (!moduleName || moduleName.startsWith("node:"))
|
|
17171
17744
|
continue;
|
|
17172
|
-
const resolved =
|
|
17745
|
+
const resolved = ts7.resolveModuleName(moduleName, sourceFile.fileName, ctx.program.getCompilerOptions(), ts7.sys).resolvedModule?.resolvedFileName;
|
|
17173
17746
|
if (resolved && isProjectSourcePath(resolved, ctx.rootDir) && !enqueued.has(resolved)) {
|
|
17174
17747
|
enqueued.add(resolved);
|
|
17175
17748
|
queue.push(resolved);
|
|
@@ -17191,7 +17764,7 @@ function isProjectSourceFile(sourceFile, rootDir) {
|
|
|
17191
17764
|
return isProjectSourcePath(sourceFile.fileName, rootDir) && /\.(tsx?|mts|cts)$/.test(sourceFile.fileName);
|
|
17192
17765
|
}
|
|
17193
17766
|
function indexFile(sf, ctx) {
|
|
17194
|
-
for (const cls of sf.statements.filter(
|
|
17767
|
+
for (const cls of sf.statements.filter(ts7.isClassDeclaration)) {
|
|
17195
17768
|
const name = cls.name?.text;
|
|
17196
17769
|
if (name && !ctx.classesByName.has(name)) {
|
|
17197
17770
|
ctx.classesByName.set(name, { name, decl: cls, file: sf.fileName });
|
|
@@ -17199,9 +17772,9 @@ function indexFile(sf, ctx) {
|
|
|
17199
17772
|
if (name)
|
|
17200
17773
|
indexInfraResource(cls, name, sf, ctx);
|
|
17201
17774
|
}
|
|
17202
|
-
for (const statement of sf.statements.filter(
|
|
17775
|
+
for (const statement of sf.statements.filter(ts7.isVariableStatement)) {
|
|
17203
17776
|
for (const decl of statement.declarationList.declarations) {
|
|
17204
|
-
if (
|
|
17777
|
+
if (ts7.isIdentifier(decl.name) && !ctx.variablesByName.has(decl.name.text)) {
|
|
17205
17778
|
ctx.variablesByName.set(decl.name.text, decl);
|
|
17206
17779
|
}
|
|
17207
17780
|
const info = parseTokenVariable(decl, sf.fileName);
|
|
@@ -17213,16 +17786,16 @@ function indexFile(sf, ctx) {
|
|
|
17213
17786
|
}
|
|
17214
17787
|
function parseTokenVariable(decl, file) {
|
|
17215
17788
|
const init = decl.initializer;
|
|
17216
|
-
if (!init || !
|
|
17789
|
+
if (!init || !ts7.isNewExpression(init))
|
|
17217
17790
|
return;
|
|
17218
17791
|
if (nodeText(init.expression) !== "InjectionToken")
|
|
17219
17792
|
return;
|
|
17220
17793
|
const [nameArg, optionsArg] = init.arguments ?? [];
|
|
17221
17794
|
const info = { name: variableName(decl), file, line: lineOf(decl) };
|
|
17222
|
-
if (nameArg &&
|
|
17795
|
+
if (nameArg && ts7.isStringLiteral(nameArg)) {
|
|
17223
17796
|
info.stringName = nameArg.text;
|
|
17224
17797
|
}
|
|
17225
|
-
if (optionsArg &&
|
|
17798
|
+
if (optionsArg && ts7.isObjectLiteralExpression(optionsArg)) {
|
|
17226
17799
|
const scope = stringLiteralProp(optionsArg, "scope");
|
|
17227
17800
|
if (scope && isScope(scope)) {
|
|
17228
17801
|
info.scope = scope;
|
|
@@ -17242,23 +17815,23 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
17242
17815
|
const { options, className, file, line } = candidate;
|
|
17243
17816
|
const name = nameByNode.get(candidate.node) ?? className;
|
|
17244
17817
|
const featureSpec = parseFeatureSpec(getProp(options, "spec"), ctx);
|
|
17245
|
-
const tags = arrayProp(options, "tags").map((el) =>
|
|
17818
|
+
const tags = arrayProp(options, "tags").map((el) => ts7.isStringLiteral(el) ? el.text : nodeText(el).replace(/['"]/g, "")).filter(Boolean);
|
|
17246
17819
|
const aspects = parseAspectRefs(getProp(options, "aspects"), ctx, `module ${name}`);
|
|
17247
17820
|
const moduleResourceNames = parseModuleInfraResources(infraResourceProp(options, "resources", ctx), ctx, `module ${name}`, sourcePath(ctx.rootDir, file), line);
|
|
17248
17821
|
const imports = arrayProp(options, "imports").map((el) => {
|
|
17249
17822
|
const unwrapped = unwrapForwardRef(el);
|
|
17250
|
-
const decl =
|
|
17823
|
+
const decl = ts7.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
|
|
17251
17824
|
if (decl) {
|
|
17252
17825
|
const known = nameByNode.get(decl);
|
|
17253
17826
|
if (known)
|
|
17254
17827
|
return known;
|
|
17255
|
-
if (
|
|
17828
|
+
if (ts7.isClassDeclaration(decl)) {
|
|
17256
17829
|
const dec = findDecorator(decl, "Module");
|
|
17257
17830
|
const decOptions = dec && decoratorObjectArg(dec);
|
|
17258
17831
|
const decName = decOptions && stringLiteralProp(decOptions, "name");
|
|
17259
17832
|
return decName ?? decl.name?.text ?? nodeText(el);
|
|
17260
17833
|
}
|
|
17261
|
-
if (
|
|
17834
|
+
if (ts7.isVariableDeclaration(decl))
|
|
17262
17835
|
return variableName(decl);
|
|
17263
17836
|
}
|
|
17264
17837
|
return nodeText(el);
|
|
@@ -17272,7 +17845,7 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
17272
17845
|
providers.push(...parsedProviders);
|
|
17273
17846
|
continue;
|
|
17274
17847
|
}
|
|
17275
|
-
if (
|
|
17848
|
+
if (ts7.isCallExpression(el)) {
|
|
17276
17849
|
const helper = nodeText(el.expression).split(".").pop() ?? nodeText(el.expression);
|
|
17277
17850
|
warn(ctx, "unsupported-provider-helper", `无法静态展开 provider helper '${helper}';请改用显式 Provider 或实现编译器支持的 helper`, sourcePath(ctx.rootDir, el.getSourceFile().fileName), lineOf(el));
|
|
17278
17851
|
continue;
|
|
@@ -17282,10 +17855,10 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
17282
17855
|
providers.push(provider);
|
|
17283
17856
|
}
|
|
17284
17857
|
for (const el of arrayProp(options, "jobs")) {
|
|
17285
|
-
if (!
|
|
17858
|
+
if (!ts7.isIdentifier(el))
|
|
17286
17859
|
continue;
|
|
17287
17860
|
const decl = resolveDeclaration(el, ctx)[0];
|
|
17288
|
-
if (!decl || !
|
|
17861
|
+
if (!decl || !ts7.isClassDeclaration(decl))
|
|
17289
17862
|
continue;
|
|
17290
17863
|
const className = decl.name?.text ?? el.text;
|
|
17291
17864
|
const registeredProvider = providers.find((provider) => provider.token === className || provider.useClass === className);
|
|
@@ -17307,6 +17880,7 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
17307
17880
|
...deps.hostDeps.length > 0 ? { hostDeps: deps.hostDeps } : {},
|
|
17308
17881
|
...deps.functionalInjects.length > 0 ? { functionalInjects: deps.functionalInjects } : {},
|
|
17309
17882
|
...hasDestroyHook(decl) ? { hasOnDestroy: true } : {},
|
|
17883
|
+
...hasInitHook(decl) ? { hasOnInit: true } : {},
|
|
17310
17884
|
exported: exportsSet.has(className),
|
|
17311
17885
|
file: sourcePath(ctx.rootDir, decl.getSourceFile().fileName),
|
|
17312
17886
|
line: lineOf(decl),
|
|
@@ -17322,18 +17896,18 @@ function parseModule(candidate, nameByNode, ctx) {
|
|
|
17322
17896
|
const handlerClasses = [];
|
|
17323
17897
|
const seenHandlers = new Set;
|
|
17324
17898
|
const collectHandler = (expr) => {
|
|
17325
|
-
if (!
|
|
17899
|
+
if (!ts7.isIdentifier(expr))
|
|
17326
17900
|
return;
|
|
17327
17901
|
const decl = resolveDeclaration(expr, ctx)[0];
|
|
17328
|
-
if (decl &&
|
|
17902
|
+
if (decl && ts7.isClassDeclaration(decl) && !seenHandlers.has(decl.name?.text ?? "")) {
|
|
17329
17903
|
seenHandlers.add(decl.name?.text ?? "");
|
|
17330
17904
|
handlerClasses.push(decl);
|
|
17331
17905
|
}
|
|
17332
17906
|
};
|
|
17333
17907
|
for (const el of arrayProp(options, "providers")) {
|
|
17334
|
-
if (
|
|
17908
|
+
if (ts7.isIdentifier(el))
|
|
17335
17909
|
collectHandler(el);
|
|
17336
|
-
if (
|
|
17910
|
+
if (ts7.isObjectLiteralExpression(el)) {
|
|
17337
17911
|
const useClass = getProp(el, "useClass");
|
|
17338
17912
|
if (useClass)
|
|
17339
17913
|
collectHandler(useClass);
|
|
@@ -17442,17 +18016,17 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
17442
18016
|
if (seen.has(input))
|
|
17443
18017
|
return;
|
|
17444
18018
|
seen.add(input);
|
|
17445
|
-
if (
|
|
17446
|
-
const local = input.getSourceFile().statements.flatMap((statement) =>
|
|
18019
|
+
if (ts7.isIdentifier(input)) {
|
|
18020
|
+
const local = input.getSourceFile().statements.flatMap((statement) => ts7.isVariableStatement(statement) ? [...statement.declarationList.declarations] : []);
|
|
17447
18021
|
const resolved = resolveDeclaration(input, ctx)[0];
|
|
17448
|
-
const decl = (resolved &&
|
|
17449
|
-
if (decl &&
|
|
18022
|
+
const decl = (resolved && ts7.isVariableDeclaration(resolved) ? resolved : undefined) ?? ctx.variablesByName.get(input.text) ?? local.find((candidate) => ts7.isIdentifier(candidate.name) && candidate.name.text === input.text) ?? descendantsOfKind(input.getSourceFile(), ts7.isVariableDeclaration).find((candidate) => ts7.isIdentifier(candidate.name) && candidate.name.text === input.text);
|
|
18023
|
+
if (decl && ts7.isVariableDeclaration(decl))
|
|
17450
18024
|
return parseFeatureSpec(decl.initializer, ctx, seen);
|
|
17451
18025
|
}
|
|
17452
|
-
if (
|
|
18026
|
+
if (ts7.isCallExpression(input) && nodeText(input.expression) === "defineFeatureSpec") {
|
|
17453
18027
|
return parseFeatureSpec(input.arguments[0], ctx, seen);
|
|
17454
18028
|
}
|
|
17455
|
-
if (
|
|
18029
|
+
if (ts7.isAsExpression(input) || ts7.isSatisfiesExpression(input) || ts7.isParenthesizedExpression(input)) {
|
|
17456
18030
|
return parseFeatureSpec(input.expression, ctx, seen);
|
|
17457
18031
|
}
|
|
17458
18032
|
const invalid = () => {
|
|
@@ -17465,28 +18039,28 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
17465
18039
|
});
|
|
17466
18040
|
return;
|
|
17467
18041
|
};
|
|
17468
|
-
if (!
|
|
18042
|
+
if (!ts7.isObjectLiteralExpression(input))
|
|
17469
18043
|
return invalid();
|
|
17470
18044
|
const name = stringLiteralProp(input, "name");
|
|
17471
18045
|
const statesExpr = getProp(input, "states");
|
|
17472
18046
|
const transitionObject = getProp(input, "transitions");
|
|
17473
|
-
if (!name || !statesExpr || !
|
|
18047
|
+
if (!name || !statesExpr || !ts7.isArrayLiteralExpression(statesExpr) || statesExpr.elements.some((state) => !ts7.isStringLiteral(state)) || !transitionObject || !ts7.isObjectLiteralExpression(transitionObject) || input.properties.some((property) => !ts7.isPropertyAssignment(property))) {
|
|
17474
18048
|
return invalid();
|
|
17475
18049
|
}
|
|
17476
18050
|
const states = [];
|
|
17477
18051
|
for (const state of statesExpr.elements) {
|
|
17478
|
-
if (!
|
|
18052
|
+
if (!ts7.isStringLiteral(state))
|
|
17479
18053
|
return invalid();
|
|
17480
18054
|
states.push(state.text);
|
|
17481
18055
|
}
|
|
17482
18056
|
const transitions = [];
|
|
17483
18057
|
for (const property of transitionObject.properties) {
|
|
17484
|
-
if (!
|
|
18058
|
+
if (!ts7.isPropertyAssignment(property) || ts7.isComputedPropertyName(property.name) || !ts7.isObjectLiteralExpression(property.initializer))
|
|
17485
18059
|
return invalid();
|
|
17486
18060
|
const options = property.initializer;
|
|
17487
18061
|
const from = stringLiteralProp(options, "from");
|
|
17488
18062
|
const to = stringLiteralProp(options, "to");
|
|
17489
|
-
if (!from || !to || options.properties.some((prop) => !
|
|
18063
|
+
if (!from || !to || options.properties.some((prop) => !ts7.isPropertyAssignment(prop)) || ["permission", "command", "route", "audit"].some((key) => getProp(options, key) && !stringLiteralProp(options, key)) || ["transaction", "idempotency"].some((key) => getProp(options, key) && !commandModeProp(options, key))) {
|
|
17490
18064
|
return invalid();
|
|
17491
18065
|
}
|
|
17492
18066
|
const permission = stringLiteralProp(options, "permission");
|
|
@@ -17513,21 +18087,21 @@ function resolveStaticObjectLiteral(input, ctx, seen = new Set) {
|
|
|
17513
18087
|
if (!input || seen.has(input))
|
|
17514
18088
|
return;
|
|
17515
18089
|
seen.add(input);
|
|
17516
|
-
if (
|
|
18090
|
+
if (ts7.isAsExpression(input) || ts7.isSatisfiesExpression(input) || ts7.isParenthesizedExpression(input)) {
|
|
17517
18091
|
return resolveStaticObjectLiteral(input.expression, ctx, seen);
|
|
17518
18092
|
}
|
|
17519
|
-
if (
|
|
17520
|
-
const declaration = resolveDeclaration(input, ctx).find(
|
|
18093
|
+
if (ts7.isIdentifier(input)) {
|
|
18094
|
+
const declaration = resolveDeclaration(input, ctx).find(ts7.isVariableDeclaration);
|
|
17521
18095
|
return declaration?.initializer ? resolveStaticObjectLiteral(declaration.initializer, ctx, seen) : undefined;
|
|
17522
18096
|
}
|
|
17523
|
-
if (
|
|
18097
|
+
if (ts7.isCallExpression(input)) {
|
|
17524
18098
|
const expressionName = nodeText(input.expression);
|
|
17525
18099
|
if (expressionName === "defineRouteContract" || expressionName.endsWith(".defineRouteContract")) {
|
|
17526
18100
|
return resolveStaticObjectLiteral(input.arguments[0], ctx, seen);
|
|
17527
18101
|
}
|
|
17528
18102
|
return;
|
|
17529
18103
|
}
|
|
17530
|
-
return
|
|
18104
|
+
return ts7.isObjectLiteralExpression(input) ? input : undefined;
|
|
17531
18105
|
}
|
|
17532
18106
|
function routePolicyProperty(object, name, ctx, seen = new Set) {
|
|
17533
18107
|
if (seen.has(object))
|
|
@@ -17535,15 +18109,15 @@ function routePolicyProperty(object, name, ctx, seen = new Set) {
|
|
|
17535
18109
|
const ancestry = new Set(seen).add(object);
|
|
17536
18110
|
let result = { unresolved: false };
|
|
17537
18111
|
for (const property of object.properties) {
|
|
17538
|
-
if (
|
|
18112
|
+
if (ts7.isSpreadAssignment(property)) {
|
|
17539
18113
|
const spread = resolveStaticObjectLiteral(property.expression, ctx);
|
|
17540
18114
|
const nested = spread ? routePolicyProperty(spread, name, ctx, ancestry) : { unresolved: true };
|
|
17541
18115
|
if (nested.unresolved || nested.value !== undefined)
|
|
17542
18116
|
result = nested;
|
|
17543
|
-
} else if (
|
|
18117
|
+
} else if (ts7.isComputedPropertyName(property.name)) {
|
|
17544
18118
|
result = { unresolved: true };
|
|
17545
18119
|
} else if (propertyName(property.name) === name) {
|
|
17546
|
-
result =
|
|
18120
|
+
result = ts7.isPropertyAssignment(property) ? { value: property.initializer, unresolved: false } : { unresolved: true };
|
|
17547
18121
|
}
|
|
17548
18122
|
}
|
|
17549
18123
|
return result;
|
|
@@ -17581,9 +18155,9 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17581
18155
|
const file = sourcePath(ctx.rootDir, el.getSourceFile().fileName);
|
|
17582
18156
|
const line = lineOf(el);
|
|
17583
18157
|
const unwrappedEl = unwrapForwardRef(el);
|
|
17584
|
-
if (
|
|
18158
|
+
if (ts7.isIdentifier(unwrappedEl)) {
|
|
17585
18159
|
const decl = resolveDeclaration(unwrappedEl, ctx)[0];
|
|
17586
|
-
const cls = decl &&
|
|
18160
|
+
const cls = decl && ts7.isClassDeclaration(decl) ? decl : undefined;
|
|
17587
18161
|
const className = cls?.name?.text ?? unwrappedEl.text;
|
|
17588
18162
|
const { deps, optionalDeps, selfDeps, skipSelfDeps, hostDeps, functionalInjects, missing } = cls ? classDeps(cls, ctx) : { deps: [], optionalDeps: [], selfDeps: [], skipSelfDeps: [], hostDeps: [], functionalInjects: [], missing: false };
|
|
17589
18163
|
const injectable = cls ? parseInjectableOptions(cls, ctx) : undefined;
|
|
@@ -17604,13 +18178,14 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17604
18178
|
...functionalInjects.length > 0 ? { functionalInjects } : {},
|
|
17605
18179
|
...injectable?.providedIn ? { providedIn: injectable.providedIn } : {},
|
|
17606
18180
|
...cls && hasDestroyHook(cls) ? { hasOnDestroy: true } : {},
|
|
18181
|
+
...cls && hasInitHook(cls) ? { hasOnInit: true } : {},
|
|
17607
18182
|
exported: exportsSet.has(className),
|
|
17608
18183
|
file,
|
|
17609
18184
|
line,
|
|
17610
18185
|
...cls ? { importPath: modulePath(ctx.rootDir, cls.getSourceFile().fileName) } : {}
|
|
17611
18186
|
};
|
|
17612
18187
|
}
|
|
17613
|
-
if (!
|
|
18188
|
+
if (!ts7.isObjectLiteralExpression(el))
|
|
17614
18189
|
return;
|
|
17615
18190
|
const provideExpr = getProp(el, "provide");
|
|
17616
18191
|
if (!provideExpr)
|
|
@@ -17625,8 +18200,8 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17625
18200
|
const useExistingExpr = getProp(el, "useExisting");
|
|
17626
18201
|
if (useClassExpr) {
|
|
17627
18202
|
const unwrappedClass = unwrapForwardRef(useClassExpr);
|
|
17628
|
-
const decl =
|
|
17629
|
-
const cls = decl &&
|
|
18203
|
+
const decl = ts7.isIdentifier(unwrappedClass) ? resolveDeclaration(unwrappedClass, ctx)[0] : undefined;
|
|
18204
|
+
const cls = decl && ts7.isClassDeclaration(decl) ? decl : undefined;
|
|
17630
18205
|
const useClass = cls?.name?.text ?? nodeText(unwrappedClass);
|
|
17631
18206
|
let deps = explicitDeps;
|
|
17632
18207
|
let optionalDeps = [];
|
|
@@ -17674,6 +18249,7 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17674
18249
|
...multi === undefined ? {} : { multi },
|
|
17675
18250
|
...injectable?.providedIn ? { providedIn: injectable.providedIn } : {},
|
|
17676
18251
|
...cls && hasMethod(cls, "onDestroy") ? { hasOnDestroy: true } : {},
|
|
18252
|
+
...cls && hasInitHook(cls) ? { hasOnInit: true } : {},
|
|
17677
18253
|
exported: exportsSet.has(token),
|
|
17678
18254
|
file,
|
|
17679
18255
|
line,
|
|
@@ -17682,7 +18258,7 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17682
18258
|
}
|
|
17683
18259
|
if (useValueExpr) {
|
|
17684
18260
|
validateProviderCompatibility(provideExpr, useValueExpr, "value", token, ctx, file, line);
|
|
17685
|
-
const importPath =
|
|
18261
|
+
const importPath = ts7.isIdentifier(useValueExpr) ? importPathOf(useValueExpr, ctx) : undefined;
|
|
17686
18262
|
return {
|
|
17687
18263
|
token,
|
|
17688
18264
|
tokenKind,
|
|
@@ -17698,12 +18274,12 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17698
18274
|
};
|
|
17699
18275
|
}
|
|
17700
18276
|
if (useFactoryExpr) {
|
|
17701
|
-
const factoryName =
|
|
18277
|
+
const factoryName = ts7.isIdentifier(useFactoryExpr) ? (() => {
|
|
17702
18278
|
const decl = resolveDeclaration(useFactoryExpr, ctx)[0];
|
|
17703
|
-
return decl && (
|
|
18279
|
+
return decl && (ts7.isFunctionDeclaration(decl) || ts7.isVariableDeclaration(decl)) ? (ts7.isFunctionDeclaration(decl) ? decl.name?.text : variableName(decl)) ?? useFactoryExpr.text : useFactoryExpr.text;
|
|
17704
18280
|
})() : nodeText(useFactoryExpr);
|
|
17705
18281
|
validateProviderCompatibility(provideExpr, useFactoryExpr, "factory", token, ctx, file, line);
|
|
17706
|
-
const importPath =
|
|
18282
|
+
const importPath = ts7.isIdentifier(useFactoryExpr) ? importPathOf(useFactoryExpr, ctx) : undefined;
|
|
17707
18283
|
return {
|
|
17708
18284
|
token,
|
|
17709
18285
|
tokenKind,
|
|
@@ -17739,20 +18315,20 @@ function parseProvider(el, exportsSet, ctx) {
|
|
|
17739
18315
|
function expandProviderExpressions(expressions, ctx, seen = new Set) {
|
|
17740
18316
|
const result = [];
|
|
17741
18317
|
for (const expression of expressions) {
|
|
17742
|
-
if (
|
|
18318
|
+
if (ts7.isSpreadElement(expression)) {
|
|
17743
18319
|
result.push(...expandProviderExpressions([expression.expression], ctx, seen));
|
|
17744
18320
|
continue;
|
|
17745
18321
|
}
|
|
17746
|
-
if (
|
|
18322
|
+
if (ts7.isIdentifier(expression)) {
|
|
17747
18323
|
const declaration = resolveDeclaration(expression, ctx)[0];
|
|
17748
|
-
if (declaration &&
|
|
18324
|
+
if (declaration && ts7.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
17749
18325
|
const key = `${declaration.getSourceFile().fileName}:${declaration.pos}`;
|
|
17750
18326
|
if (seen.has(key))
|
|
17751
18327
|
continue;
|
|
17752
18328
|
const initializer = declaration.initializer;
|
|
17753
|
-
if (
|
|
18329
|
+
if (ts7.isCallExpression(initializer) && isProviderHelper(initializer, "makeEnvironmentProviders")) {
|
|
17754
18330
|
const nested = initializer.arguments[0];
|
|
17755
|
-
if (nested &&
|
|
18331
|
+
if (nested && ts7.isArrayLiteralExpression(nested)) {
|
|
17756
18332
|
seen.add(key);
|
|
17757
18333
|
result.push(...expandProviderExpressions([...nested.elements], ctx, seen));
|
|
17758
18334
|
seen.delete(key);
|
|
@@ -17761,9 +18337,9 @@ function expandProviderExpressions(expressions, ctx, seen = new Set) {
|
|
|
17761
18337
|
}
|
|
17762
18338
|
}
|
|
17763
18339
|
}
|
|
17764
|
-
if (
|
|
18340
|
+
if (ts7.isCallExpression(expression) && isProviderHelper(expression, "makeEnvironmentProviders")) {
|
|
17765
18341
|
const nested = expression.arguments[0];
|
|
17766
|
-
if (nested &&
|
|
18342
|
+
if (nested && ts7.isArrayLiteralExpression(nested)) {
|
|
17767
18343
|
result.push(...expandProviderExpressions([...nested.elements], ctx, seen));
|
|
17768
18344
|
continue;
|
|
17769
18345
|
}
|
|
@@ -17776,7 +18352,7 @@ function isProviderHelper(expression, name) {
|
|
|
17776
18352
|
return nodeText(expression.expression).split(".").pop() === name;
|
|
17777
18353
|
}
|
|
17778
18354
|
function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
17779
|
-
if (!
|
|
18355
|
+
if (!ts7.isCallExpression(expression))
|
|
17780
18356
|
return;
|
|
17781
18357
|
const helper = nodeText(expression.expression).split(".").pop();
|
|
17782
18358
|
const args = expression.arguments;
|
|
@@ -17789,7 +18365,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
17789
18365
|
return [];
|
|
17790
18366
|
const { name: token, kind: tokenKind } = tokenNameOf(tokenExpr, ctx);
|
|
17791
18367
|
validateProviderCompatibility(tokenExpr, valueExpr, "value", token, ctx, file, line);
|
|
17792
|
-
const importPath =
|
|
18368
|
+
const importPath = ts7.isIdentifier(valueExpr) ? importPathOf(valueExpr, ctx) : undefined;
|
|
17793
18369
|
return [{
|
|
17794
18370
|
token,
|
|
17795
18371
|
tokenKind,
|
|
@@ -17808,7 +18384,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
17808
18384
|
if (!initializer)
|
|
17809
18385
|
return [];
|
|
17810
18386
|
const token = helper === "provideAppInitializer" ? "APP_INITIALIZER" : "ENVIRONMENT_INITIALIZER";
|
|
17811
|
-
const importPath =
|
|
18387
|
+
const importPath = ts7.isIdentifier(initializer) ? importPathOf(initializer, ctx) : undefined;
|
|
17812
18388
|
return [{
|
|
17813
18389
|
token,
|
|
17814
18390
|
tokenKind: "injection-token",
|
|
@@ -17827,7 +18403,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
17827
18403
|
const providers = [];
|
|
17828
18404
|
const routes = args[0];
|
|
17829
18405
|
if (routes) {
|
|
17830
|
-
const importPath =
|
|
18406
|
+
const importPath = ts7.isIdentifier(routes) ? importPathOf(routes, ctx) : undefined;
|
|
17831
18407
|
providers.push({
|
|
17832
18408
|
token: "ROUTE_CONFIG",
|
|
17833
18409
|
tokenKind: "injection-token",
|
|
@@ -17842,7 +18418,7 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
17842
18418
|
});
|
|
17843
18419
|
}
|
|
17844
18420
|
for (const feature of args.slice(1)) {
|
|
17845
|
-
if (!
|
|
18421
|
+
if (!ts7.isCallExpression(feature))
|
|
17846
18422
|
continue;
|
|
17847
18423
|
const featureName = nodeText(feature.expression).split(".").pop();
|
|
17848
18424
|
if (featureName === "withRouterConfig" && feature.arguments[0]) {
|
|
@@ -17859,8 +18435,8 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
17859
18435
|
});
|
|
17860
18436
|
} else if (featureName === "withTitleStrategy" && feature.arguments[0]) {
|
|
17861
18437
|
const strategy = feature.arguments[0];
|
|
17862
|
-
const isClass =
|
|
17863
|
-
const importPath =
|
|
18438
|
+
const isClass = ts7.isIdentifier(strategy) && Boolean(resolveDeclaration(strategy, ctx).find((declaration) => ts7.isClassDeclaration(declaration)));
|
|
18439
|
+
const importPath = ts7.isIdentifier(strategy) ? importPathOf(strategy, ctx) : undefined;
|
|
17864
18440
|
providers.push({
|
|
17865
18441
|
token: "TITLE_STRATEGY",
|
|
17866
18442
|
tokenKind: "injection-token",
|
|
@@ -17892,14 +18468,14 @@ function parseFunctionalProvider(expression, exportsSet, ctx) {
|
|
|
17892
18468
|
importModule: "@supacloud/app"
|
|
17893
18469
|
}];
|
|
17894
18470
|
for (const feature of args) {
|
|
17895
|
-
if (!
|
|
18471
|
+
if (!ts7.isCallExpression(feature))
|
|
17896
18472
|
continue;
|
|
17897
18473
|
const featureName = nodeText(feature.expression).split(".").pop();
|
|
17898
18474
|
if (featureName === "withInterceptors") {
|
|
17899
18475
|
for (const interceptorArg of feature.arguments) {
|
|
17900
|
-
const values =
|
|
18476
|
+
const values = ts7.isArrayLiteralExpression(interceptorArg) ? [...interceptorArg.elements] : [interceptorArg];
|
|
17901
18477
|
for (const value of values) {
|
|
17902
|
-
const importPath =
|
|
18478
|
+
const importPath = ts7.isIdentifier(value) ? importPathOf(value, ctx) : undefined;
|
|
17903
18479
|
providers.push({
|
|
17904
18480
|
token: "HTTP_INTERCEPTORS",
|
|
17905
18481
|
tokenKind: "injection-token",
|
|
@@ -17946,9 +18522,9 @@ function providerTokenValueType(expr, ctx) {
|
|
|
17946
18522
|
const typeArguments = typeArgumentsOf(type, ctx);
|
|
17947
18523
|
if (typeArguments.length > 0)
|
|
17948
18524
|
return typeArguments[0];
|
|
17949
|
-
if (
|
|
18525
|
+
if (ts7.isIdentifier(expr)) {
|
|
17950
18526
|
const declaration = resolveDeclaration(expr, ctx)[0];
|
|
17951
|
-
if (declaration &&
|
|
18527
|
+
if (declaration && ts7.isClassDeclaration(declaration)) {
|
|
17952
18528
|
return declaredClassType(declaration, ctx);
|
|
17953
18529
|
}
|
|
17954
18530
|
}
|
|
@@ -17956,9 +18532,9 @@ function providerTokenValueType(expr, ctx) {
|
|
|
17956
18532
|
}
|
|
17957
18533
|
function providerImplementationType(expr, kind, ctx) {
|
|
17958
18534
|
if (kind === "class" || kind === "existing") {
|
|
17959
|
-
if (
|
|
18535
|
+
if (ts7.isIdentifier(expr)) {
|
|
17960
18536
|
const declaration = resolveDeclaration(expr, ctx)[0];
|
|
17961
|
-
if (declaration &&
|
|
18537
|
+
if (declaration && ts7.isClassDeclaration(declaration)) {
|
|
17962
18538
|
return declaredClassType(declaration, ctx);
|
|
17963
18539
|
}
|
|
17964
18540
|
}
|
|
@@ -17968,7 +18544,7 @@ function providerImplementationType(expr, kind, ctx) {
|
|
|
17968
18544
|
}
|
|
17969
18545
|
if (kind === "factory") {
|
|
17970
18546
|
const type = ctx.checker.getTypeAtLocation(expr);
|
|
17971
|
-
const signature = ctx.checker.getSignaturesOfType(type,
|
|
18547
|
+
const signature = ctx.checker.getSignaturesOfType(type, ts7.SignatureKind.Call)[0];
|
|
17972
18548
|
return signature?.getReturnType();
|
|
17973
18549
|
}
|
|
17974
18550
|
return ctx.checker.getTypeAtLocation(expr);
|
|
@@ -17987,16 +18563,16 @@ function isTypeReference(type) {
|
|
|
17987
18563
|
return "target" in type;
|
|
17988
18564
|
}
|
|
17989
18565
|
function isUnknownOrAny(type) {
|
|
17990
|
-
return (type.flags & (
|
|
18566
|
+
return (type.flags & (ts7.TypeFlags.Any | ts7.TypeFlags.Unknown)) !== 0;
|
|
17991
18567
|
}
|
|
17992
18568
|
function parseController(input, ctx) {
|
|
17993
18569
|
let decl;
|
|
17994
|
-
if (
|
|
18570
|
+
if (ts7.isClassDeclaration(input)) {
|
|
17995
18571
|
decl = input;
|
|
17996
18572
|
} else {
|
|
17997
18573
|
const unwrapped = unwrapForwardRef(input);
|
|
17998
|
-
const resolved =
|
|
17999
|
-
if (resolved &&
|
|
18574
|
+
const resolved = ts7.isIdentifier(unwrapped) ? resolveDeclaration(unwrapped, ctx)[0] : undefined;
|
|
18575
|
+
if (resolved && ts7.isClassDeclaration(resolved)) {
|
|
18000
18576
|
decl = resolved;
|
|
18001
18577
|
}
|
|
18002
18578
|
}
|
|
@@ -18009,9 +18585,9 @@ function parseController(input, ctx) {
|
|
|
18009
18585
|
let standalone;
|
|
18010
18586
|
const pathArg = decoratorArguments(controllerDec)[0];
|
|
18011
18587
|
if (pathArg) {
|
|
18012
|
-
if (
|
|
18588
|
+
if (ts7.isStringLiteral(pathArg)) {
|
|
18013
18589
|
path = pathArg.text;
|
|
18014
|
-
} else if (
|
|
18590
|
+
} else if (ts7.isObjectLiteralExpression(pathArg)) {
|
|
18015
18591
|
const p = stringLiteralProp(pathArg, "path");
|
|
18016
18592
|
if (p)
|
|
18017
18593
|
path = p;
|
|
@@ -18034,7 +18610,7 @@ function parseController(input, ctx) {
|
|
|
18034
18610
|
}
|
|
18035
18611
|
}
|
|
18036
18612
|
}
|
|
18037
|
-
for (const method of decl.members.filter(
|
|
18613
|
+
for (const method of decl.members.filter(ts7.isMethodDeclaration)) {
|
|
18038
18614
|
for (const dec of decoratorsOf(method)) {
|
|
18039
18615
|
const name = decoratorName2(dec);
|
|
18040
18616
|
const httpMethod = name ? ROUTE_DECORATORS[name] : undefined;
|
|
@@ -18042,7 +18618,7 @@ function parseController(input, ctx) {
|
|
|
18042
18618
|
continue;
|
|
18043
18619
|
const args = decoratorArguments(dec);
|
|
18044
18620
|
const pathArg = args[0];
|
|
18045
|
-
const routePath = pathArg &&
|
|
18621
|
+
const routePath = pathArg && ts7.isStringLiteral(pathArg) ? pathArg.text : "/";
|
|
18046
18622
|
const route = {
|
|
18047
18623
|
method: httpMethod,
|
|
18048
18624
|
path: routePath,
|
|
@@ -18116,12 +18692,12 @@ function parseController(input, ctx) {
|
|
|
18116
18692
|
} else if (dName === "Headers") {
|
|
18117
18693
|
hasBindingDecorator = true;
|
|
18118
18694
|
const argument = dArgs[0];
|
|
18119
|
-
const bindingName = argument !== undefined &&
|
|
18695
|
+
const bindingName = argument !== undefined && ts7.isStringLiteral(argument) ? argument.text : undefined;
|
|
18120
18696
|
paramNode = { name: pName, kind: "headers", ...bindingName === undefined ? {} : { bindingName } };
|
|
18121
18697
|
} else if (dName === "Cookie") {
|
|
18122
18698
|
hasBindingDecorator = true;
|
|
18123
18699
|
const argument = dArgs[0];
|
|
18124
|
-
const bindingName = argument !== undefined &&
|
|
18700
|
+
const bindingName = argument !== undefined && ts7.isStringLiteral(argument) ? argument.text : undefined;
|
|
18125
18701
|
paramNode = { name: pName, kind: "cookie", ...bindingName === undefined ? {} : { bindingName } };
|
|
18126
18702
|
}
|
|
18127
18703
|
}
|
|
@@ -18183,20 +18759,20 @@ function parseController(input, ctx) {
|
|
|
18183
18759
|
}
|
|
18184
18760
|
} else if (dName === "Title") {
|
|
18185
18761
|
const tArg = mArgs[0];
|
|
18186
|
-
if (tArg &&
|
|
18762
|
+
if (tArg && ts7.isStringLiteral(tArg)) {
|
|
18187
18763
|
route.title = tArg.text;
|
|
18188
18764
|
}
|
|
18189
18765
|
} else if (dName === "Data") {
|
|
18190
18766
|
const dArg = mArgs[0];
|
|
18191
|
-
if (dArg &&
|
|
18767
|
+
if (dArg && ts7.isObjectLiteralExpression(dArg)) {
|
|
18192
18768
|
route.data = { ...route.data, ...parseObjectLiteralValues(dArg) };
|
|
18193
18769
|
}
|
|
18194
18770
|
} else if (dName === "Resolve") {
|
|
18195
18771
|
const rArg = mArgs[0];
|
|
18196
|
-
if (rArg &&
|
|
18772
|
+
if (rArg && ts7.isObjectLiteralExpression(rArg)) {
|
|
18197
18773
|
const resolvers = route.resolvers ?? {};
|
|
18198
18774
|
for (const prop of rArg.properties) {
|
|
18199
|
-
if (
|
|
18775
|
+
if (ts7.isPropertyAssignment(prop)) {
|
|
18200
18776
|
const rName = propertyName(prop.name);
|
|
18201
18777
|
const init = prop.initializer;
|
|
18202
18778
|
if (init)
|
|
@@ -18224,7 +18800,7 @@ function parseController(input, ctx) {
|
|
|
18224
18800
|
}
|
|
18225
18801
|
const parse = parsePolicy.value;
|
|
18226
18802
|
if (parse) {
|
|
18227
|
-
if (
|
|
18803
|
+
if (ts7.isStringLiteral(parse) && parse.text === "none")
|
|
18228
18804
|
route.parse = "none";
|
|
18229
18805
|
else
|
|
18230
18806
|
ctx.diagnostics.push({
|
|
@@ -18236,7 +18812,7 @@ function parseController(input, ctx) {
|
|
|
18236
18812
|
}
|
|
18237
18813
|
const allowDeleteBody = deletePolicy.value;
|
|
18238
18814
|
if (allowDeleteBody) {
|
|
18239
|
-
if (allowDeleteBody.kind ===
|
|
18815
|
+
if (allowDeleteBody.kind === ts7.SyntaxKind.TrueKeyword)
|
|
18240
18816
|
route.allowDeleteBody = true;
|
|
18241
18817
|
else
|
|
18242
18818
|
ctx.diagnostics.push({
|
|
@@ -18261,7 +18837,7 @@ function parseController(input, ctx) {
|
|
|
18261
18837
|
});
|
|
18262
18838
|
}
|
|
18263
18839
|
const contract = getProp(optionsObject, "contract");
|
|
18264
|
-
if (contract &&
|
|
18840
|
+
if (contract && ts7.isObjectLiteralExpression(contract)) {
|
|
18265
18841
|
route.contract = {};
|
|
18266
18842
|
for (const field of ["body", "response", "evidence"]) {
|
|
18267
18843
|
const value = stringLiteralProp(contract, field);
|
|
@@ -18279,7 +18855,7 @@ function parseController(input, ctx) {
|
|
|
18279
18855
|
}
|
|
18280
18856
|
for (const field of ["body", "params", "query", "headers", "cookie", "response"]) {
|
|
18281
18857
|
const schemaExpr = getProp(optionsObject, field);
|
|
18282
|
-
if (schemaExpr &&
|
|
18858
|
+
if (schemaExpr && ts7.isIdentifier(schemaExpr)) {
|
|
18283
18859
|
route[field] = nodeText(schemaExpr);
|
|
18284
18860
|
const importPath = importPathOf(schemaExpr, ctx);
|
|
18285
18861
|
if (importPath)
|
|
@@ -18294,7 +18870,7 @@ function parseController(input, ctx) {
|
|
|
18294
18870
|
const responses = {};
|
|
18295
18871
|
const selectors = new Map;
|
|
18296
18872
|
for (const property of responsesObject.properties) {
|
|
18297
|
-
if (!
|
|
18873
|
+
if (!ts7.isPropertyAssignment(property) || ts7.isComputedPropertyName(property.name))
|
|
18298
18874
|
continue;
|
|
18299
18875
|
const status = propertyName(property.name);
|
|
18300
18876
|
if (!isRouteResponseSelector(status)) {
|
|
@@ -18326,7 +18902,7 @@ function parseController(input, ctx) {
|
|
|
18326
18902
|
}
|
|
18327
18903
|
selectors.set(canonical, status);
|
|
18328
18904
|
const schemaExpr = property.initializer;
|
|
18329
|
-
if (!
|
|
18905
|
+
if (!ts7.isIdentifier(schemaExpr)) {
|
|
18330
18906
|
ctx.diagnostics.push({
|
|
18331
18907
|
severity: "error",
|
|
18332
18908
|
code: "invalid-route-response-map",
|
|
@@ -18348,18 +18924,18 @@ function parseController(input, ctx) {
|
|
|
18348
18924
|
route.responses = responses;
|
|
18349
18925
|
}
|
|
18350
18926
|
const commandExpr = getProp(optionsObject, "command");
|
|
18351
|
-
if (commandExpr &&
|
|
18927
|
+
if (commandExpr && ts7.isIdentifier(commandExpr)) {
|
|
18352
18928
|
const commandDecl = resolveDeclaration(commandExpr, ctx)[0];
|
|
18353
|
-
route.command = commandDecl &&
|
|
18929
|
+
route.command = commandDecl && ts7.isClassDeclaration(commandDecl) ? commandDecl.name?.text ?? commandExpr.text : commandExpr.text;
|
|
18354
18930
|
}
|
|
18355
18931
|
const guardsExpr = getProp(optionsObject, "guards");
|
|
18356
|
-
if (guardsExpr &&
|
|
18932
|
+
if (guardsExpr && ts7.isArrayLiteralExpression(guardsExpr)) {
|
|
18357
18933
|
for (const el of guardsExpr.elements) {
|
|
18358
18934
|
routeGuards.push(tokenText(el, ctx));
|
|
18359
18935
|
}
|
|
18360
18936
|
}
|
|
18361
18937
|
const canMatchExpr = getProp(optionsObject, "canMatch");
|
|
18362
|
-
if (canMatchExpr &&
|
|
18938
|
+
if (canMatchExpr && ts7.isArrayLiteralExpression(canMatchExpr)) {
|
|
18363
18939
|
const canMatchList = [];
|
|
18364
18940
|
for (const el of canMatchExpr.elements) {
|
|
18365
18941
|
canMatchList.push(tokenText(el, ctx));
|
|
@@ -18369,16 +18945,16 @@ function parseController(input, ctx) {
|
|
|
18369
18945
|
}
|
|
18370
18946
|
}
|
|
18371
18947
|
const canDeactivateExpr = getProp(optionsObject, "canDeactivate");
|
|
18372
|
-
if (canDeactivateExpr &&
|
|
18948
|
+
if (canDeactivateExpr && ts7.isArrayLiteralExpression(canDeactivateExpr)) {
|
|
18373
18949
|
for (const el of canDeactivateExpr.elements) {
|
|
18374
18950
|
routeCanDeactivate.push(tokenText(el, ctx));
|
|
18375
18951
|
}
|
|
18376
18952
|
}
|
|
18377
18953
|
const resolversExpr = getProp(optionsObject, "resolvers");
|
|
18378
|
-
if (resolversExpr &&
|
|
18954
|
+
if (resolversExpr && ts7.isObjectLiteralExpression(resolversExpr)) {
|
|
18379
18955
|
const resolvers = {};
|
|
18380
18956
|
for (const prop of resolversExpr.properties) {
|
|
18381
|
-
if (
|
|
18957
|
+
if (ts7.isPropertyAssignment(prop)) {
|
|
18382
18958
|
const rName = propertyName(prop.name);
|
|
18383
18959
|
const init = prop.initializer;
|
|
18384
18960
|
if (init)
|
|
@@ -18390,22 +18966,22 @@ function parseController(input, ctx) {
|
|
|
18390
18966
|
}
|
|
18391
18967
|
}
|
|
18392
18968
|
const redirectToExpr = getProp(optionsObject, "redirectTo");
|
|
18393
|
-
if (redirectToExpr &&
|
|
18969
|
+
if (redirectToExpr && ts7.isStringLiteral(redirectToExpr)) {
|
|
18394
18970
|
route.redirectTo = redirectToExpr.text;
|
|
18395
18971
|
}
|
|
18396
18972
|
const pathMatchExpr = getProp(optionsObject, "pathMatch");
|
|
18397
|
-
if (pathMatchExpr &&
|
|
18973
|
+
if (pathMatchExpr && ts7.isStringLiteral(pathMatchExpr)) {
|
|
18398
18974
|
const val = pathMatchExpr.text;
|
|
18399
18975
|
if (val === "full" || val === "prefix") {
|
|
18400
18976
|
route.pathMatch = val;
|
|
18401
18977
|
}
|
|
18402
18978
|
}
|
|
18403
18979
|
const titleExpr = getProp(optionsObject, "title");
|
|
18404
|
-
if (titleExpr &&
|
|
18980
|
+
if (titleExpr && ts7.isStringLiteral(titleExpr)) {
|
|
18405
18981
|
route.title = titleExpr.text;
|
|
18406
18982
|
}
|
|
18407
18983
|
const dataExpr = getProp(optionsObject, "data");
|
|
18408
|
-
if (dataExpr &&
|
|
18984
|
+
if (dataExpr && ts7.isObjectLiteralExpression(dataExpr)) {
|
|
18409
18985
|
route.data = { ...route.data, ...parseObjectLiteralValues(dataExpr) };
|
|
18410
18986
|
}
|
|
18411
18987
|
const aspects = parseAspectRefs(getProp(optionsObject, "aspects"), ctx, `route ${httpMethod} ${routePath}`);
|
|
@@ -18427,6 +19003,7 @@ function parseController(input, ctx) {
|
|
|
18427
19003
|
scope: injectable?.scope ?? "request",
|
|
18428
19004
|
deps,
|
|
18429
19005
|
...hasDestroyHook(decl) ? { hasOnDestroy: true } : {},
|
|
19006
|
+
...hasInitHook(decl) ? { hasOnInit: true } : {},
|
|
18430
19007
|
...optionalDeps.length > 0 ? { optionalDeps } : {},
|
|
18431
19008
|
...selfDeps.length > 0 ? { selfDeps } : {},
|
|
18432
19009
|
...skipSelfDeps.length > 0 ? { skipSelfDeps } : {},
|
|
@@ -18460,7 +19037,7 @@ function parseJobOptions(meta, owner, ctx) {
|
|
|
18460
19037
|
const expression = getProp(meta, field);
|
|
18461
19038
|
if (!expression)
|
|
18462
19039
|
continue;
|
|
18463
|
-
if (!
|
|
19040
|
+
if (!ts7.isIdentifier(expression)) {
|
|
18464
19041
|
jobOptionError(ctx, "invalid-job-schema", `${owner} 的 ${field} schema 必须是可静态解析的标识符引用,不能使用内联调用或动态表达式`, expression, "SC4019", `将 schema 提取为命名导出,例如 ${field}: ${field === "input" ? "JobInput" : "JobOutput"}。`);
|
|
18465
19042
|
continue;
|
|
18466
19043
|
}
|
|
@@ -18484,7 +19061,7 @@ function parseJobEnum(meta, field, allowed, owner, ctx, code, errorCode) {
|
|
|
18484
19061
|
const expression = getProp(meta, field);
|
|
18485
19062
|
if (!expression)
|
|
18486
19063
|
return;
|
|
18487
|
-
if (!
|
|
19064
|
+
if (!ts7.isStringLiteral(expression) || !allowed.includes(expression.text)) {
|
|
18488
19065
|
jobOptionError(ctx, code, `${owner} 的 ${field} 必须是 ${allowed.map((value) => JSON.stringify(value)).join(" 或 ")} 字符串字面量`, expression, errorCode);
|
|
18489
19066
|
return;
|
|
18490
19067
|
}
|
|
@@ -18494,7 +19071,7 @@ function parseJobInteger(meta, field, min, max, owner, ctx, code, errorCode) {
|
|
|
18494
19071
|
const expression = getProp(meta, field);
|
|
18495
19072
|
if (!expression)
|
|
18496
19073
|
return;
|
|
18497
|
-
const value =
|
|
19074
|
+
const value = ts7.isNumericLiteral(expression) ? Number(expression.text) : Number.NaN;
|
|
18498
19075
|
if (!Number.isSafeInteger(value) || value < min || value > max) {
|
|
18499
19076
|
jobOptionError(ctx, code, `${owner} 的 ${field} 必须是 ${min} 到 ${max} 之间的安全整数`, expression, errorCode);
|
|
18500
19077
|
return;
|
|
@@ -18530,7 +19107,7 @@ function isOpaqueSchema(identifier, declaration, ctx) {
|
|
|
18530
19107
|
const property = type.getProperty(kind.value === "Union" ? "anyOf" : "allOf");
|
|
18531
19108
|
if (!property)
|
|
18532
19109
|
return true;
|
|
18533
|
-
const members = ctx.checker.getIndexTypeOfType(ctx.checker.getTypeOfSymbolAtLocation(property, identifier),
|
|
19110
|
+
const members = ctx.checker.getIndexTypeOfType(ctx.checker.getTypeOfSymbolAtLocation(property, identifier), ts7.IndexKind.Number);
|
|
18534
19111
|
if (!members)
|
|
18535
19112
|
return true;
|
|
18536
19113
|
const branches = members.isUnion() ? members.types : [members];
|
|
@@ -18542,8 +19119,8 @@ function isOpaqueSchema(identifier, declaration, ctx) {
|
|
|
18542
19119
|
}
|
|
18543
19120
|
if (opaque(ctx.checker.getTypeAtLocation(identifier), new Set))
|
|
18544
19121
|
return true;
|
|
18545
|
-
const initializer = declaration &&
|
|
18546
|
-
return Boolean(initializer &&
|
|
19122
|
+
const initializer = declaration && ts7.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
|
|
19123
|
+
return Boolean(initializer && ts7.isCallExpression(initializer) && ts7.isPropertyAccessExpression(initializer.expression) && ["Unknown", "Any"].includes(initializer.expression.name.text));
|
|
18547
19124
|
}
|
|
18548
19125
|
function checkedRpc(meta, ctx) {
|
|
18549
19126
|
const expression = getProp(meta, "rpc");
|
|
@@ -18564,7 +19141,7 @@ function checkedRpc(meta, ctx) {
|
|
|
18564
19141
|
}
|
|
18565
19142
|
function classDeps(cls, ctx) {
|
|
18566
19143
|
const injectable = parseInjectableOptions(cls, ctx);
|
|
18567
|
-
const ctor = cls.members.find(
|
|
19144
|
+
const ctor = cls.members.find(ts7.isConstructorDeclaration);
|
|
18568
19145
|
const deps = injectable?.deps ? [...injectable.deps] : [];
|
|
18569
19146
|
const optionalDeps = [];
|
|
18570
19147
|
const selfDeps = [];
|
|
@@ -18598,23 +19175,23 @@ function classDeps(cls, ctx) {
|
|
|
18598
19175
|
}
|
|
18599
19176
|
});
|
|
18600
19177
|
}
|
|
18601
|
-
for (const prop of cls.members.filter(
|
|
19178
|
+
for (const prop of cls.members.filter(ts7.isPropertyDeclaration)) {
|
|
18602
19179
|
const init = prop.initializer;
|
|
18603
|
-
if (init &&
|
|
19180
|
+
if (init && ts7.isCallExpression(init)) {
|
|
18604
19181
|
const callName = nodeText(init.expression).split(".").pop();
|
|
18605
19182
|
if (callName === "inject") {
|
|
18606
19183
|
const [tokenArg, optionsArg] = init.arguments;
|
|
18607
19184
|
if (tokenArg) {
|
|
18608
19185
|
const tokenName = tokenText(tokenArg, ctx);
|
|
18609
19186
|
const unwrappedToken = unwrapForwardRef(tokenArg);
|
|
18610
|
-
const known =
|
|
19187
|
+
const known = ts7.isStringLiteral(unwrappedToken) || ts7.isIdentifier(unwrappedToken) && (ctx.tokensByName.has(tokenName) || ctx.classesByName.has(tokenName));
|
|
18611
19188
|
if (!known) {
|
|
18612
19189
|
missing = true;
|
|
18613
19190
|
continue;
|
|
18614
19191
|
}
|
|
18615
19192
|
if (!deps.includes(tokenName))
|
|
18616
19193
|
deps.push(tokenName);
|
|
18617
|
-
const options = optionsArg &&
|
|
19194
|
+
const options = optionsArg && ts7.isObjectLiteralExpression(optionsArg) ? {
|
|
18618
19195
|
optional: booleanProp(optionsArg, "optional") ?? false,
|
|
18619
19196
|
self: booleanProp(optionsArg, "self") ?? false,
|
|
18620
19197
|
skipSelf: booleanProp(optionsArg, "skipSelf") ?? false,
|
|
@@ -18629,9 +19206,9 @@ function classDeps(cls, ctx) {
|
|
|
18629
19206
|
if (options.host && !hostDeps.includes(tokenName))
|
|
18630
19207
|
hostDeps.push(tokenName);
|
|
18631
19208
|
if (!functionalInjects.some((entry) => entry.token === tokenName)) {
|
|
18632
|
-
const declaration =
|
|
19209
|
+
const declaration = ts7.isIdentifier(unwrappedToken) ? resolveDeclaration(unwrappedToken, ctx)[0] : undefined;
|
|
18633
19210
|
const localFile = declaration && isProjectSourcePath(declaration.getSourceFile().fileName, ctx.rootDir) ? declaration.getSourceFile().fileName : undefined;
|
|
18634
|
-
const importModule = declaration && !localFile &&
|
|
19211
|
+
const importModule = declaration && !localFile && ts7.isIdentifier(unwrappedToken) ? importModuleOf(unwrappedToken, ctx) : undefined;
|
|
18635
19212
|
functionalInjects.push({
|
|
18636
19213
|
token: tokenName,
|
|
18637
19214
|
expression: nodeText(unwrappedToken),
|
|
@@ -18675,7 +19252,7 @@ function parseInjectableOptions(cls, ctx) {
|
|
|
18675
19252
|
}
|
|
18676
19253
|
function parseInjectParams(cls, ctx) {
|
|
18677
19254
|
const result = new Map;
|
|
18678
|
-
const ctor = cls.members.find(
|
|
19255
|
+
const ctor = cls.members.find(ts7.isConstructorDeclaration);
|
|
18679
19256
|
if (!ctor)
|
|
18680
19257
|
return result;
|
|
18681
19258
|
ctor.parameters.forEach((param, index) => {
|
|
@@ -18691,7 +19268,7 @@ function parseInjectParams(cls, ctx) {
|
|
|
18691
19268
|
}
|
|
18692
19269
|
function parseOptionalParams(cls) {
|
|
18693
19270
|
const result = new Set;
|
|
18694
|
-
const ctor = cls.members.find(
|
|
19271
|
+
const ctor = cls.members.find(ts7.isConstructorDeclaration);
|
|
18695
19272
|
if (!ctor)
|
|
18696
19273
|
return result;
|
|
18697
19274
|
ctor.parameters.forEach((param, index) => {
|
|
@@ -18706,7 +19283,7 @@ function parseOptionalParams(cls) {
|
|
|
18706
19283
|
}
|
|
18707
19284
|
function parseModifierParams(cls, modifierName) {
|
|
18708
19285
|
const result = new Set;
|
|
18709
|
-
const ctor = cls.members.find(
|
|
19286
|
+
const ctor = cls.members.find(ts7.isConstructorDeclaration);
|
|
18710
19287
|
if (!ctor)
|
|
18711
19288
|
return result;
|
|
18712
19289
|
ctor.parameters.forEach((param, index) => {
|
|
@@ -18718,13 +19295,13 @@ function parseModifierParams(cls, modifierName) {
|
|
|
18718
19295
|
return result;
|
|
18719
19296
|
}
|
|
18720
19297
|
function unwrapForwardRef(expr) {
|
|
18721
|
-
if (
|
|
19298
|
+
if (ts7.isCallExpression(expr)) {
|
|
18722
19299
|
const exprText = nodeText(expr.expression);
|
|
18723
19300
|
if (exprText === "forwardRef" || exprText.endsWith(".forwardRef")) {
|
|
18724
19301
|
const arg = expr.arguments[0];
|
|
18725
|
-
if (arg && (
|
|
19302
|
+
if (arg && (ts7.isArrowFunction(arg) || ts7.isFunctionExpression(arg))) {
|
|
18726
19303
|
const body = arg.body;
|
|
18727
|
-
if (body &&
|
|
19304
|
+
if (body && ts7.isExpression(body)) {
|
|
18728
19305
|
return unwrapForwardRef(body);
|
|
18729
19306
|
}
|
|
18730
19307
|
}
|
|
@@ -18734,13 +19311,13 @@ function unwrapForwardRef(expr) {
|
|
|
18734
19311
|
}
|
|
18735
19312
|
function tokenText(expr, ctx) {
|
|
18736
19313
|
const unwrapped = unwrapForwardRef(expr);
|
|
18737
|
-
if (
|
|
19314
|
+
if (ts7.isStringLiteral(unwrapped))
|
|
18738
19315
|
return unwrapped.text;
|
|
18739
|
-
if (
|
|
19316
|
+
if (ts7.isIdentifier(unwrapped)) {
|
|
18740
19317
|
const decl = resolveDeclaration(unwrapped, ctx)[0];
|
|
18741
|
-
if (decl &&
|
|
19318
|
+
if (decl && ts7.isClassDeclaration(decl))
|
|
18742
19319
|
return decl.name?.text ?? unwrapped.text;
|
|
18743
|
-
if (decl &&
|
|
19320
|
+
if (decl && ts7.isVariableDeclaration(decl))
|
|
18744
19321
|
return variableName(decl);
|
|
18745
19322
|
}
|
|
18746
19323
|
return nodeText(unwrapped);
|
|
@@ -18760,12 +19337,12 @@ function resolveScope(input, ctx) {
|
|
|
18760
19337
|
}
|
|
18761
19338
|
function tokenNameOf(expr, ctx) {
|
|
18762
19339
|
const unwrapped = unwrapForwardRef(expr);
|
|
18763
|
-
if (
|
|
19340
|
+
if (ts7.isIdentifier(unwrapped)) {
|
|
18764
19341
|
const decl = resolveDeclaration(unwrapped, ctx)[0];
|
|
18765
|
-
if (decl &&
|
|
19342
|
+
if (decl && ts7.isClassDeclaration(decl)) {
|
|
18766
19343
|
return { name: decl.name?.text ?? nodeText(expr), kind: "class" };
|
|
18767
19344
|
}
|
|
18768
|
-
if (decl &&
|
|
19345
|
+
if (decl && ts7.isVariableDeclaration(decl)) {
|
|
18769
19346
|
const name = variableName(decl);
|
|
18770
19347
|
return { name, kind: ctx.tokensByName.has(name) ? "injection-token" : "class" };
|
|
18771
19348
|
}
|
|
@@ -18781,10 +19358,10 @@ function resolveDeclaration(id, ctx) {
|
|
|
18781
19358
|
return [];
|
|
18782
19359
|
let declarations = symbol.declarations ?? [];
|
|
18783
19360
|
for (let guard = 0;guard < 4; guard += 1) {
|
|
18784
|
-
const isAlias = declarations.some((d) =>
|
|
19361
|
+
const isAlias = declarations.some((d) => ts7.isImportSpecifier(d) || ts7.isImportClause(d) || ts7.isNamespaceImport(d));
|
|
18785
19362
|
if (!isAlias)
|
|
18786
19363
|
break;
|
|
18787
|
-
if (!(symbol.flags &
|
|
19364
|
+
if (!(symbol.flags & ts7.SymbolFlags.Alias))
|
|
18788
19365
|
break;
|
|
18789
19366
|
const aliased = ctx.checker.getAliasedSymbol(symbol);
|
|
18790
19367
|
symbol = aliased;
|
|
@@ -18804,9 +19381,9 @@ function importModuleOf(id, ctx) {
|
|
|
18804
19381
|
for (const declaration of declarations) {
|
|
18805
19382
|
let current = declaration;
|
|
18806
19383
|
while (current) {
|
|
18807
|
-
if (
|
|
19384
|
+
if (ts7.isImportDeclaration(current)) {
|
|
18808
19385
|
const moduleSpecifier = current.moduleSpecifier;
|
|
18809
|
-
return
|
|
19386
|
+
return ts7.isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : undefined;
|
|
18810
19387
|
}
|
|
18811
19388
|
current = current.parent;
|
|
18812
19389
|
}
|
|
@@ -18818,27 +19395,27 @@ function findDecorator(cls, name) {
|
|
|
18818
19395
|
}
|
|
18819
19396
|
function decoratorName2(dec) {
|
|
18820
19397
|
const expr = dec.expression;
|
|
18821
|
-
if (
|
|
19398
|
+
if (ts7.isCallExpression(expr)) {
|
|
18822
19399
|
return nodeText(expr.expression).split(".").pop();
|
|
18823
19400
|
}
|
|
18824
|
-
if (
|
|
19401
|
+
if (ts7.isIdentifier(expr))
|
|
18825
19402
|
return expr.text;
|
|
18826
19403
|
return;
|
|
18827
19404
|
}
|
|
18828
19405
|
function decoratorObjectArg(dec) {
|
|
18829
19406
|
const expr = dec.expression;
|
|
18830
|
-
if (!
|
|
19407
|
+
if (!ts7.isCallExpression(expr))
|
|
18831
19408
|
return;
|
|
18832
19409
|
const arg = expr.arguments[0];
|
|
18833
|
-
return arg &&
|
|
19410
|
+
return arg && ts7.isObjectLiteralExpression(arg) ? arg : undefined;
|
|
18834
19411
|
}
|
|
18835
19412
|
function getProp(obj, name) {
|
|
18836
|
-
const prop = obj.properties.find((item) => (
|
|
19413
|
+
const prop = obj.properties.find((item) => (ts7.isPropertyAssignment(item) || ts7.isShorthandPropertyAssignment(item)) && propertyName(item.name) === name);
|
|
18837
19414
|
if (!prop)
|
|
18838
19415
|
return;
|
|
18839
|
-
if (
|
|
19416
|
+
if (ts7.isPropertyAssignment(prop))
|
|
18840
19417
|
return prop.initializer;
|
|
18841
|
-
if (
|
|
19418
|
+
if (ts7.isShorthandPropertyAssignment(prop))
|
|
18842
19419
|
return prop.name;
|
|
18843
19420
|
return;
|
|
18844
19421
|
}
|
|
@@ -18846,10 +19423,10 @@ function toCompilerDiagnostic(diagnostic, rootDir) {
|
|
|
18846
19423
|
const file = diagnostic.file;
|
|
18847
19424
|
const position = file && diagnostic.start !== undefined ? file.getLineAndCharacterOfPosition(diagnostic.start) : undefined;
|
|
18848
19425
|
return {
|
|
18849
|
-
severity: diagnostic.category ===
|
|
19426
|
+
severity: diagnostic.category === ts7.DiagnosticCategory.Error ? "error" : "warn",
|
|
18850
19427
|
code: `typescript-${diagnostic.code}`,
|
|
18851
19428
|
errorCode: `TS${diagnostic.code}`,
|
|
18852
|
-
message:
|
|
19429
|
+
message: ts7.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
18853
19430
|
`),
|
|
18854
19431
|
...file ? { file: sourcePath(rootDir, file.fileName) } : {},
|
|
18855
19432
|
...position ? { line: position.line + 1 } : {}
|
|
@@ -18857,16 +19434,16 @@ function toCompilerDiagnostic(diagnostic, rootDir) {
|
|
|
18857
19434
|
}
|
|
18858
19435
|
function stringLiteralProp(obj, name) {
|
|
18859
19436
|
const expr = getProp(obj, name);
|
|
18860
|
-
return expr &&
|
|
19437
|
+
return expr && ts7.isStringLiteral(expr) ? expr.text : undefined;
|
|
18861
19438
|
}
|
|
18862
19439
|
function arrayProp(obj, name) {
|
|
18863
19440
|
const expr = getProp(obj, name);
|
|
18864
|
-
return expr &&
|
|
19441
|
+
return expr && ts7.isArrayLiteralExpression(expr) ? [...expr.elements] : [];
|
|
18865
19442
|
}
|
|
18866
19443
|
function parseAspectRefs(expression, ctx, owner) {
|
|
18867
19444
|
if (!expression)
|
|
18868
19445
|
return [];
|
|
18869
|
-
if (!
|
|
19446
|
+
if (!ts7.isArrayLiteralExpression(expression)) {
|
|
18870
19447
|
ctx.diagnostics.push({
|
|
18871
19448
|
severity: "error",
|
|
18872
19449
|
code: "dynamic-aspect-reference",
|
|
@@ -18881,7 +19458,7 @@ function parseAspectRefs(expression, ctx, owner) {
|
|
|
18881
19458
|
}
|
|
18882
19459
|
const refs = [];
|
|
18883
19460
|
for (const element of expression.elements) {
|
|
18884
|
-
if (
|
|
19461
|
+
if (ts7.isSpreadElement(element) || !ts7.isIdentifier(element)) {
|
|
18885
19462
|
ctx.diagnostics.push({
|
|
18886
19463
|
severity: "error",
|
|
18887
19464
|
code: "dynamic-aspect-reference",
|
|
@@ -18894,7 +19471,7 @@ function parseAspectRefs(expression, ctx, owner) {
|
|
|
18894
19471
|
});
|
|
18895
19472
|
continue;
|
|
18896
19473
|
}
|
|
18897
|
-
const declaration = resolveDeclaration(element, ctx).find((candidate) =>
|
|
19474
|
+
const declaration = resolveDeclaration(element, ctx).find((candidate) => ts7.isFunctionDeclaration(candidate) || ts7.isVariableDeclaration(candidate) && candidate.initializer !== undefined && (ts7.isArrowFunction(candidate.initializer) || ts7.isFunctionExpression(candidate.initializer)));
|
|
18898
19475
|
if (!declaration) {
|
|
18899
19476
|
ctx.diagnostics.push({
|
|
18900
19477
|
severity: "error",
|
|
@@ -18908,7 +19485,7 @@ function parseAspectRefs(expression, ctx, owner) {
|
|
|
18908
19485
|
});
|
|
18909
19486
|
continue;
|
|
18910
19487
|
}
|
|
18911
|
-
const name =
|
|
19488
|
+
const name = ts7.isFunctionDeclaration(declaration) ? declaration.name?.text : ts7.isVariableDeclaration(declaration) ? variableName(declaration) : undefined;
|
|
18912
19489
|
if (!name)
|
|
18913
19490
|
continue;
|
|
18914
19491
|
const declaredFile = declaration.getSourceFile().fileName;
|
|
@@ -18928,9 +19505,9 @@ function booleanProp(obj, name) {
|
|
|
18928
19505
|
const expr = getProp(obj, name);
|
|
18929
19506
|
if (!expr)
|
|
18930
19507
|
return;
|
|
18931
|
-
if (expr.kind ===
|
|
19508
|
+
if (expr.kind === ts7.SyntaxKind.TrueKeyword)
|
|
18932
19509
|
return true;
|
|
18933
|
-
if (expr.kind ===
|
|
19510
|
+
if (expr.kind === ts7.SyntaxKind.FalseKeyword)
|
|
18934
19511
|
return false;
|
|
18935
19512
|
return;
|
|
18936
19513
|
}
|
|
@@ -18944,15 +19521,15 @@ function parseBindingOptions(args, defaultName) {
|
|
|
18944
19521
|
let defaultValue;
|
|
18945
19522
|
const first = args[0];
|
|
18946
19523
|
const second = args[1];
|
|
18947
|
-
if (first &&
|
|
19524
|
+
if (first && ts7.isStringLiteral(first)) {
|
|
18948
19525
|
name = first.text;
|
|
18949
|
-
} else if (first &&
|
|
19526
|
+
} else if (first && ts7.isObjectLiteralExpression(first)) {
|
|
18950
19527
|
const nameProp = getProp(first, "name");
|
|
18951
|
-
if (nameProp &&
|
|
19528
|
+
if (nameProp && ts7.isStringLiteral(nameProp)) {
|
|
18952
19529
|
name = nameProp.text;
|
|
18953
19530
|
}
|
|
18954
19531
|
const trProp = getProp(first, "transform");
|
|
18955
|
-
if (trProp &&
|
|
19532
|
+
if (trProp && ts7.isStringLiteral(trProp)) {
|
|
18956
19533
|
const val = trProp.text;
|
|
18957
19534
|
if (val === "number" || val === "boolean" || val === "string") {
|
|
18958
19535
|
transform = val;
|
|
@@ -18963,9 +19540,9 @@ function parseBindingOptions(args, defaultName) {
|
|
|
18963
19540
|
defaultValue = parseLiteralValue(defProp);
|
|
18964
19541
|
}
|
|
18965
19542
|
}
|
|
18966
|
-
if (second &&
|
|
19543
|
+
if (second && ts7.isObjectLiteralExpression(second)) {
|
|
18967
19544
|
const trProp = getProp(second, "transform");
|
|
18968
|
-
if (trProp &&
|
|
19545
|
+
if (trProp && ts7.isStringLiteral(trProp)) {
|
|
18969
19546
|
const val = trProp.text;
|
|
18970
19547
|
if (val === "number" || val === "boolean" || val === "string") {
|
|
18971
19548
|
transform = val;
|
|
@@ -18979,18 +19556,18 @@ function parseBindingOptions(args, defaultName) {
|
|
|
18979
19556
|
return { name, ...transform ? { transform } : {}, default: defaultValue };
|
|
18980
19557
|
}
|
|
18981
19558
|
function parseLiteralValue(node) {
|
|
18982
|
-
if (
|
|
19559
|
+
if (ts7.isStringLiteral(node))
|
|
18983
19560
|
return node.text;
|
|
18984
|
-
if (
|
|
19561
|
+
if (ts7.isNumericLiteral(node))
|
|
18985
19562
|
return Number(node.text);
|
|
18986
|
-
if (node.kind ===
|
|
19563
|
+
if (node.kind === ts7.SyntaxKind.TrueKeyword)
|
|
18987
19564
|
return true;
|
|
18988
|
-
if (node.kind ===
|
|
19565
|
+
if (node.kind === ts7.SyntaxKind.FalseKeyword)
|
|
18989
19566
|
return false;
|
|
18990
|
-
if (
|
|
19567
|
+
if (ts7.isArrayLiteralExpression(node)) {
|
|
18991
19568
|
return node.elements.map(parseLiteralValue);
|
|
18992
19569
|
}
|
|
18993
|
-
if (
|
|
19570
|
+
if (ts7.isObjectLiteralExpression(node)) {
|
|
18994
19571
|
return parseObjectLiteralValues(node);
|
|
18995
19572
|
}
|
|
18996
19573
|
return;
|
|
@@ -18998,7 +19575,7 @@ function parseLiteralValue(node) {
|
|
|
18998
19575
|
function parseObjectLiteralValues(obj) {
|
|
18999
19576
|
const result = {};
|
|
19000
19577
|
for (const prop of obj.properties) {
|
|
19001
|
-
if (
|
|
19578
|
+
if (ts7.isPropertyAssignment(prop)) {
|
|
19002
19579
|
const name = propertyName(prop.name);
|
|
19003
19580
|
const init = prop.initializer;
|
|
19004
19581
|
if (init) {
|
|
@@ -19015,7 +19592,7 @@ function sourcePath(rootDir, absFile) {
|
|
|
19015
19592
|
return relative2(rootDir, absFile).split(sep2).join("/");
|
|
19016
19593
|
}
|
|
19017
19594
|
function unwrapInfraResourceExpression(value) {
|
|
19018
|
-
while (
|
|
19595
|
+
while (ts7.isParenthesizedExpression(value) || ts7.isAsExpression(value) || ts7.isTypeAssertionExpression(value) || ts7.isSatisfiesExpression(value) || ts7.isNonNullExpression(value)) {
|
|
19019
19596
|
value = value.expression;
|
|
19020
19597
|
}
|
|
19021
19598
|
return value;
|
|
@@ -19025,7 +19602,7 @@ function infraResourceProp(obj, name, ctx) {
|
|
|
19025
19602
|
if (members.length === 0)
|
|
19026
19603
|
return;
|
|
19027
19604
|
const member = members[0];
|
|
19028
|
-
if (members.length !== 1 || !
|
|
19605
|
+
if (members.length !== 1 || !ts7.isPropertyAssignment(member) || ts7.isComputedPropertyName(member.name) || obj.properties.some(ts7.isSpreadAssignment)) {
|
|
19029
19606
|
pushResourceError(ctx, "unknown-resource", `${name} 必须是唯一、显式的静态属性,且不能被对象展开覆盖`, sourcePath(ctx.rootDir, obj.getSourceFile().fileName), lineOf(member), `使用 ${name}: [...],不要使用简写属性、计算属性或对象展开。`);
|
|
19030
19607
|
return;
|
|
19031
19608
|
}
|
|
@@ -19038,7 +19615,7 @@ function indexInfraResource(cls, className, sf, ctx) {
|
|
|
19038
19615
|
const file = sourcePath(ctx.rootDir, sf.fileName);
|
|
19039
19616
|
const line = lineOf(cls);
|
|
19040
19617
|
const options = decoratorObjectArg(decorator);
|
|
19041
|
-
if (!options || options.properties.some((property) => !
|
|
19618
|
+
if (!options || options.properties.some((property) => !ts7.isPropertyAssignment(property) || ts7.isComputedPropertyName(property.name)) || new Set(options.properties.map((property) => property.name && propertyName(property.name))).size !== options.properties.length) {
|
|
19042
19619
|
pushResourceError(ctx, "invalid-resource-kind", "@InfraResource 需要静态的 { name, kind } 对象参数", file, line, '使用 @InfraResource({ name: "orders-db", kind: "database" }),不要使用对象展开或重复属性。');
|
|
19043
19620
|
return;
|
|
19044
19621
|
}
|
|
@@ -19069,14 +19646,14 @@ function indexInfraResource(cls, className, sf, ctx) {
|
|
|
19069
19646
|
}
|
|
19070
19647
|
function resolveInfraResourceRef(el, ctx, owner, file, line) {
|
|
19071
19648
|
const unwrapped = unwrapInfraResourceExpression(unwrapForwardRef(unwrapInfraResourceExpression(el)));
|
|
19072
|
-
const identifier =
|
|
19649
|
+
const identifier = ts7.isIdentifier(unwrapped) ? unwrapped : ts7.isPropertyAccessExpression(unwrapped) && ts7.isIdentifier(unwrapped.name) ? unwrapped.name : undefined;
|
|
19073
19650
|
let symbol = identifier ? ctx.checker.getSymbolAtLocation(identifier) : undefined;
|
|
19074
19651
|
const visited = new Set;
|
|
19075
|
-
while (symbol && symbol.flags &
|
|
19652
|
+
while (symbol && symbol.flags & ts7.SymbolFlags.Alias && !visited.has(symbol)) {
|
|
19076
19653
|
visited.add(symbol);
|
|
19077
19654
|
symbol = ctx.checker.getAliasedSymbol(symbol);
|
|
19078
19655
|
}
|
|
19079
|
-
const declaration = symbol?.declarations?.find(
|
|
19656
|
+
const declaration = symbol?.declarations?.find(ts7.isClassDeclaration);
|
|
19080
19657
|
const resource = declaration ? ctx.infraResources.get(declaration) : undefined;
|
|
19081
19658
|
if (!resource) {
|
|
19082
19659
|
pushResourceError(ctx, "unknown-resource", `${owner} 引用的资源 '${nodeText(el)}' 未声明为 @InfraResource`, file, line, "引用实际声明了 @InfraResource({ name, kind }) 的类,不能依赖其他文件的同名类。");
|
|
@@ -19089,7 +19666,7 @@ function parseModuleInfraResources(value, ctx, owner, file, line) {
|
|
|
19089
19666
|
if (!value)
|
|
19090
19667
|
return names;
|
|
19091
19668
|
const array = unwrapInfraResourceExpression(value);
|
|
19092
|
-
if (!
|
|
19669
|
+
if (!ts7.isArrayLiteralExpression(array)) {
|
|
19093
19670
|
pushResourceError(ctx, "unknown-resource", `${owner} 的 resources 必须是静态数组`, file, line, "使用 resources: [ResourceClass];省略该属性表示不声明资源。");
|
|
19094
19671
|
return names;
|
|
19095
19672
|
}
|
|
@@ -19104,14 +19681,14 @@ function parseInfraResourceUseRefs(value, ctx, owner, file, line) {
|
|
|
19104
19681
|
if (!value)
|
|
19105
19682
|
return [];
|
|
19106
19683
|
const array = unwrapInfraResourceExpression(value);
|
|
19107
|
-
if (!
|
|
19684
|
+
if (!ts7.isArrayLiteralExpression(array)) {
|
|
19108
19685
|
pushResourceError(ctx, "unknown-resource", `${owner} 的 uses 必须是静态数组`, file, line, '使用 uses: [{ resource: ResourceClass, operations: ["read"] }]。');
|
|
19109
19686
|
return [];
|
|
19110
19687
|
}
|
|
19111
19688
|
const uses = new Map;
|
|
19112
19689
|
for (const element of array.elements) {
|
|
19113
19690
|
const entry = unwrapInfraResourceExpression(element);
|
|
19114
|
-
if (!
|
|
19691
|
+
if (!ts7.isObjectLiteralExpression(entry) || entry.properties.some((property) => !ts7.isPropertyAssignment(property) || ts7.isComputedPropertyName(property.name) || !["resource", "operations"].includes(propertyName(property.name))) || new Set(entry.properties.map((property) => property.name && propertyName(property.name))).size !== entry.properties.length) {
|
|
19115
19692
|
pushResourceError(ctx, "unknown-resource", `${owner} 的 uses 项必须是显式的 { resource, operations } 对象`, file, lineOf(element), "使用显式属性,不要使用对象/数组展开、简写、计算属性或重复属性。");
|
|
19116
19693
|
continue;
|
|
19117
19694
|
}
|
|
@@ -19129,14 +19706,14 @@ function parseInfraResourceUseRefs(value, ctx, owner, file, line) {
|
|
|
19129
19706
|
operations.add("read");
|
|
19130
19707
|
} else {
|
|
19131
19708
|
const operationArray = unwrapInfraResourceExpression(operationsEl);
|
|
19132
|
-
if (!
|
|
19709
|
+
if (!ts7.isArrayLiteralExpression(operationArray) || operationArray.elements.length === 0) {
|
|
19133
19710
|
pushResourceError(ctx, "invalid-resource-operation", `${owner} 对资源 '${resource}' 的 operations 必须是非空静态数组`, file, lineOf(operationsEl), "仅省略 operations 时默认 read;显式填写时必须包含有效操作。");
|
|
19134
19711
|
continue;
|
|
19135
19712
|
}
|
|
19136
19713
|
let invalid = false;
|
|
19137
19714
|
for (const operationEl of operationArray.elements) {
|
|
19138
19715
|
const operation = unwrapInfraResourceExpression(operationEl);
|
|
19139
|
-
if (!
|
|
19716
|
+
if (!ts7.isStringLiteral(operation) || !isInfraResourceOperation(operation.text)) {
|
|
19140
19717
|
pushResourceError(ctx, "invalid-resource-operation", `${owner} 对资源 '${resource}' 声明了无效操作 '${nodeText(operationEl)}'`, file, lineOf(operationEl), `operations 只能包含字符串字面量 ${INFRA_RESOURCE_OPERATIONS.join(" | ")}。`);
|
|
19141
19718
|
invalid = true;
|
|
19142
19719
|
continue;
|
|
@@ -19183,11 +19760,11 @@ import { join as join4 } from "node:path";
|
|
|
19183
19760
|
|
|
19184
19761
|
// src/type-safety.ts
|
|
19185
19762
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
19186
|
-
import { dirname as dirname3, join as join3, relative as relative3, resolve as
|
|
19187
|
-
import * as
|
|
19763
|
+
import { dirname as dirname3, join as join3, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
|
|
19764
|
+
import * as ts9 from "@typescript/typescript6";
|
|
19188
19765
|
|
|
19189
19766
|
// src/sql-safety.ts
|
|
19190
|
-
import * as
|
|
19767
|
+
import * as ts8 from "@typescript/typescript6";
|
|
19191
19768
|
var SQL_SAFETY_DIAGNOSTIC_CODES = {
|
|
19192
19769
|
"sql-result-assertion": { errorCode: "SC6007", docsUrl: "https://supacloud.dev/errors/SC6007" },
|
|
19193
19770
|
"sql-raw-dynamic": { errorCode: "SC6008", docsUrl: "https://supacloud.dev/errors/SC6008" }
|
|
@@ -19195,10 +19772,10 @@ var SQL_SAFETY_DIAGNOSTIC_CODES = {
|
|
|
19195
19772
|
function scanDrizzleSql(sourceFile, checker, file, strict) {
|
|
19196
19773
|
const diagnostics = [];
|
|
19197
19774
|
const importedSql = (expression) => {
|
|
19198
|
-
const symbol = checker.getSymbolAtLocation(
|
|
19775
|
+
const symbol = checker.getSymbolAtLocation(ts8.isPropertyAccessExpression(expression) ? expression.name : expression);
|
|
19199
19776
|
if (!symbol)
|
|
19200
19777
|
return false;
|
|
19201
|
-
const target = symbol.flags &
|
|
19778
|
+
const target = symbol.flags & ts8.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
19202
19779
|
return target.name === "sql" && (target.declarations ?? []).some((declaration) => /(?:^|\/)node_modules\/drizzle-orm\//.test(declaration.getSourceFile().fileName.replaceAll("\\", "/")));
|
|
19203
19780
|
};
|
|
19204
19781
|
const report = (code, node, message) => {
|
|
@@ -19212,16 +19789,16 @@ function scanDrizzleSql(sourceFile, checker, file, strict) {
|
|
|
19212
19789
|
});
|
|
19213
19790
|
};
|
|
19214
19791
|
const visit = (node) => {
|
|
19215
|
-
if (
|
|
19792
|
+
if (ts8.isTaggedTemplateExpression(node) && importedSql(node.tag) && node.typeArguments?.some((type) => type.kind !== ts8.SyntaxKind.UnknownKeyword)) {
|
|
19216
19793
|
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.");
|
|
19217
19794
|
}
|
|
19218
|
-
if (
|
|
19795
|
+
if (ts8.isCallExpression(node) && ts8.isPropertyAccessExpression(node.expression) && node.expression.name.text === "raw" && importedSql(node.expression.expression)) {
|
|
19219
19796
|
const argument = node.arguments[0];
|
|
19220
|
-
if (!argument || !
|
|
19797
|
+
if (!argument || !ts8.isStringLiteral(argument) && !ts8.isNoSubstitutionTemplateLiteral(argument)) {
|
|
19221
19798
|
report("sql-raw-dynamic", node, "Dynamic sql.raw bypasses parameter binding. Interpolate values with sql templates; keep reviewed static DDL in migrations.");
|
|
19222
19799
|
}
|
|
19223
19800
|
}
|
|
19224
|
-
|
|
19801
|
+
ts8.forEachChild(node, visit);
|
|
19225
19802
|
};
|
|
19226
19803
|
visit(sourceFile);
|
|
19227
19804
|
return diagnostics;
|
|
@@ -19253,7 +19830,7 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
19253
19830
|
for (const [file, content] of Object.entries(artifacts)) {
|
|
19254
19831
|
if (content === undefined)
|
|
19255
19832
|
continue;
|
|
19256
|
-
const sourceFile =
|
|
19833
|
+
const sourceFile = ts9.createSourceFile(file, content, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TS);
|
|
19257
19834
|
for (const node of descendantsOfKind2(sourceFile, isAnyKeyword)) {
|
|
19258
19835
|
diagnostics.push(makeDiagnostic("generated-any", `生成产物 ${file} 包含 any;严格生成模式要求使用 unknown、具体接口或泛型约束。`, sourceFile, node, strict));
|
|
19259
19836
|
}
|
|
@@ -19261,31 +19838,31 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
19261
19838
|
return diagnostics;
|
|
19262
19839
|
}
|
|
19263
19840
|
function scanProductionSource(options) {
|
|
19264
|
-
const rootDir =
|
|
19265
|
-
const configPath =
|
|
19841
|
+
const rootDir = resolve3(options.rootDir);
|
|
19842
|
+
const configPath = ts9.findConfigFile(rootDir, ts9.sys.fileExists) ?? join3(rootDir, "tsconfig.json");
|
|
19266
19843
|
const projectConfig = existsSync2(configPath) ? readProjectConfig2(configPath) : {
|
|
19267
19844
|
options: {
|
|
19268
19845
|
strict: true,
|
|
19269
19846
|
skipLibCheck: true,
|
|
19270
|
-
target:
|
|
19271
|
-
module:
|
|
19272
|
-
moduleResolution:
|
|
19847
|
+
target: ts9.ScriptTarget.ES2022,
|
|
19848
|
+
module: ts9.ModuleKind.ESNext,
|
|
19849
|
+
moduleResolution: ts9.ModuleResolutionKind.Bundler
|
|
19273
19850
|
},
|
|
19274
19851
|
errors: []
|
|
19275
19852
|
};
|
|
19276
19853
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
19277
|
-
const rootNames =
|
|
19854
|
+
const rootNames = ts9.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist"], include).filter((file) => isProductionSourcePath(rootDir, file, [...DEFAULT_EXCLUDES, ...options.exclude ?? []]));
|
|
19278
19855
|
const compilerOptions = { ...projectConfig.options, noEmit: true };
|
|
19279
|
-
const host =
|
|
19856
|
+
const host = ts9.createCompilerHost(compilerOptions);
|
|
19280
19857
|
host.getCurrentDirectory = () => dirname3(configPath);
|
|
19281
|
-
const program =
|
|
19858
|
+
const program = ts9.createProgram(rootNames, compilerOptions, host);
|
|
19282
19859
|
const outDir = options.outDir ? normalizeRelative(rootDir, options.outDir) : undefined;
|
|
19283
19860
|
const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
|
|
19284
19861
|
const sourceFiles = program.getSourceFiles().filter((sourceFile) => isProductionSource(rootDir, sourceFile, excludes, outDir));
|
|
19285
19862
|
const diagnostics = [...projectConfig.errors, ...program.getOptionsDiagnostics()].map((diagnostic) => ({
|
|
19286
19863
|
severity: "error",
|
|
19287
19864
|
code: "source-config",
|
|
19288
|
-
message:
|
|
19865
|
+
message: ts9.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
19289
19866
|
`),
|
|
19290
19867
|
file: diagnostic.file ? normalizeRelative(rootDir, diagnostic.file.fileName) : normalizeRelative(rootDir, configPath),
|
|
19291
19868
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
@@ -19302,7 +19879,7 @@ function scanProductionSource(options) {
|
|
|
19302
19879
|
diagnostics.push({
|
|
19303
19880
|
severity: "error",
|
|
19304
19881
|
code: "source-typescript",
|
|
19305
|
-
message:
|
|
19882
|
+
message: ts9.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
19306
19883
|
`),
|
|
19307
19884
|
...diagnostic.file ? { file: normalizeRelative(rootDir, diagnostic.file.fileName) } : {},
|
|
19308
19885
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
@@ -19312,9 +19889,9 @@ function scanProductionSource(options) {
|
|
|
19312
19889
|
for (const sourceFile of sourceFiles) {
|
|
19313
19890
|
scanSourceFile(sourceFile, checker, rootDir, diagnostics, options.strict ?? false);
|
|
19314
19891
|
diagnostics.push(...scanDrizzleSql(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), options.strict ?? false));
|
|
19315
|
-
const scanner =
|
|
19316
|
-
for (let kind = scanner.scan();kind !==
|
|
19317
|
-
if ((kind ===
|
|
19892
|
+
const scanner = ts9.createScanner(ts9.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
|
|
19893
|
+
for (let kind = scanner.scan();kind !== ts9.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
|
|
19894
|
+
if ((kind === ts9.SyntaxKind.SingleLineCommentTrivia || kind === ts9.SyntaxKind.MultiLineCommentTrivia) && /@ts-(?:ignore|nocheck|expect-error)\b/.test(scanner.getTokenText())) {
|
|
19318
19895
|
diagnostics.push({
|
|
19319
19896
|
severity: "error",
|
|
19320
19897
|
code: "source-type-suppression",
|
|
@@ -19334,22 +19911,22 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
19334
19911
|
diagnostics.push(makeDiagnostic("source-any", "生产源码使用了显式 any;请改用 unknown、具体接口或泛型约束。", sourceFile, node, strict, rootDir));
|
|
19335
19912
|
}
|
|
19336
19913
|
for (const node of descendants(sourceFile)) {
|
|
19337
|
-
if (
|
|
19338
|
-
if (
|
|
19914
|
+
if (ts9.isAsExpression(node)) {
|
|
19915
|
+
if (ts9.isAsExpression(node.parent) || ts9.isTypeAssertionExpression(node.parent))
|
|
19339
19916
|
continue;
|
|
19340
19917
|
const assertedType = node.type.getText(sourceFile);
|
|
19341
19918
|
if (assertedType === "const")
|
|
19342
19919
|
continue;
|
|
19343
19920
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
19344
|
-
} else if (
|
|
19345
|
-
if (
|
|
19921
|
+
} else if (ts9.isTypeAssertionExpression(node)) {
|
|
19922
|
+
if (ts9.isAsExpression(node.parent) || ts9.isTypeAssertionExpression(node.parent))
|
|
19346
19923
|
continue;
|
|
19347
19924
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
19348
|
-
} else if (
|
|
19925
|
+
} else if (ts9.isNonNullExpression(node)) {
|
|
19349
19926
|
diagnostics.push(makeDiagnostic("source-non-null-assertion", `生产源码包含非空断言 ${node.getText(sourceFile)};请显式处理 null/undefined。`, sourceFile, node, strict, rootDir));
|
|
19350
19927
|
}
|
|
19351
19928
|
}
|
|
19352
|
-
for (const declaration of descendantsOfKind2(sourceFile,
|
|
19929
|
+
for (const declaration of descendantsOfKind2(sourceFile, ts9.isVariableDeclaration)) {
|
|
19353
19930
|
const initializer = declaration.initializer;
|
|
19354
19931
|
if (!initializer || declaration.type)
|
|
19355
19932
|
continue;
|
|
@@ -19365,11 +19942,11 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
19365
19942
|
if (isLetDeclaration(declaration) && isLiteralSyntax(initializer) && !isLiteralType(declarationType)) {
|
|
19366
19943
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `变量 ${declaration.name.getText(sourceFile)} 的字面量类型从 ${checker.typeToString(initializerType, initializer)} 隐式宽化为 ${checker.typeToString(declarationType, declaration)};请补充类型或使用 const。`, sourceFile, declaration, strict, rootDir));
|
|
19367
19944
|
}
|
|
19368
|
-
if (
|
|
19945
|
+
if (ts9.isObjectLiteralExpression(initializer) && isConstDeclaration(declaration) && initializer.getText(sourceFile).length > 0 && initializer.properties.some((property) => ts9.isPropertyAssignment(property) && property.initializer !== undefined && !ts9.isAsExpression(property.initializer) && isLiteralExpression(property.initializer))) {
|
|
19369
19946
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `常量对象 ${declaration.name.getText(sourceFile)} 的字面量属性会隐式宽化;请补充对象类型或使用 as const。`, sourceFile, declaration, strict, rootDir));
|
|
19370
19947
|
}
|
|
19371
19948
|
}
|
|
19372
|
-
for (const parameter of descendantsOfKind2(sourceFile,
|
|
19949
|
+
for (const parameter of descendantsOfKind2(sourceFile, ts9.isParameter)) {
|
|
19373
19950
|
if (parameter.type)
|
|
19374
19951
|
continue;
|
|
19375
19952
|
for (const name of bindingNames(parameter.name)) {
|
|
@@ -19380,10 +19957,10 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
19380
19957
|
}
|
|
19381
19958
|
}
|
|
19382
19959
|
function readProjectConfig2(configPath) {
|
|
19383
|
-
const config =
|
|
19960
|
+
const config = ts9.readConfigFile(configPath, (file) => readFileSync2(file, "utf8"));
|
|
19384
19961
|
if (config.error)
|
|
19385
19962
|
return { options: {}, errors: [config.error] };
|
|
19386
|
-
const parsed =
|
|
19963
|
+
const parsed = ts9.parseJsonConfigFileContent(config.config, ts9.sys, dirname3(configPath));
|
|
19387
19964
|
return { options: parsed.options, errors: parsed.errors };
|
|
19388
19965
|
}
|
|
19389
19966
|
function isProductionSource(rootDir, sourceFile, excludes, outDir) {
|
|
@@ -19403,42 +19980,42 @@ function globMatches(value, pattern) {
|
|
|
19403
19980
|
return new RegExp(`^${escaped}$`).test(value);
|
|
19404
19981
|
}
|
|
19405
19982
|
function bindingNames(name) {
|
|
19406
|
-
if (
|
|
19983
|
+
if (ts9.isIdentifier(name))
|
|
19407
19984
|
return [name];
|
|
19408
|
-
return name.elements.flatMap((element) =>
|
|
19985
|
+
return name.elements.flatMap((element) => ts9.isBindingElement(element) ? bindingNames(element.name) : []);
|
|
19409
19986
|
}
|
|
19410
19987
|
function isLiteralExpression(node) {
|
|
19411
19988
|
if (!node)
|
|
19412
19989
|
return false;
|
|
19413
19990
|
return [
|
|
19414
|
-
|
|
19415
|
-
|
|
19416
|
-
|
|
19417
|
-
|
|
19991
|
+
ts9.SyntaxKind.StringLiteral,
|
|
19992
|
+
ts9.SyntaxKind.NumericLiteral,
|
|
19993
|
+
ts9.SyntaxKind.TrueKeyword,
|
|
19994
|
+
ts9.SyntaxKind.FalseKeyword
|
|
19418
19995
|
].includes(node.kind);
|
|
19419
19996
|
}
|
|
19420
19997
|
function isLiteralSyntax(node) {
|
|
19421
|
-
return
|
|
19998
|
+
return ts9.isStringLiteral(node) || ts9.isNumericLiteral(node) || node.kind === ts9.SyntaxKind.TrueKeyword || node.kind === ts9.SyntaxKind.FalseKeyword;
|
|
19422
19999
|
}
|
|
19423
20000
|
function isLiteralType(type) {
|
|
19424
|
-
return (type.flags & (
|
|
20001
|
+
return (type.flags & (ts9.TypeFlags.StringLiteral | ts9.TypeFlags.NumberLiteral | ts9.TypeFlags.BooleanLiteral | ts9.TypeFlags.BigIntLiteral)) !== 0;
|
|
19425
20002
|
}
|
|
19426
20003
|
function isAnyType(type) {
|
|
19427
|
-
return (type.flags &
|
|
20004
|
+
return (type.flags & ts9.TypeFlags.Any) !== 0;
|
|
19428
20005
|
}
|
|
19429
20006
|
function isLetDeclaration(declaration) {
|
|
19430
|
-
return
|
|
20007
|
+
return ts9.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts9.NodeFlags.Let) !== 0;
|
|
19431
20008
|
}
|
|
19432
20009
|
function isConstDeclaration(declaration) {
|
|
19433
|
-
return
|
|
20010
|
+
return ts9.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts9.NodeFlags.Const) !== 0;
|
|
19434
20011
|
}
|
|
19435
20012
|
function descendants(root) {
|
|
19436
20013
|
const result = [];
|
|
19437
20014
|
const visit = (node) => {
|
|
19438
20015
|
result.push(node);
|
|
19439
|
-
|
|
20016
|
+
ts9.forEachChild(node, visit);
|
|
19440
20017
|
};
|
|
19441
|
-
|
|
20018
|
+
ts9.forEachChild(root, visit);
|
|
19442
20019
|
return result;
|
|
19443
20020
|
}
|
|
19444
20021
|
function descendantsOfKind2(root, predicate) {
|
|
@@ -19446,9 +20023,9 @@ function descendantsOfKind2(root, predicate) {
|
|
|
19446
20023
|
const visit = (node) => {
|
|
19447
20024
|
if (predicate(node))
|
|
19448
20025
|
result.push(node);
|
|
19449
|
-
|
|
20026
|
+
ts9.forEachChild(node, visit);
|
|
19450
20027
|
};
|
|
19451
|
-
|
|
20028
|
+
ts9.forEachChild(root, visit);
|
|
19452
20029
|
return result;
|
|
19453
20030
|
}
|
|
19454
20031
|
function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir) {
|
|
@@ -19469,7 +20046,7 @@ function normalizeRelative(rootDir, filePath) {
|
|
|
19469
20046
|
return relative3(rootDir, filePath).split(sep3).join("/").replace(/^\.\//, "");
|
|
19470
20047
|
}
|
|
19471
20048
|
function isAnyKeyword(node) {
|
|
19472
|
-
return node.kind ===
|
|
20049
|
+
return node.kind === ts9.SyntaxKind.AnyKeyword;
|
|
19473
20050
|
}
|
|
19474
20051
|
|
|
19475
20052
|
// src/compile.ts
|
|
@@ -19870,8 +20447,8 @@ function formatDeliveryPlan(result) {
|
|
|
19870
20447
|
// src/delivery-build.ts
|
|
19871
20448
|
import { mkdir as mkdir3, mkdtemp, readFile as readFile5, realpath as realpath3, rename as rename3, rm as rm2 } from "node:fs/promises";
|
|
19872
20449
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
19873
|
-
import { dirname as dirname7, join as join9, relative as relative7, resolve as
|
|
19874
|
-
import * as
|
|
20450
|
+
import { dirname as dirname7, join as join9, relative as relative7, resolve as resolve11, sep as sep7 } from "node:path";
|
|
20451
|
+
import * as ts14 from "@typescript/typescript6";
|
|
19875
20452
|
|
|
19876
20453
|
// src/delivery-build-schema.ts
|
|
19877
20454
|
init_delivery_build_schema();
|
|
@@ -19912,23 +20489,23 @@ function renderDeliveryTarget(graph, target, options) {
|
|
|
19912
20489
|
init_delivery_files2();
|
|
19913
20490
|
import { isBuiltin } from "node:module";
|
|
19914
20491
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
19915
|
-
import { join as join7, resolve as
|
|
19916
|
-
import * as
|
|
20492
|
+
import { join as join7, resolve as resolve8 } from "node:path";
|
|
20493
|
+
import * as ts13 from "@typescript/typescript6";
|
|
19917
20494
|
|
|
19918
20495
|
// src/delivery-imports.ts
|
|
19919
|
-
import * as
|
|
20496
|
+
import * as ts12 from "@typescript/typescript6";
|
|
19920
20497
|
function staticDeliveryImports(path, contents) {
|
|
19921
20498
|
if (!/\.[cm]?[jt]sx?$/.test(path))
|
|
19922
20499
|
return contents;
|
|
19923
|
-
const source =
|
|
20500
|
+
const source = ts12.createSourceFile(path, new TextDecoder().decode(contents), ts12.ScriptTarget.Latest, true);
|
|
19924
20501
|
const computed = [];
|
|
19925
20502
|
function scan(node) {
|
|
19926
|
-
if (
|
|
20503
|
+
if (ts12.isCallExpression(node) && (node.expression.kind === ts12.SyntaxKind.ImportKeyword || ts12.isIdentifier(node.expression) && node.expression.text === "require")) {
|
|
19927
20504
|
const argument = node.arguments[0];
|
|
19928
|
-
if (!argument || !
|
|
20505
|
+
if (!argument || !ts12.isStringLiteral(argument) && !ts12.isNoSubstitutionTemplateLiteral(argument))
|
|
19929
20506
|
computed.push(node);
|
|
19930
20507
|
}
|
|
19931
|
-
|
|
20508
|
+
ts12.forEachChild(node, scan);
|
|
19932
20509
|
}
|
|
19933
20510
|
scan(source);
|
|
19934
20511
|
if (computed.length === 0)
|
|
@@ -19936,36 +20513,36 @@ function staticDeliveryImports(path, contents) {
|
|
|
19936
20513
|
const reject = () => {
|
|
19937
20514
|
throw new Error("Computed module loading is not supported in independent delivery bundles.");
|
|
19938
20515
|
};
|
|
19939
|
-
if (!
|
|
20516
|
+
if (!ts12.isExternalModule(source))
|
|
19940
20517
|
return reject();
|
|
19941
|
-
const host =
|
|
20518
|
+
const host = ts12.createCompilerHost({ noLib: true, noResolve: true, allowJs: true });
|
|
19942
20519
|
host.getSourceFile = (name) => name === path ? source : undefined;
|
|
19943
|
-
const checker =
|
|
20520
|
+
const checker = ts12.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, host).getTypeChecker();
|
|
19944
20521
|
const replacements = new Map;
|
|
19945
20522
|
const removed = new Set;
|
|
19946
20523
|
for (const call of computed) {
|
|
19947
20524
|
let visit = function(node) {
|
|
19948
|
-
const referenced =
|
|
19949
|
-
if (
|
|
20525
|
+
const referenced = ts12.isIdentifier(node) ? ts12.isShorthandPropertyAssignment(node.parent) ? checker.getShorthandAssignmentValueSymbol(node.parent) : ts12.isExportSpecifier(node.parent) ? checker.getExportSpecifierLocalTargetSymbol(node.parent) : checker.getSymbolAtLocation(node) : undefined;
|
|
20526
|
+
if (ts12.isIdentifier(node) && node !== declarationName && referenced === symbol) {
|
|
19950
20527
|
const use = node.parent;
|
|
19951
|
-
if (!
|
|
20528
|
+
if (!ts12.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
|
|
19952
20529
|
return reject();
|
|
19953
20530
|
const value = use.arguments[0];
|
|
19954
|
-
if (!value || !
|
|
20531
|
+
if (!value || !ts12.isStringLiteral(value) && !ts12.isNoSubstitutionTemplateLiteral(value))
|
|
19955
20532
|
return reject();
|
|
19956
20533
|
references++;
|
|
19957
|
-
replacements.set(use,
|
|
20534
|
+
replacements.set(use, ts12.factory.createCallExpression(call.expression, undefined, [value]));
|
|
19958
20535
|
}
|
|
19959
|
-
|
|
20536
|
+
ts12.forEachChild(node, visit);
|
|
19960
20537
|
};
|
|
19961
20538
|
const statement = call.parent;
|
|
19962
20539
|
const block = statement.parent;
|
|
19963
20540
|
const declaration = block.parent;
|
|
19964
|
-
if (call.expression.kind !==
|
|
20541
|
+
if (call.expression.kind !== ts12.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts12.isReturnStatement(statement) || !ts12.isBlock(block) || block.statements.length !== 1 || !ts12.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
|
|
19965
20542
|
return reject();
|
|
19966
20543
|
const parameter = declaration.parameters[0];
|
|
19967
20544
|
const argument = call.arguments[0];
|
|
19968
|
-
if (!parameter || !
|
|
20545
|
+
if (!parameter || !ts12.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts12.isIdentifier(argument) || checker.getSymbolAtLocation(argument) !== checker.getSymbolAtLocation(parameter.name))
|
|
19969
20546
|
return reject();
|
|
19970
20547
|
const symbol = checker.getSymbolAtLocation(declaration.name);
|
|
19971
20548
|
if (!symbol || symbol.declarations?.length !== 1)
|
|
@@ -19977,22 +20554,22 @@ function staticDeliveryImports(path, contents) {
|
|
|
19977
20554
|
return reject();
|
|
19978
20555
|
removed.add(declaration);
|
|
19979
20556
|
}
|
|
19980
|
-
const transformed =
|
|
20557
|
+
const transformed = ts12.transform(source, [(context) => {
|
|
19981
20558
|
const visit = (node) => {
|
|
19982
|
-
if (
|
|
20559
|
+
if (ts12.isFunctionDeclaration(node) && removed.has(node))
|
|
19983
20560
|
return;
|
|
19984
|
-
const replacement =
|
|
20561
|
+
const replacement = ts12.isCallExpression(node) ? replacements.get(node) : undefined;
|
|
19985
20562
|
if (replacement)
|
|
19986
20563
|
return replacement;
|
|
19987
|
-
return
|
|
20564
|
+
return ts12.visitEachChild(node, visit, context);
|
|
19988
20565
|
};
|
|
19989
|
-
return (node) =>
|
|
20566
|
+
return (node) => ts12.visitNode(node, visit, ts12.isSourceFile) ?? node;
|
|
19990
20567
|
}]);
|
|
19991
20568
|
try {
|
|
19992
20569
|
const transformedSource = transformed.transformed[0];
|
|
19993
20570
|
if (!transformedSource)
|
|
19994
20571
|
return reject();
|
|
19995
|
-
return new TextEncoder().encode(
|
|
20572
|
+
return new TextEncoder().encode(ts12.createPrinter().printFile(transformedSource));
|
|
19996
20573
|
} finally {
|
|
19997
20574
|
transformed.dispose();
|
|
19998
20575
|
}
|
|
@@ -20089,7 +20666,7 @@ async function bundleDeliveryTarget(name, code, project, generatedDirectory, opt
|
|
|
20089
20666
|
async function bundleDeliveryTargetInProcess(name, code, project, generatedDirectory, options) {
|
|
20090
20667
|
const inputs = new Map;
|
|
20091
20668
|
const workingDirectory = process.cwd();
|
|
20092
|
-
const entry =
|
|
20669
|
+
const entry = resolve8(generatedDirectory, `delivery-${name}.ts`);
|
|
20093
20670
|
const entryPattern = new RegExp(`^${entry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`);
|
|
20094
20671
|
const result = await Bun.build({
|
|
20095
20672
|
entrypoints: [entry],
|
|
@@ -20112,7 +20689,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
20112
20689
|
if (args.path === entry)
|
|
20113
20690
|
return { contents: code, loader: "ts" };
|
|
20114
20691
|
const bytes = await readFile4(args.path);
|
|
20115
|
-
inputs.set(
|
|
20692
|
+
inputs.set(resolve8(args.path), digest(bytes));
|
|
20116
20693
|
return { contents: staticDeliveryImports(args.path, bytes), loader: args.loader };
|
|
20117
20694
|
});
|
|
20118
20695
|
}
|
|
@@ -20122,7 +20699,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
20122
20699
|
throw new Error("Independent bundle failed or has no dependency metadata.");
|
|
20123
20700
|
const runtimeImports = new Set;
|
|
20124
20701
|
for (const [path, metadata] of Object.entries(result.metafile.inputs)) {
|
|
20125
|
-
if (
|
|
20702
|
+
if (resolve8(workingDirectory, path) !== entry && !inputs.has(resolve8(workingDirectory, path))) {
|
|
20126
20703
|
throw new Error("Bundler reported an input that was not captured by the delivery snapshot.");
|
|
20127
20704
|
}
|
|
20128
20705
|
for (const imported of metadata.imports) {
|
|
@@ -20140,16 +20717,16 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
20140
20717
|
const bytes = new Uint8Array(await output.arrayBuffer());
|
|
20141
20718
|
if (/\.[cm]?js$/.test(path)) {
|
|
20142
20719
|
let check = function(node) {
|
|
20143
|
-
const specifier =
|
|
20144
|
-
if (specifier &&
|
|
20720
|
+
const specifier = ts13.isImportDeclaration(node) || ts13.isExportDeclaration(node) ? node.moduleSpecifier : ts13.isCallExpression(node) && (node.expression.kind === ts13.SyntaxKind.ImportKeyword || ts13.isIdentifier(node.expression) && /^(?:__)?require$/.test(node.expression.text) || ts13.isPropertyAccessExpression(node.expression) && node.expression.name.text === "require" && ts13.isMetaProperty(node.expression.expression) && node.expression.expression.keywordToken === ts13.SyntaxKind.ImportKeyword) ? node.arguments[0] : undefined;
|
|
20721
|
+
if (specifier && ts13.isStringLiteralLike(specifier)) {
|
|
20145
20722
|
if (!isBuiltin(specifier.text) && specifier.text !== "bun" && !specifier.text.startsWith("bun:")) {
|
|
20146
20723
|
throw new Error("Independent bundles cannot retain external package imports.");
|
|
20147
20724
|
}
|
|
20148
20725
|
runtimeImports.add(specifier.text);
|
|
20149
20726
|
}
|
|
20150
|
-
|
|
20727
|
+
ts13.forEachChild(node, check);
|
|
20151
20728
|
};
|
|
20152
|
-
const source =
|
|
20729
|
+
const source = ts13.createSourceFile(path, new TextDecoder().decode(bytes), ts13.ScriptTarget.Latest, true);
|
|
20153
20730
|
check(source);
|
|
20154
20731
|
}
|
|
20155
20732
|
files.set(`bundle/${path}`, bytes);
|
|
@@ -20439,14 +21016,14 @@ interface DeliveryWorkerHost {
|
|
|
20439
21016
|
|
|
20440
21017
|
// src/delivery-migrations.ts
|
|
20441
21018
|
init_delivery_files2();
|
|
20442
|
-
import { resolve as
|
|
21019
|
+
import { resolve as resolve10 } from "node:path";
|
|
20443
21020
|
async function prepareDeliveryMigrations(project, generatedRoot, declarations = []) {
|
|
20444
21021
|
const entries = [];
|
|
20445
21022
|
const files = new Map;
|
|
20446
21023
|
const inputs = new Map;
|
|
20447
21024
|
let totalBytes = 0;
|
|
20448
21025
|
for (const declaration of [...declarations].sort((a, b) => BigInt(a.version) < BigInt(b.version) ? -1 : BigInt(a.version) > BigInt(b.version) ? 1 : 0)) {
|
|
20449
|
-
const source =
|
|
21026
|
+
const source = resolve10(project, declaration.source);
|
|
20450
21027
|
if (!inside(project, source) || inside(generatedRoot, source))
|
|
20451
21028
|
throw new Error("Invalid migration source.");
|
|
20452
21029
|
const bytes = await readBoundedOwned(project, source, 1048576);
|
|
@@ -20497,7 +21074,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20497
21074
|
const settings = parseDeliveryOptions(delivery);
|
|
20498
21075
|
if (typeof Bun === "undefined")
|
|
20499
21076
|
throw new Error("Independent delivery builds require Bun.");
|
|
20500
|
-
const configPath =
|
|
21077
|
+
const configPath = ts14.findConfigFile(resolve11(options.rootDir), ts14.sys.fileExists);
|
|
20501
21078
|
if (!configPath)
|
|
20502
21079
|
throw new Error("Independent delivery builds require a project tsconfig.json.");
|
|
20503
21080
|
const lexicalProject = dirname7(configPath);
|
|
@@ -20505,19 +21082,19 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20505
21082
|
const sourceRoot = await realpath3(options.rootDir);
|
|
20506
21083
|
if (!inside(project, sourceRoot))
|
|
20507
21084
|
throw new Error("Application sources must be inside the project.");
|
|
20508
|
-
const requested =
|
|
21085
|
+
const requested = resolve11(options.outDir, "delivery");
|
|
20509
21086
|
if (!inside(lexicalProject, requested))
|
|
20510
21087
|
throw new Error("Output must be inside the application project.");
|
|
20511
|
-
const buildRoot =
|
|
20512
|
-
const generatedRoot =
|
|
21088
|
+
const buildRoot = resolve11(project, relative7(lexicalProject, requested));
|
|
21089
|
+
const generatedRoot = resolve11(project, relative7(lexicalProject, options.outDir));
|
|
20513
21090
|
if (inside(generatedRoot, sourceRoot))
|
|
20514
21091
|
throw new Error("Output must not contain the application source root.");
|
|
20515
21092
|
const configInputs = new Map;
|
|
20516
|
-
const parsedConfig =
|
|
20517
|
-
...
|
|
21093
|
+
const parsedConfig = ts14.getParsedCommandLineOfConfigFile(await realpath3(configPath), {}, {
|
|
21094
|
+
...ts14.sys,
|
|
20518
21095
|
readFile(path) {
|
|
20519
21096
|
const contents = readFileSync3(path, "utf8");
|
|
20520
|
-
configInputs.set(
|
|
21097
|
+
configInputs.set(resolve11(path), digest(contents));
|
|
20521
21098
|
return contents;
|
|
20522
21099
|
},
|
|
20523
21100
|
onUnRecoverableConfigFileDiagnostic() {
|
|
@@ -20555,7 +21132,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20555
21132
|
if (!target || (kind === "worker" ? target.kind !== "jobs" : target.kind === "jobs")) {
|
|
20556
21133
|
throw new Error("Delivery host kind does not match its target.");
|
|
20557
21134
|
}
|
|
20558
|
-
const path =
|
|
21135
|
+
const path = resolve11(sourceRoot, app.source);
|
|
20559
21136
|
if (inside(generatedRoot, path) || !/\.[cm]?ts$/.test(path))
|
|
20560
21137
|
throw new Error("Hosts require application TypeScript source.");
|
|
20561
21138
|
hosts.set(app.target, { path, kind, hash: digest(await readOwned(sourceRoot, path)) });
|
|
@@ -20634,7 +21211,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20634
21211
|
for (const [name, contents] of Object.entries(generated))
|
|
20635
21212
|
await writeArtifact(stage, `generated/${name}`, contents);
|
|
20636
21213
|
{
|
|
20637
|
-
const program =
|
|
21214
|
+
const program = ts14.createProgram({
|
|
20638
21215
|
rootNames: [
|
|
20639
21216
|
...parsedConfig.fileNames.filter((path) => !inside(generatedRoot, path)),
|
|
20640
21217
|
...Object.keys(generated).map((name) => join9(stage, "generated", name))
|
|
@@ -20642,12 +21219,12 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20642
21219
|
options: { ...parsedConfig.options, rootDir: project },
|
|
20643
21220
|
...parsedConfig.projectReferences ? { projectReferences: parsedConfig.projectReferences } : {}
|
|
20644
21221
|
});
|
|
20645
|
-
const diagnostics =
|
|
20646
|
-
if (diagnostics.some((item) => item.category ===
|
|
20647
|
-
return failed(diagnostics.filter((item) => item.category ===
|
|
21222
|
+
const diagnostics = ts14.getPreEmitDiagnostics(program);
|
|
21223
|
+
if (diagnostics.some((item) => item.category === ts14.DiagnosticCategory.Error)) {
|
|
21224
|
+
return failed(diagnostics.filter((item) => item.category === ts14.DiagnosticCategory.Error).map((item) => ({
|
|
20648
21225
|
severity: "error",
|
|
20649
21226
|
code: "delivery-generated-type-error",
|
|
20650
|
-
message:
|
|
21227
|
+
message: ts14.flattenDiagnosticMessageText(item.messageText, `
|
|
20651
21228
|
`),
|
|
20652
21229
|
...item.file ? { file: item.file.fileName } : {}
|
|
20653
21230
|
})));
|
|
@@ -20682,7 +21259,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20682
21259
|
}));
|
|
20683
21260
|
const assetInputs = {};
|
|
20684
21261
|
for (const asset of assets.filter((asset) => asset.target === target.name)) {
|
|
20685
|
-
const path =
|
|
21262
|
+
const path = resolve11(sourceRoot, asset.source);
|
|
20686
21263
|
const bytes = await readOwned(sourceRoot, path);
|
|
20687
21264
|
const hash = digest(bytes);
|
|
20688
21265
|
const previousHash = snapshots.get(path);
|
|
@@ -20793,210 +21370,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
20793
21370
|
// src/index.ts
|
|
20794
21371
|
init_delivery_migration_archive2();
|
|
20795
21372
|
init_feature();
|
|
20796
|
-
|
|
20797
|
-
// src/fixes.ts
|
|
20798
|
-
import { randomUUID } from "node:crypto";
|
|
20799
|
-
import { lstat as lstat2, readFile as readFile6, realpath as realpath4, rename as rename4, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
20800
|
-
import { dirname as dirname8, isAbsolute as isAbsolute3, relative as relative8, resolve as resolve11, sep as sep8 } from "node:path";
|
|
20801
|
-
import * as ts12 from "@typescript/typescript6";
|
|
20802
|
-
async function applyDiagnosticFix(fix, options = {}) {
|
|
20803
|
-
if (!fix || typeof fix.targetFile !== "string")
|
|
20804
|
-
throw new Error("Invalid DiagnosticFix");
|
|
20805
|
-
const root = await realpath4(options.rootDir ?? process.cwd());
|
|
20806
|
-
const file = resolve11(root, fix.targetFile);
|
|
20807
|
-
const stat = await lstat2(file);
|
|
20808
|
-
const resolved = await realpath4(file);
|
|
20809
|
-
const relativePath = relative8(root, resolved);
|
|
20810
|
-
if (stat.isSymbolicLink() || !stat.isFile() || isAbsolute3(relativePath) || relativePath === ".." || relativePath.startsWith(`..${sep8}`)) {
|
|
20811
|
-
throw new Error("Fix target must be a regular file inside rootDir");
|
|
20812
|
-
}
|
|
20813
|
-
const original = await readFile6(file, "utf8");
|
|
20814
|
-
let source = parse5(file, original);
|
|
20815
|
-
let content;
|
|
20816
|
-
switch (fix.type) {
|
|
20817
|
-
case "set_command_mode": {
|
|
20818
|
-
if (fix.property !== "transaction" && fix.property !== "idempotency" || fix.value !== "required" && fix.value !== "none") {
|
|
20819
|
-
throw new Error("Command mode fix requires an explicit property and policy value");
|
|
20820
|
-
}
|
|
20821
|
-
const object = decoratorObject(findClass(source, fix.command), "Command");
|
|
20822
|
-
const current = property(object, fix.property);
|
|
20823
|
-
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
20824
|
-
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
20825
|
-
}
|
|
20826
|
-
content = replaceProperty(source, object, fix.property, ts12.factory.createStringLiteral(fix.value));
|
|
20827
|
-
break;
|
|
20828
|
-
}
|
|
20829
|
-
case "add_module_import": {
|
|
20830
|
-
if (!fix.importPath || !fix.symbol)
|
|
20831
|
-
throw new Error("Module fix requires importPath and symbol");
|
|
20832
|
-
identifier2(fix.symbol);
|
|
20833
|
-
const withImport = importSymbol(source, fix.importPath, fix.symbol);
|
|
20834
|
-
source = parse5(file, withImport);
|
|
20835
|
-
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
20836
|
-
const imports = property(object, "imports");
|
|
20837
|
-
if (imports && !ts12.isArrayLiteralExpression(imports.initializer)) {
|
|
20838
|
-
throw new Error("Module imports must be a static array");
|
|
20839
|
-
}
|
|
20840
|
-
const values = imports && ts12.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
20841
|
-
if (values.some(ts12.isSpreadElement))
|
|
20842
|
-
throw new Error("Module imports cannot contain spread elements");
|
|
20843
|
-
content = values.some((value) => ts12.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts12.factory.createArrayLiteralExpression([
|
|
20844
|
-
...values,
|
|
20845
|
-
ts12.factory.createIdentifier(fix.symbol)
|
|
20846
|
-
]));
|
|
20847
|
-
break;
|
|
20848
|
-
}
|
|
20849
|
-
case "add_command_permission": {
|
|
20850
|
-
const permission = options.permission ?? fix.permission;
|
|
20851
|
-
if (!permission?.trim()) {
|
|
20852
|
-
throw new Error("Permission fix requires an explicit permission; privileges are never inferred");
|
|
20853
|
-
}
|
|
20854
|
-
const command = findClass(source, fix.command);
|
|
20855
|
-
const object = decoratorObject(command, "Command");
|
|
20856
|
-
const current = property(object, "permission");
|
|
20857
|
-
if (current && (!ts12.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
20858
|
-
throw new Error("Command permission already exists with a different value");
|
|
20859
|
-
}
|
|
20860
|
-
content = current ? original : replaceProperty(source, object, "permission", ts12.factory.createStringLiteral(permission));
|
|
20861
|
-
break;
|
|
20862
|
-
}
|
|
20863
|
-
case "add_route_parameter_binding": {
|
|
20864
|
-
const controller = findClass(source, fix.controller);
|
|
20865
|
-
const method = unique(controller.members.filter((member) => ts12.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
|
|
20866
|
-
const parameter = unique(method.parameters.filter((candidate) => ts12.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
|
|
20867
|
-
const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
|
|
20868
|
-
if (!binding)
|
|
20869
|
-
throw new Error("Invalid route binding");
|
|
20870
|
-
const decorators = ts12.getDecorators(parameter) ?? [];
|
|
20871
|
-
if (decorators.length > 0)
|
|
20872
|
-
throw new Error("Parameter already has a decorator");
|
|
20873
|
-
const framework = unique(source.statements.filter((statement) => ts12.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts12.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
|
|
20874
|
-
if (!ts12.isImportDeclaration(framework) || !ts12.isStringLiteral(framework.moduleSpecifier)) {
|
|
20875
|
-
throw new Error("Framework import must be static");
|
|
20876
|
-
}
|
|
20877
|
-
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
20878
|
-
content = importSymbol(parse5(file, edited), framework.moduleSpecifier.text, binding);
|
|
20879
|
-
break;
|
|
20880
|
-
}
|
|
20881
|
-
default:
|
|
20882
|
-
throw new Error(`Diagnostic fix '${fix.type}' requires a manual semantic decision; no files changed`);
|
|
20883
|
-
}
|
|
20884
|
-
parse5(file, content);
|
|
20885
|
-
const result = { file, changed: content !== original, content };
|
|
20886
|
-
if (options.dryRun === false && result.changed) {
|
|
20887
|
-
const temporary = `${file}.supacloud-fix-${randomUUID()}`;
|
|
20888
|
-
try {
|
|
20889
|
-
await writeFile3(temporary, content, { encoding: "utf8", flag: "wx", mode: stat.mode });
|
|
20890
|
-
if (await readFile6(file, "utf8") !== original)
|
|
20891
|
-
throw new Error("Target changed while preparing the fix");
|
|
20892
|
-
await rename4(temporary, file);
|
|
20893
|
-
} finally {
|
|
20894
|
-
await unlink2(temporary).catch(() => {});
|
|
20895
|
-
}
|
|
20896
|
-
}
|
|
20897
|
-
return result;
|
|
20898
|
-
}
|
|
20899
|
-
function parse5(file, text) {
|
|
20900
|
-
const result = ts12.transpileModule(text, {
|
|
20901
|
-
fileName: file,
|
|
20902
|
-
reportDiagnostics: true,
|
|
20903
|
-
compilerOptions: { target: ts12.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
20904
|
-
});
|
|
20905
|
-
if (result.diagnostics?.some((item) => item.category === ts12.DiagnosticCategory.Error)) {
|
|
20906
|
-
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
20907
|
-
}
|
|
20908
|
-
return ts12.createSourceFile(file, text, ts12.ScriptTarget.Latest, true, ts12.ScriptKind.TS);
|
|
20909
|
-
}
|
|
20910
|
-
function unique(items, description) {
|
|
20911
|
-
if (items.length !== 1)
|
|
20912
|
-
throw new Error(`Expected exactly one ${description}; found ${items.length}`);
|
|
20913
|
-
return items[0];
|
|
20914
|
-
}
|
|
20915
|
-
function identifier2(value) {
|
|
20916
|
-
if (!/^[A-Za-z_$][\w$]*$/.test(value))
|
|
20917
|
-
throw new Error(`Invalid identifier '${value}'`);
|
|
20918
|
-
}
|
|
20919
|
-
function nameOf(name) {
|
|
20920
|
-
if (!name)
|
|
20921
|
-
return "";
|
|
20922
|
-
return ts12.isIdentifier(name) || ts12.isStringLiteral(name) || ts12.isNumericLiteral(name) ? name.text : "";
|
|
20923
|
-
}
|
|
20924
|
-
function property(object, key) {
|
|
20925
|
-
if (object.properties.some((item) => !ts12.isPropertyAssignment(item) || ts12.isComputedPropertyName(item.name))) {
|
|
20926
|
-
throw new Error("Fix requires explicit static object properties");
|
|
20927
|
-
}
|
|
20928
|
-
const values = object.properties.filter((item) => ts12.isPropertyAssignment(item) && nameOf(item.name) === key);
|
|
20929
|
-
if (values.length > 1)
|
|
20930
|
-
throw new Error(`Duplicate '${key}' property`);
|
|
20931
|
-
return values[0];
|
|
20932
|
-
}
|
|
20933
|
-
function stringProperty(object, key) {
|
|
20934
|
-
const value = property(object, key)?.initializer;
|
|
20935
|
-
return value && ts12.isStringLiteral(value) ? value.text : undefined;
|
|
20936
|
-
}
|
|
20937
|
-
function replaceProperty(source, object, key, value) {
|
|
20938
|
-
const previous = property(object, key);
|
|
20939
|
-
const replacement = ts12.factory.createPropertyAssignment(key, value);
|
|
20940
|
-
const properties = object.properties.map((item) => item === previous ? replacement : item);
|
|
20941
|
-
if (!previous)
|
|
20942
|
-
properties.push(replacement);
|
|
20943
|
-
const updated = ts12.factory.updateObjectLiteralExpression(object, properties);
|
|
20944
|
-
return source.text.slice(0, object.getStart(source)) + ts12.createPrinter().printNode(ts12.EmitHint.Expression, updated, source) + source.text.slice(object.end);
|
|
20945
|
-
}
|
|
20946
|
-
function findClass(source, name) {
|
|
20947
|
-
return unique(source.statements.filter((statement) => ts12.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
20948
|
-
}
|
|
20949
|
-
function decoratorObject(node, name) {
|
|
20950
|
-
const decorator = unique((ts12.getDecorators(node) ?? []).filter((item) => ts12.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
|
|
20951
|
-
const argument = ts12.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
|
|
20952
|
-
if (!argument || !ts12.isObjectLiteralExpression(argument))
|
|
20953
|
-
throw new Error(`@${name} requires a static object`);
|
|
20954
|
-
return argument;
|
|
20955
|
-
}
|
|
20956
|
-
function moduleObjects(source) {
|
|
20957
|
-
const result = [];
|
|
20958
|
-
for (const statement of source.statements) {
|
|
20959
|
-
if (ts12.isClassDeclaration(statement) && (ts12.getDecorators(statement) ?? []).some((item) => ts12.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
|
|
20960
|
-
result.push(decoratorObject(statement, "Module"));
|
|
20961
|
-
}
|
|
20962
|
-
if (ts12.isVariableStatement(statement)) {
|
|
20963
|
-
for (const declaration of statement.declarationList.declarations) {
|
|
20964
|
-
const call = declaration.initializer;
|
|
20965
|
-
if (call && ts12.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts12.isObjectLiteralExpression(call.arguments[0])) {
|
|
20966
|
-
result.push(call.arguments[0]);
|
|
20967
|
-
}
|
|
20968
|
-
}
|
|
20969
|
-
}
|
|
20970
|
-
}
|
|
20971
|
-
return result;
|
|
20972
|
-
}
|
|
20973
|
-
function importSymbol(source, path, symbol) {
|
|
20974
|
-
identifier2(symbol);
|
|
20975
|
-
const current = resolve11(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
|
|
20976
|
-
const target = resolve11(dirname8(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
20977
|
-
if (current === target)
|
|
20978
|
-
return source.text;
|
|
20979
|
-
const matches = source.statements.filter((item) => ts12.isImportDeclaration(item) && ts12.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
|
|
20980
|
-
if (matches.length > 1)
|
|
20981
|
-
throw new Error(`Ambiguous imports from '${path}'`);
|
|
20982
|
-
const match = matches[0];
|
|
20983
|
-
if (match && ts12.isImportDeclaration(match) && match.importClause?.namedBindings && ts12.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
|
|
20984
|
-
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
20985
|
-
return source.text;
|
|
20986
|
-
const bindings = match.importClause.namedBindings;
|
|
20987
|
-
const updated = ts12.factory.updateNamedImports(bindings, [
|
|
20988
|
-
...bindings.elements,
|
|
20989
|
-
ts12.factory.createImportSpecifier(false, undefined, ts12.factory.createIdentifier(symbol))
|
|
20990
|
-
]);
|
|
20991
|
-
return source.text.slice(0, bindings.getStart(source)) + ts12.createPrinter().printNode(ts12.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
|
|
20992
|
-
}
|
|
20993
|
-
if (match)
|
|
20994
|
-
throw new Error(`Import from '${path}' is not a named value import`);
|
|
20995
|
-
return `import { ${symbol} } from ${JSON.stringify(path)};
|
|
20996
|
-
${source.text}`;
|
|
20997
|
-
}
|
|
20998
|
-
|
|
20999
|
-
// src/index.ts
|
|
21373
|
+
init_fixes();
|
|
21000
21374
|
init_execution_context();
|
|
21001
21375
|
init_delivery_context();
|
|
21002
21376
|
init_application_development2();
|
|
@@ -21220,12 +21594,12 @@ init_release_evidence();
|
|
|
21220
21594
|
|
|
21221
21595
|
// src/watch.ts
|
|
21222
21596
|
import { existsSync as existsSync4, watch } from "node:fs";
|
|
21223
|
-
import { dirname as dirname9, relative as relative10, resolve as
|
|
21597
|
+
import { dirname as dirname9, relative as relative10, resolve as resolve14, sep as sep10 } from "node:path";
|
|
21224
21598
|
|
|
21225
21599
|
// src/incremental.ts
|
|
21226
|
-
import { createHash as
|
|
21600
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
21227
21601
|
import { access as access3, readdir as readdir3, readFile as readFile7 } from "node:fs/promises";
|
|
21228
|
-
import { isAbsolute as isAbsolute4, relative as relative9, resolve as
|
|
21602
|
+
import { isAbsolute as isAbsolute4, relative as relative9, resolve as resolve13, sep as sep9 } from "node:path";
|
|
21229
21603
|
init_graphql_inputs();
|
|
21230
21604
|
function createDependencyGraphCache() {
|
|
21231
21605
|
return {
|
|
@@ -21306,11 +21680,11 @@ async function readSourceBytes(path) {
|
|
|
21306
21680
|
return readFile7(path);
|
|
21307
21681
|
}
|
|
21308
21682
|
async function updateSnapshot(previous, options, changedPaths) {
|
|
21309
|
-
const rootDir =
|
|
21310
|
-
const outDir =
|
|
21683
|
+
const rootDir = resolve13(options.rootDir);
|
|
21684
|
+
const outDir = resolve13(options.outDir);
|
|
21311
21685
|
const files = { ...previous.files };
|
|
21312
21686
|
await Promise.all(changedPaths.map(async (changedPath) => {
|
|
21313
|
-
const absolutePath = isAbsolute4(changedPath) ?
|
|
21687
|
+
const absolutePath = isAbsolute4(changedPath) ? resolve13(changedPath) : resolve13(rootDir, changedPath);
|
|
21314
21688
|
const relativeChangedPath = relative9(rootDir, absolutePath);
|
|
21315
21689
|
if (relativeChangedPath === ".." || relativeChangedPath.startsWith(`..${sep9}`))
|
|
21316
21690
|
return;
|
|
@@ -21320,7 +21694,7 @@ async function updateSnapshot(previous, options, changedPaths) {
|
|
|
21320
21694
|
try {
|
|
21321
21695
|
await access3(absolutePath);
|
|
21322
21696
|
const content = await readSourceBytes(absolutePath);
|
|
21323
|
-
files[relativePath] =
|
|
21697
|
+
files[relativePath] = createHash9("sha256").update(content).digest("hex");
|
|
21324
21698
|
} catch {
|
|
21325
21699
|
delete files[relativePath];
|
|
21326
21700
|
}
|
|
@@ -21328,14 +21702,14 @@ async function updateSnapshot(previous, options, changedPaths) {
|
|
|
21328
21702
|
return { files, optionsKey: optionsKeyOf(options) };
|
|
21329
21703
|
}
|
|
21330
21704
|
async function createSnapshot(options) {
|
|
21331
|
-
const rootDir =
|
|
21332
|
-
const outDir =
|
|
21705
|
+
const rootDir = resolve13(options.rootDir);
|
|
21706
|
+
const outDir = resolve13(options.outDir);
|
|
21333
21707
|
const paths = await listSourceFiles(rootDir, outDir);
|
|
21334
21708
|
const files = {};
|
|
21335
21709
|
const entries = await Promise.all(paths.map(async (path) => {
|
|
21336
21710
|
const content = await readSourceBytes(path);
|
|
21337
21711
|
const key = relative9(rootDir, path).split(sep9).join("/");
|
|
21338
|
-
return [key,
|
|
21712
|
+
return [key, createHash9("sha256").update(content).digest("hex")];
|
|
21339
21713
|
}));
|
|
21340
21714
|
for (const [key, hash] of entries)
|
|
21341
21715
|
files[key] = hash;
|
|
@@ -21343,7 +21717,7 @@ async function createSnapshot(options) {
|
|
|
21343
21717
|
const key = relative9(rootDir, path).split(sep9).join("/");
|
|
21344
21718
|
try {
|
|
21345
21719
|
const content = await readSourceBytes(path);
|
|
21346
|
-
files[key] =
|
|
21720
|
+
files[key] = createHash9("sha256").update(content).digest("hex");
|
|
21347
21721
|
} catch {
|
|
21348
21722
|
files[key] = "missing";
|
|
21349
21723
|
}
|
|
@@ -21352,8 +21726,8 @@ async function createSnapshot(options) {
|
|
|
21352
21726
|
}
|
|
21353
21727
|
function optionsKeyOf(options) {
|
|
21354
21728
|
return JSON.stringify({
|
|
21355
|
-
rootDir:
|
|
21356
|
-
outDir:
|
|
21729
|
+
rootDir: resolve13(options.rootDir),
|
|
21730
|
+
outDir: resolve13(options.outDir),
|
|
21357
21731
|
include: options.include,
|
|
21358
21732
|
strict: options.strict,
|
|
21359
21733
|
writeOnError: options.writeOnError,
|
|
@@ -21377,7 +21751,7 @@ async function listSourceFiles(rootDir, outDir) {
|
|
|
21377
21751
|
const result = [];
|
|
21378
21752
|
const visit = async (directory) => {
|
|
21379
21753
|
for (const entry of await readdir3(directory, { withFileTypes: true })) {
|
|
21380
|
-
const path =
|
|
21754
|
+
const path = resolve13(directory, entry.name);
|
|
21381
21755
|
if (entry.isDirectory()) {
|
|
21382
21756
|
if (entry.name === "node_modules" || entry.name === ".git" || path === outDir)
|
|
21383
21757
|
continue;
|
|
@@ -21512,8 +21886,8 @@ function isCompilerConfigurationPath(rootDir, changedPath) {
|
|
|
21512
21886
|
].includes(relativePath) || /^tsconfig\.[^/]+\.json$/.test(relativePath);
|
|
21513
21887
|
}
|
|
21514
21888
|
function watchProject(options) {
|
|
21515
|
-
const rootDir =
|
|
21516
|
-
const outDir =
|
|
21889
|
+
const rootDir = resolve14(options.rootDir);
|
|
21890
|
+
const outDir = resolve14(options.outDir);
|
|
21517
21891
|
const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
21518
21892
|
let timer;
|
|
21519
21893
|
let closed = false;
|
|
@@ -21523,7 +21897,7 @@ function watchProject(options) {
|
|
|
21523
21897
|
const pendingPaths = new Set;
|
|
21524
21898
|
let watcher;
|
|
21525
21899
|
let schemaWatcher;
|
|
21526
|
-
const schemaPath = options.graphql ?
|
|
21900
|
+
const schemaPath = options.graphql ? resolve14(rootDir, options.graphql.schema) : undefined;
|
|
21527
21901
|
const incremental = createIncrementalCompiler();
|
|
21528
21902
|
let initialEvent;
|
|
21529
21903
|
let resolveReady = () => {
|
|
@@ -21633,7 +22007,7 @@ function watchProject(options) {
|
|
|
21633
22007
|
watcher = watch(rootDir, { recursive: true }, (_eventType, filename) => {
|
|
21634
22008
|
if (!filename)
|
|
21635
22009
|
return schedule();
|
|
21636
|
-
const changedPath =
|
|
22010
|
+
const changedPath = resolve14(rootDir, filename.toString());
|
|
21637
22011
|
const relativePath = relative10(outDir, changedPath);
|
|
21638
22012
|
if (!relativePath.startsWith("..") && relativePath !== "")
|
|
21639
22013
|
return;
|
|
@@ -21646,7 +22020,7 @@ function watchProject(options) {
|
|
|
21646
22020
|
while (!existsSync4(directory) && dirname9(directory) !== directory)
|
|
21647
22021
|
directory = dirname9(directory);
|
|
21648
22022
|
schemaWatcher = watch(directory, { recursive: true }, (_eventType, filename) => {
|
|
21649
|
-
if (!filename ||
|
|
22023
|
+
if (!filename || resolve14(directory, filename.toString()) === schemaPath)
|
|
21650
22024
|
schedule(schemaPath);
|
|
21651
22025
|
});
|
|
21652
22026
|
}
|
|
@@ -21669,13 +22043,13 @@ function watchProject(options) {
|
|
|
21669
22043
|
}
|
|
21670
22044
|
// src/migrations.ts
|
|
21671
22045
|
import { rename as rename5, readFile as readFile9, writeFile as writeFile4, rm as rm3 } from "node:fs/promises";
|
|
21672
|
-
import { relative as relative11, resolve as
|
|
21673
|
-
import * as
|
|
22046
|
+
import { relative as relative11, resolve as resolve16 } from "node:path";
|
|
22047
|
+
import * as ts16 from "@typescript/typescript6";
|
|
21674
22048
|
|
|
21675
22049
|
// src/migration-policy.ts
|
|
21676
22050
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
21677
22051
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
21678
|
-
import { resolve as
|
|
22052
|
+
import { resolve as resolve15 } from "node:path";
|
|
21679
22053
|
var cachedCompilerVersion;
|
|
21680
22054
|
function compilerVersion() {
|
|
21681
22055
|
if (cachedCompilerVersion !== undefined)
|
|
@@ -21689,9 +22063,9 @@ function compilerVersion() {
|
|
|
21689
22063
|
}
|
|
21690
22064
|
function migrationDependencies() {
|
|
21691
22065
|
return {
|
|
21692
|
-
"@supacloud/app": "0.
|
|
22066
|
+
"@supacloud/app": "0.21.0",
|
|
21693
22067
|
"@supacloud/compiler": compilerVersion(),
|
|
21694
|
-
"@supacloud/elysia": "0.
|
|
22068
|
+
"@supacloud/elysia": "0.23.0",
|
|
21695
22069
|
elysia: "2.0.0-beta.19",
|
|
21696
22070
|
typescript: "7.0.2"
|
|
21697
22071
|
};
|
|
@@ -21700,7 +22074,7 @@ async function checkMigrationDependencies(rootDir) {
|
|
|
21700
22074
|
const problems = [];
|
|
21701
22075
|
for (const [name, expected] of Object.entries(migrationDependencies())) {
|
|
21702
22076
|
try {
|
|
21703
|
-
const manifest = JSON.parse(await readFile8(
|
|
22077
|
+
const manifest = JSON.parse(await readFile8(resolve15(rootDir, "node_modules", name, "package.json"), "utf8"));
|
|
21704
22078
|
if (!manifest || typeof manifest !== "object" || !("name" in manifest) || manifest.name !== name || !("version" in manifest) || manifest.version !== expected) {
|
|
21705
22079
|
problems.push(`${name}: requires tested installed version ${expected}`);
|
|
21706
22080
|
}
|
|
@@ -21714,29 +22088,29 @@ async function checkMigrationDependencies(rootDir) {
|
|
|
21714
22088
|
// src/migrations.ts
|
|
21715
22089
|
var ROUTE_DECORATORS2 = new Set(["Get", "Post", "Put", "Patch", "Delete", "Head", "Options"]);
|
|
21716
22090
|
var MIGRATION_COMPILER_OPTIONS = {
|
|
21717
|
-
target:
|
|
21718
|
-
module:
|
|
21719
|
-
moduleResolution:
|
|
22091
|
+
target: ts16.ScriptTarget.ES2022,
|
|
22092
|
+
module: ts16.ModuleKind.ESNext,
|
|
22093
|
+
moduleResolution: ts16.ModuleResolutionKind.Bundler,
|
|
21720
22094
|
noEmit: true,
|
|
21721
22095
|
skipLibCheck: true
|
|
21722
22096
|
};
|
|
21723
22097
|
function migrationCompilerOptions(rootDir) {
|
|
21724
22098
|
if (!rootDir)
|
|
21725
22099
|
return MIGRATION_COMPILER_OPTIONS;
|
|
21726
|
-
const configPath =
|
|
22100
|
+
const configPath = ts16.findConfigFile(rootDir, ts16.sys.fileExists);
|
|
21727
22101
|
if (!configPath)
|
|
21728
22102
|
return MIGRATION_COMPILER_OPTIONS;
|
|
21729
22103
|
const configHost = {
|
|
21730
|
-
...
|
|
22104
|
+
...ts16.sys,
|
|
21731
22105
|
onUnRecoverableConfigFileDiagnostic: (_diagnostic) => {}
|
|
21732
22106
|
};
|
|
21733
|
-
const parsed =
|
|
22107
|
+
const parsed = ts16.getParsedCommandLineOfConfigFile(configPath, {}, configHost);
|
|
21734
22108
|
if (!parsed || parsed.errors.length > 0)
|
|
21735
22109
|
return MIGRATION_COMPILER_OPTIONS;
|
|
21736
22110
|
return { ...parsed.options, noEmit: true, skipLibCheck: true };
|
|
21737
22111
|
}
|
|
21738
22112
|
function propertyName2(property) {
|
|
21739
|
-
if (
|
|
22113
|
+
if (ts16.isIdentifier(property) || ts16.isStringLiteral(property) || ts16.isNumericLiteral(property))
|
|
21740
22114
|
return property.text;
|
|
21741
22115
|
return;
|
|
21742
22116
|
}
|
|
@@ -21746,7 +22120,7 @@ function lineOf2(sourceFile, node) {
|
|
|
21746
22120
|
function resolveSymbol(symbol, checker) {
|
|
21747
22121
|
if (!symbol)
|
|
21748
22122
|
return;
|
|
21749
|
-
for (let guard = 0;guard < 4 && (symbol.flags &
|
|
22123
|
+
for (let guard = 0;guard < 4 && (symbol.flags & ts16.SymbolFlags.Alias) !== 0; guard += 1) {
|
|
21750
22124
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
21751
22125
|
if (aliased === symbol)
|
|
21752
22126
|
break;
|
|
@@ -21755,12 +22129,12 @@ function resolveSymbol(symbol, checker) {
|
|
|
21755
22129
|
return symbol;
|
|
21756
22130
|
}
|
|
21757
22131
|
function symbolForExpression(expression, checker) {
|
|
21758
|
-
const location =
|
|
22132
|
+
const location = ts16.isIdentifier(expression) ? expression : ts16.isPropertyAccessExpression(expression) ? expression.name : ts16.isElementAccessExpression(expression) && expression.argumentExpression && ts16.isStringLiteral(expression.argumentExpression) ? expression : undefined;
|
|
21759
22133
|
return location ? resolveSymbol(checker.getSymbolAtLocation(location), checker) : undefined;
|
|
21760
22134
|
}
|
|
21761
22135
|
function unwrapExpression(expression) {
|
|
21762
22136
|
let current = expression;
|
|
21763
|
-
while (
|
|
22137
|
+
while (ts16.isAsExpression(current) || ts16.isSatisfiesExpression(current) || ts16.isParenthesizedExpression(current) || ts16.isTypeAssertionExpression(current)) {
|
|
21764
22138
|
current = current.expression;
|
|
21765
22139
|
}
|
|
21766
22140
|
return current;
|
|
@@ -21775,7 +22149,7 @@ function isRouteDecoratorCall(node, checker) {
|
|
|
21775
22149
|
if (node.arguments.length < 2)
|
|
21776
22150
|
return false;
|
|
21777
22151
|
const name = node.expression.getText(node.getSourceFile());
|
|
21778
|
-
if (
|
|
22152
|
+
if (ts16.isIdentifier(node.expression) && ROUTE_DECORATORS2.has(node.expression.text))
|
|
21779
22153
|
return true;
|
|
21780
22154
|
if (ROUTE_DECORATORS2.has(name))
|
|
21781
22155
|
return true;
|
|
@@ -21789,14 +22163,14 @@ function resolveStaticObjectLiteral2(input, checker, seen = new Set) {
|
|
|
21789
22163
|
if (seen.has(expression))
|
|
21790
22164
|
return;
|
|
21791
22165
|
seen.add(expression);
|
|
21792
|
-
if (
|
|
22166
|
+
if (ts16.isObjectLiteralExpression(expression))
|
|
21793
22167
|
return expression;
|
|
21794
|
-
if (
|
|
22168
|
+
if (ts16.isCallExpression(expression) && isDefineRouteContractCall(expression, checker)) {
|
|
21795
22169
|
return resolveStaticObjectLiteral2(expression.arguments[0], checker, seen);
|
|
21796
22170
|
}
|
|
21797
22171
|
const symbol = symbolForExpression(expression, checker);
|
|
21798
22172
|
for (const declaration of symbol?.declarations ?? []) {
|
|
21799
|
-
if (
|
|
22173
|
+
if (ts16.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
21800
22174
|
const resolved = resolveStaticObjectLiteral2(declaration.initializer, checker, seen);
|
|
21801
22175
|
if (resolved)
|
|
21802
22176
|
return resolved;
|
|
@@ -21810,25 +22184,25 @@ function displayFile(rootDir, fileName) {
|
|
|
21810
22184
|
}
|
|
21811
22185
|
function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
21812
22186
|
const compilerOptions = migrationCompilerOptions(rootDir);
|
|
21813
|
-
const host =
|
|
22187
|
+
const host = ts16.createCompilerHost(compilerOptions);
|
|
21814
22188
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
21815
22189
|
const fileExists = host.fileExists.bind(host);
|
|
21816
22190
|
const readFile = host.readFile.bind(host);
|
|
21817
22191
|
const currentDirectory = host.getCurrentDirectory.bind(host);
|
|
21818
|
-
host.fileExists = (fileName) => sourceOverrides.has(
|
|
21819
|
-
host.readFile = (fileName) => sourceOverrides.get(
|
|
22192
|
+
host.fileExists = (fileName) => sourceOverrides.has(resolve16(fileName)) || fileExists(fileName);
|
|
22193
|
+
host.readFile = (fileName) => sourceOverrides.get(resolve16(fileName)) ?? readFile(fileName);
|
|
21820
22194
|
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
21821
|
-
const source = sourceOverrides.get(
|
|
21822
|
-
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) :
|
|
22195
|
+
const source = sourceOverrides.get(resolve16(fileName));
|
|
22196
|
+
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts16.createSourceFile(fileName, source, languageVersion, true);
|
|
21823
22197
|
};
|
|
21824
22198
|
host.getCurrentDirectory = () => rootDir ?? currentDirectory();
|
|
21825
|
-
return
|
|
22199
|
+
return ts16.createProgram(fileNames, compilerOptions, host);
|
|
21826
22200
|
}
|
|
21827
22201
|
function routeResponseProperties(object) {
|
|
21828
|
-
const responseProperties = object.properties.filter((property) =>
|
|
22202
|
+
const responseProperties = object.properties.filter((property) => ts16.isPropertyAssignment(property) && propertyName2(property.name) === "response");
|
|
21829
22203
|
return {
|
|
21830
22204
|
response: responseProperties[0],
|
|
21831
|
-
hasResponses: object.properties.some((property) => (
|
|
22205
|
+
hasResponses: object.properties.some((property) => (ts16.isPropertyAssignment(property) || ts16.isShorthandPropertyAssignment(property)) && propertyName2(property.name) === "responses"),
|
|
21832
22206
|
duplicateResponse: responseProperties.length > 1
|
|
21833
22207
|
};
|
|
21834
22208
|
}
|
|
@@ -21844,15 +22218,15 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
21844
22218
|
issues.push(issue);
|
|
21845
22219
|
};
|
|
21846
22220
|
for (const sourceFile of sourceFiles) {
|
|
21847
|
-
const sourcePath =
|
|
22221
|
+
const sourcePath = resolve16(sourceFile.fileName);
|
|
21848
22222
|
if (!includedFiles.has(sourcePath))
|
|
21849
22223
|
continue;
|
|
21850
22224
|
const visit = (node) => {
|
|
21851
|
-
if (
|
|
22225
|
+
if (ts16.isCallExpression(node) && isRouteDecoratorCall(node, checker)) {
|
|
21852
22226
|
const options = node.arguments[1];
|
|
21853
22227
|
const object = options && resolveStaticObjectLiteral2(options, checker);
|
|
21854
22228
|
if (object) {
|
|
21855
|
-
const objectPath =
|
|
22229
|
+
const objectPath = resolve16(object.getSourceFile().fileName);
|
|
21856
22230
|
const properties = routeResponseProperties(object);
|
|
21857
22231
|
if (properties.response) {
|
|
21858
22232
|
if (!includedFiles.has(objectPath)) {
|
|
@@ -21868,7 +22242,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
21868
22242
|
}
|
|
21869
22243
|
}
|
|
21870
22244
|
}
|
|
21871
|
-
|
|
22245
|
+
ts16.forEachChild(node, visit);
|
|
21872
22246
|
};
|
|
21873
22247
|
visit(sourceFile);
|
|
21874
22248
|
}
|
|
@@ -21895,13 +22269,13 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
21895
22269
|
line: lineOf2(sourceFile, response)
|
|
21896
22270
|
});
|
|
21897
22271
|
} else {
|
|
21898
|
-
const replacements = replacementsByFile.get(
|
|
22272
|
+
const replacements = replacementsByFile.get(resolve16(sourceFile.fileName)) ?? [];
|
|
21899
22273
|
replacements.push({
|
|
21900
22274
|
start: response.getStart(sourceFile),
|
|
21901
22275
|
end: response.getEnd(),
|
|
21902
22276
|
text: `responses: { 200: ${response.initializer.getText(sourceFile)} }`
|
|
21903
22277
|
});
|
|
21904
|
-
replacementsByFile.set(
|
|
22278
|
+
replacementsByFile.set(resolve16(sourceFile.fileName), replacements);
|
|
21905
22279
|
}
|
|
21906
22280
|
}
|
|
21907
22281
|
return { replacementsByFile, issues };
|
|
@@ -21914,7 +22288,7 @@ function applyReplacements(source, replacements) {
|
|
|
21914
22288
|
return content;
|
|
21915
22289
|
}
|
|
21916
22290
|
function migrateRouteResponse(source, fileName) {
|
|
21917
|
-
const absoluteFile =
|
|
22291
|
+
const absoluteFile = resolve16(fileName);
|
|
21918
22292
|
const sourceOverrides = new Map([[absoluteFile, source]]);
|
|
21919
22293
|
const program = createMigrationProgram([absoluteFile], sourceOverrides);
|
|
21920
22294
|
const sourceFile = program.getSourceFile(absoluteFile);
|
|
@@ -21930,7 +22304,7 @@ function migrateRouteResponse(source, fileName) {
|
|
|
21930
22304
|
}]
|
|
21931
22305
|
};
|
|
21932
22306
|
}
|
|
21933
|
-
const plan = planRouteResponseMigration([sourceFile], program.getTypeChecker(),
|
|
22307
|
+
const plan = planRouteResponseMigration([sourceFile], program.getTypeChecker(), resolve16("."), new Set([absoluteFile]));
|
|
21934
22308
|
const replacements = plan.replacementsByFile.get(absoluteFile) ?? [];
|
|
21935
22309
|
return {
|
|
21936
22310
|
changed: replacements.length > 0,
|
|
@@ -21940,7 +22314,7 @@ function migrateRouteResponse(source, fileName) {
|
|
|
21940
22314
|
};
|
|
21941
22315
|
}
|
|
21942
22316
|
function migrateRouteResponseProject(files, rootDir, sourceByPath) {
|
|
21943
|
-
const absoluteFiles = files.map((file) =>
|
|
22317
|
+
const absoluteFiles = files.map((file) => resolve16(file));
|
|
21944
22318
|
const program = createMigrationProgram(absoluteFiles, sourceByPath, rootDir);
|
|
21945
22319
|
const sourceFiles = absoluteFiles.map((file) => program.getSourceFile(file)).filter((file) => file !== undefined);
|
|
21946
22320
|
const plan = planRouteResponseMigration(sourceFiles, program.getTypeChecker(), rootDir, new Set(absoluteFiles));
|
|
@@ -21953,11 +22327,11 @@ function migrateRouteResponseProject(files, rootDir, sourceByPath) {
|
|
|
21953
22327
|
changed: replacements.length > 0,
|
|
21954
22328
|
content: applyReplacements(source, replacements),
|
|
21955
22329
|
replacements: replacements.length,
|
|
21956
|
-
issues: plan.issues.filter((issue) =>
|
|
22330
|
+
issues: plan.issues.filter((issue) => resolve16(rootDir, issue.file) === file)
|
|
21957
22331
|
});
|
|
21958
22332
|
}
|
|
21959
22333
|
for (const issue of plan.issues) {
|
|
21960
|
-
const path =
|
|
22334
|
+
const path = resolve16(rootDir, issue.file);
|
|
21961
22335
|
if (!results.has(path) && sourceByPath.has(path)) {
|
|
21962
22336
|
results.set(path, {
|
|
21963
22337
|
changed: false,
|
|
@@ -21976,6 +22350,13 @@ var SUPACLOUD_MIGRATIONS = [
|
|
|
21976
22350
|
to: "0.12.0",
|
|
21977
22351
|
description: "Replace deprecated route response schemas with explicit HTTP status maps.",
|
|
21978
22352
|
apply: migrateRouteResponse
|
|
22353
|
+
},
|
|
22354
|
+
{
|
|
22355
|
+
id: "http-provider-entrypoint",
|
|
22356
|
+
from: "0.12.0",
|
|
22357
|
+
to: "0.13.0",
|
|
22358
|
+
description: "Move provider-only withInterceptors imports to the shared HTTP feature entry; reject ambiguous uses.",
|
|
22359
|
+
apply: migrateHttpProviderImports
|
|
21979
22360
|
}
|
|
21980
22361
|
];
|
|
21981
22362
|
async function writeAtomically(path, content) {
|
|
@@ -21988,7 +22369,7 @@ async function writeAtomically(path, content) {
|
|
|
21988
22369
|
}
|
|
21989
22370
|
}
|
|
21990
22371
|
async function migrateProject(options) {
|
|
21991
|
-
const rootDir =
|
|
22372
|
+
const rootDir = resolve16(options.rootDir);
|
|
21992
22373
|
let migrations = SUPACLOUD_MIGRATIONS;
|
|
21993
22374
|
const preflightIssues = [];
|
|
21994
22375
|
if (options.fromVersion !== undefined || options.toVersion !== undefined) {
|
|
@@ -22028,7 +22409,7 @@ async function migrateProject(options) {
|
|
|
22028
22409
|
}
|
|
22029
22410
|
}
|
|
22030
22411
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
22031
|
-
const files =
|
|
22412
|
+
const files = ts16.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist", "generated"], include).sort();
|
|
22032
22413
|
const results = [];
|
|
22033
22414
|
const issues = [];
|
|
22034
22415
|
const pendingWrites = new Map;
|
|
@@ -22044,7 +22425,7 @@ async function migrateProject(options) {
|
|
|
22044
22425
|
}
|
|
22045
22426
|
};
|
|
22046
22427
|
for (const filePath of files) {
|
|
22047
|
-
sourceByPath.set(
|
|
22428
|
+
sourceByPath.set(resolve16(filePath), await readFile9(filePath, "utf8"));
|
|
22048
22429
|
}
|
|
22049
22430
|
const originalSources = new Map(sourceByPath);
|
|
22050
22431
|
const writtenFiles = new Set;
|
|
@@ -22053,7 +22434,7 @@ async function migrateProject(options) {
|
|
|
22053
22434
|
if (projectResults)
|
|
22054
22435
|
appendIssues(projectResults.issues);
|
|
22055
22436
|
for (const filePath of files) {
|
|
22056
|
-
const absoluteFile =
|
|
22437
|
+
const absoluteFile = resolve16(filePath);
|
|
22057
22438
|
const file = relative11(rootDir, absoluteFile) || absoluteFile;
|
|
22058
22439
|
const before = sourceByPath.get(absoluteFile);
|
|
22059
22440
|
if (before === undefined)
|
|
@@ -22112,13 +22493,13 @@ async function migrateProject(options) {
|
|
|
22112
22493
|
};
|
|
22113
22494
|
}
|
|
22114
22495
|
// src/migration-assess.ts
|
|
22115
|
-
import { createHash as
|
|
22496
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
22116
22497
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
22117
|
-
import { join as join10, resolve as
|
|
22498
|
+
import { join as join10, resolve as resolve18 } from "node:path";
|
|
22118
22499
|
|
|
22119
22500
|
// src/openapi-tools.ts
|
|
22120
22501
|
import { mkdir as mkdir4, readFile as readFile10, rename as rename6, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
|
|
22121
|
-
import { dirname as dirname10, resolve as
|
|
22502
|
+
import { dirname as dirname10, resolve as resolve17 } from "node:path";
|
|
22122
22503
|
import { pathToFileURL } from "node:url";
|
|
22123
22504
|
|
|
22124
22505
|
class OpenApiDocumentError extends Error {
|
|
@@ -22509,7 +22890,7 @@ function serializeOpenApiJson(document, space = 2) {
|
|
|
22509
22890
|
}
|
|
22510
22891
|
async function readOpenApiJson(path) {
|
|
22511
22892
|
try {
|
|
22512
|
-
const value = JSON.parse(await readFile10(
|
|
22893
|
+
const value = JSON.parse(await readFile10(resolve17(path), "utf8"));
|
|
22513
22894
|
return parseOpenApiDocument(value);
|
|
22514
22895
|
} catch (error) {
|
|
22515
22896
|
if (error instanceof OpenApiDocumentError)
|
|
@@ -22518,7 +22899,7 @@ async function readOpenApiJson(path) {
|
|
|
22518
22899
|
}
|
|
22519
22900
|
}
|
|
22520
22901
|
async function writeOpenApiJson(document, outputPath, space = 2) {
|
|
22521
|
-
const path =
|
|
22902
|
+
const path = resolve17(outputPath);
|
|
22522
22903
|
const content = serializeOpenApiJson(document, space);
|
|
22523
22904
|
await mkdir4(dirname10(path), { recursive: true });
|
|
22524
22905
|
try {
|
|
@@ -22539,7 +22920,7 @@ async function writeOpenApiJson(document, outputPath, space = 2) {
|
|
|
22539
22920
|
}
|
|
22540
22921
|
async function loadGeneratedOpenApiDocument(modulePath) {
|
|
22541
22922
|
try {
|
|
22542
|
-
const moduleUrl = pathToFileURL(
|
|
22923
|
+
const moduleUrl = pathToFileURL(resolve17(modulePath));
|
|
22543
22924
|
moduleUrl.searchParams.set("supacloud-openapi-export", "1");
|
|
22544
22925
|
const loaded = await import(moduleUrl.href);
|
|
22545
22926
|
if (!isRecord(loaded))
|
|
@@ -22636,17 +23017,17 @@ function arrayLength(value) {
|
|
|
22636
23017
|
return Array.isArray(value) ? value.length : undefined;
|
|
22637
23018
|
}
|
|
22638
23019
|
async function sha256(path) {
|
|
22639
|
-
return
|
|
23020
|
+
return createHash10("sha256").update(await readFile11(path)).digest("hex");
|
|
22640
23021
|
}
|
|
22641
23022
|
function overallStatus(findings) {
|
|
22642
23023
|
return findings.reduce((current, finding) => STATUS_PRIORITY[finding.status] > STATUS_PRIORITY[current] ? finding.status : current, "compatible");
|
|
22643
23024
|
}
|
|
22644
23025
|
async function assessMigration(options) {
|
|
22645
|
-
const projectDir =
|
|
23026
|
+
const projectDir = resolve18(options.projectDir);
|
|
22646
23027
|
const compile = {
|
|
22647
23028
|
...options.compile,
|
|
22648
|
-
rootDir:
|
|
22649
|
-
outDir:
|
|
23029
|
+
rootDir: resolve18(options.compile.rootDir),
|
|
23030
|
+
outDir: resolve18(options.compile.outDir)
|
|
22650
23031
|
};
|
|
22651
23032
|
const findings = [];
|
|
22652
23033
|
const dependencyProblems = await checkMigrationDependencies(projectDir);
|
|
@@ -22726,8 +23107,8 @@ async function assessMigration(options) {
|
|
|
22726
23107
|
}
|
|
22727
23108
|
let openApi;
|
|
22728
23109
|
if (options.baselineOpenApiPath && options.currentOpenApiPath) {
|
|
22729
|
-
const baselinePath =
|
|
22730
|
-
const currentPath =
|
|
23110
|
+
const baselinePath = resolve18(projectDir, options.baselineOpenApiPath);
|
|
23111
|
+
const currentPath = resolve18(projectDir, options.currentOpenApiPath);
|
|
22731
23112
|
try {
|
|
22732
23113
|
const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
|
|
22733
23114
|
openApi = {
|
|
@@ -22816,7 +23197,7 @@ init_validate();
|
|
|
22816
23197
|
// src/config.ts
|
|
22817
23198
|
init_graphql_options();
|
|
22818
23199
|
import { existsSync as existsSync5 } from "node:fs";
|
|
22819
|
-
import { join as join11, resolve as
|
|
23200
|
+
import { join as join11, resolve as resolve19 } from "node:path";
|
|
22820
23201
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
22821
23202
|
var DEFAULT_SUPACLOUD_CONFIG = {
|
|
22822
23203
|
graphql: false,
|
|
@@ -22909,8 +23290,8 @@ function validateGovernanceConfig(config) {
|
|
|
22909
23290
|
function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
|
|
22910
23291
|
const resolved = defineSupacloudConfig(config);
|
|
22911
23292
|
return {
|
|
22912
|
-
rootDir:
|
|
22913
|
-
outDir:
|
|
23293
|
+
rootDir: resolve19(cwd, resolved.root ?? DEFAULT_SUPACLOUD_CONFIG.root),
|
|
23294
|
+
outDir: resolve19(cwd, resolved.outDir ?? DEFAULT_SUPACLOUD_CONFIG.outDir),
|
|
22914
23295
|
include: resolved.include ?? [...DEFAULT_SUPACLOUD_CONFIG.include],
|
|
22915
23296
|
strict: resolved.strict ?? DEFAULT_SUPACLOUD_CONFIG.strict,
|
|
22916
23297
|
requireRouteContracts: resolved.requireRouteContracts ?? DEFAULT_SUPACLOUD_CONFIG.requireRouteContracts,
|
|
@@ -22928,7 +23309,7 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
|
|
|
22928
23309
|
treeShakeUnusedProviders: resolved.treeShakeUnusedProviders ?? DEFAULT_SUPACLOUD_CONFIG.treeShakeUnusedProviders,
|
|
22929
23310
|
graphql: resolved.graphql ? {
|
|
22930
23311
|
...resolved.graphql,
|
|
22931
|
-
schema:
|
|
23312
|
+
schema: resolve19(cwd, resolved.graphql.schema)
|
|
22932
23313
|
} : undefined
|
|
22933
23314
|
};
|
|
22934
23315
|
}
|