@supacloud/compiler 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/cli.js +606 -376
- package/dist/diagnostics.js +4 -2
- package/dist/fixtures/runtime-source.d.ts +2 -2
- package/dist/index.js +606 -376
- package/dist/migration-app-version.d.ts +1 -1
- package/dist/source-semantics.d.ts +18 -0
- package/dist/type-safety.d.ts +12 -0
- package/dist/types.d.ts +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,8 +34,8 @@ function getModuleBoundaryProfile(name) {
|
|
|
34
34
|
...profile,
|
|
35
35
|
rules: profile.rules.map((rule) => ({
|
|
36
36
|
...rule,
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
...rule.onlyDependOnLibsWithTags === undefined ? {} : { onlyDependOnLibsWithTags: [...rule.onlyDependOnLibsWithTags] },
|
|
38
|
+
...rule.bannedDependenciesWithTags === undefined ? {} : { bannedDependenciesWithTags: [...rule.bannedDependenciesWithTags] }
|
|
39
39
|
}))
|
|
40
40
|
};
|
|
41
41
|
}
|
|
@@ -251,7 +251,13 @@ var REQUEST_CONTEXT_TOKEN_NAME = "supacloud.request-context", JOB_CONTEXT_TOKEN_
|
|
|
251
251
|
function validateFeatureSpec(spec, module) {
|
|
252
252
|
const diagnostics = [];
|
|
253
253
|
const error = (code, message) => {
|
|
254
|
-
diagnostics.push({
|
|
254
|
+
diagnostics.push({
|
|
255
|
+
severity: "error",
|
|
256
|
+
code,
|
|
257
|
+
message,
|
|
258
|
+
...spec.file === undefined ? {} : { file: spec.file },
|
|
259
|
+
...spec.line === undefined ? {} : { line: spec.line }
|
|
260
|
+
});
|
|
255
261
|
};
|
|
256
262
|
if (!spec.name.trim() || spec.states.length === 0 || spec.states.some((state) => !state.trim()) || new Set(spec.states).size !== spec.states.length) {
|
|
257
263
|
error("invalid-feature-states", "Feature name and states must be non-empty; states must be unique.");
|
|
@@ -289,7 +295,7 @@ function validateFeatureSpec(spec, module) {
|
|
|
289
295
|
const routes = module.controllers.flatMap((controller) => controller.routes.filter((route) => `${route.method} ${joinRoutePaths(controller.path, route.path)}` === transition.route));
|
|
290
296
|
if (routes.length !== 1) {
|
|
291
297
|
error("feature-route-unresolved", `Transition ${transition.name} must reference exactly one route '${transition.route}' in module ${module.name}.`);
|
|
292
|
-
} else if (command && routes[0]
|
|
298
|
+
} else if (command && routes[0]?.command !== command.className) {
|
|
293
299
|
error("feature-route-drift", `Route ${transition.route} is not bound to ${command.className}.`);
|
|
294
300
|
}
|
|
295
301
|
}
|
|
@@ -2657,7 +2663,7 @@ ${procedureMethods.join(`
|
|
|
2657
2663
|
"",
|
|
2658
2664
|
"function selectResponseSchema(status: number, schemas: Readonly<Record<string, unknown>>): unknown {",
|
|
2659
2665
|
" const family = `${Math.floor(status / 100)}xx`;",
|
|
2660
|
-
|
|
2666
|
+
' return schemas[String(status)] ?? schemas[family] ?? schemas[family.toUpperCase()] ?? schemas["default"];',
|
|
2661
2667
|
"}",
|
|
2662
2668
|
"",
|
|
2663
2669
|
...usesValue ? [
|
|
@@ -2685,16 +2691,16 @@ ${procedureMethods.join(`
|
|
|
2685
2691
|
"function schemaReferenceTarget(ref: string, root: unknown): unknown {",
|
|
2686
2692
|
' const localRef = ref.startsWith("#/$defs/") ? ref.slice(8) : ref.startsWith("#/definitions/") ? ref.slice(14) : ref.startsWith("#/components/schemas/") ? ref.slice(21) : ref.startsWith("#") ? undefined : ref;',
|
|
2687
2693
|
" if (localRef !== undefined && isRecord(root)) {",
|
|
2688
|
-
' const defs = ref.startsWith("#/definitions/") ? root
|
|
2694
|
+
' const defs = ref.startsWith("#/definitions/") ? root["definitions"] : ref.startsWith("#/components/schemas/") ? root["components"] : root["$defs"];',
|
|
2689
2695
|
' if (ref.startsWith("#/components/schemas/") && isRecord(defs)) {',
|
|
2690
|
-
|
|
2696
|
+
' const components = defs["schemas"];',
|
|
2691
2697
|
" if (isRecord(components) && components[localRef] !== undefined) return components[localRef];",
|
|
2692
2698
|
" } else if (isRecord(defs) && defs[localRef] !== undefined) return defs[localRef];",
|
|
2693
2699
|
" }",
|
|
2694
2700
|
" for (const entry of API_SCHEMAS as readonly { name: string; schema: unknown }[]) {",
|
|
2695
2701
|
" if (entry.name === ref) return entry.schema;",
|
|
2696
2702
|
" if (!isRecord(entry.schema)) continue;",
|
|
2697
|
-
|
|
2703
|
+
' if (entry.schema["$id"] === ref || entry.schema["$id"] === localRef) return entry.schema;',
|
|
2698
2704
|
' for (const key of ["$defs", "definitions"] as const) {',
|
|
2699
2705
|
" const defs = entry.schema[key];",
|
|
2700
2706
|
" if (isRecord(defs) && localRef !== undefined && defs[localRef] !== undefined) return defs[localRef];",
|
|
@@ -2721,52 +2727,52 @@ ${procedureMethods.join(`
|
|
|
2721
2727
|
" if (schema === true) return value;",
|
|
2722
2728
|
" if (schema === false || !isRecord(schema)) return schemaError();",
|
|
2723
2729
|
' if ("~codec" in schema || Object.getOwnPropertySymbols(schema).some((symbol) => String(symbol).includes("Transform"))) throw new Error("Response schema transforms are unsupported by the generated decoder");',
|
|
2724
|
-
' if (typeof schema
|
|
2725
|
-
|
|
2726
|
-
|
|
2730
|
+
' if (typeof schema["$ref"] === "string") {',
|
|
2731
|
+
' if (seenRefs.has(schema["$ref"])) return schemaError();',
|
|
2732
|
+
' const target = schemaReferenceTarget(schema["$ref"], root);',
|
|
2727
2733
|
" if (target === undefined) return schemaError();",
|
|
2728
|
-
|
|
2734
|
+
' const nextRefs = new Set(seenRefs); nextRefs.add(schema["$ref"]);',
|
|
2729
2735
|
" return decodeSchemaValue(target, value, root, nextRefs, normalize);",
|
|
2730
2736
|
" }",
|
|
2731
|
-
|
|
2732
|
-
' if (Object.hasOwn(schema, "const") && !sameJsonValue(schema
|
|
2733
|
-
|
|
2734
|
-
|
|
2737
|
+
' if (schema["nullable"] === true && value === null) return value;',
|
|
2738
|
+
' if (Object.hasOwn(schema, "const") && !sameJsonValue(schema["const"], value)) return schemaError();',
|
|
2739
|
+
' if (Array.isArray(schema["enum"]) && !schema["enum"].some((entry) => sameJsonValue(entry, value))) return schemaError();',
|
|
2740
|
+
' if (Array.isArray(schema["anyOf"])) {',
|
|
2735
2741
|
" const matches: unknown[] = [];",
|
|
2736
|
-
|
|
2742
|
+
' for (const variant of schema["anyOf"]) { try { matches.push(decodeSchemaValue(variant, value, root, new Set(seenRefs), normalize)); } catch {} }',
|
|
2737
2743
|
" if (matches.length === 0) return schemaError();",
|
|
2738
2744
|
" return matches[0];",
|
|
2739
2745
|
" }",
|
|
2740
|
-
|
|
2746
|
+
' if (Array.isArray(schema["oneOf"])) {',
|
|
2741
2747
|
" const matches: unknown[] = [];",
|
|
2742
|
-
|
|
2748
|
+
' for (const variant of schema["oneOf"]) { try { matches.push(decodeSchemaValue(variant, value, root, new Set(seenRefs), normalize)); } catch {} }',
|
|
2743
2749
|
" if (matches.length !== 1) return schemaError();",
|
|
2744
2750
|
" return matches[0];",
|
|
2745
2751
|
" }",
|
|
2746
|
-
|
|
2752
|
+
' if (Array.isArray(schema["allOf"])) {',
|
|
2747
2753
|
" let output: unknown = value;",
|
|
2748
|
-
|
|
2754
|
+
' for (const variant of schema["allOf"]) {',
|
|
2749
2755
|
" const decoded = decodeSchemaValue(variant, value, root, new Set(seenRefs), normalize);",
|
|
2750
2756
|
" output = isRecord(output) && isRecord(decoded) ? { ...output, ...decoded } : decoded;",
|
|
2751
2757
|
" }",
|
|
2752
2758
|
" return output;",
|
|
2753
2759
|
" }",
|
|
2754
|
-
|
|
2755
|
-
|
|
2760
|
+
' if (schema["not"] !== undefined) {',
|
|
2761
|
+
' try { decodeSchemaValue(schema["not"], value, root, new Set(seenRefs), normalize); } catch { return value; }',
|
|
2756
2762
|
" return schemaError();",
|
|
2757
2763
|
" }",
|
|
2758
|
-
|
|
2759
|
-
|
|
2764
|
+
' if (Array.isArray(schema["type"])) {',
|
|
2765
|
+
' for (const type of schema["type"]) { try { return decodeSchemaValue({ ...schema, type }, value, root, new Set(seenRefs), normalize); } catch {} }',
|
|
2760
2766
|
" return schemaError();",
|
|
2761
2767
|
" }",
|
|
2762
|
-
' if (schema
|
|
2768
|
+
' if (schema["type"] === "object" || (schema["type"] === undefined && (isRecord(schema["properties"]) || schema["required"] !== undefined))) {',
|
|
2763
2769
|
" if (!isRecord(value)) return schemaError();",
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2770
|
+
' const properties = isRecord(schema["properties"]) ? schema["properties"] : {};',
|
|
2771
|
+
' const patterns = isRecord(schema["patternProperties"]) ? schema["patternProperties"] : {};',
|
|
2772
|
+
' const required = Array.isArray(schema["required"]) ? schema["required"] : [];',
|
|
2767
2773
|
' for (const name of required) if (typeof name === "string" && !Object.hasOwn(value, name)) return schemaError();',
|
|
2768
|
-
' if (typeof schema
|
|
2769
|
-
' if (typeof schema
|
|
2774
|
+
' if (typeof schema["minProperties"] === "number" && Object.keys(value).length < schema["minProperties"]) return schemaError();',
|
|
2775
|
+
' if (typeof schema["maxProperties"] === "number" && Object.keys(value).length > schema["maxProperties"]) return schemaError();',
|
|
2770
2776
|
" const output: Record<string, unknown> = {};",
|
|
2771
2777
|
" for (const [name, item] of Object.entries(value)) {",
|
|
2772
2778
|
" const propertySchema = properties[name];",
|
|
@@ -2777,52 +2783,52 @@ ${procedureMethods.join(`
|
|
|
2777
2783
|
" if (applies) { output[name] = decodeSchemaValue(patternSchema, item, root, new Set<string>(), normalize); matched = true; }",
|
|
2778
2784
|
" }",
|
|
2779
2785
|
" if (matched) continue;",
|
|
2780
|
-
|
|
2786
|
+
' if (schema["additionalProperties"] === false || schema["unevaluatedProperties"] === false || schema["additionalProperties"] === undefined) {',
|
|
2781
2787
|
" if (normalize) continue;",
|
|
2782
2788
|
" return schemaError();",
|
|
2783
2789
|
" }",
|
|
2784
|
-
|
|
2785
|
-
|
|
2790
|
+
' if (isRecord(schema["additionalProperties"])) output[name] = decodeSchemaValue(schema["additionalProperties"], item, root, new Set<string>(), normalize);',
|
|
2791
|
+
' else if (schema["additionalProperties"] === true) output[name] = item;',
|
|
2786
2792
|
" }",
|
|
2787
2793
|
" return output;",
|
|
2788
2794
|
" }",
|
|
2789
|
-
' if (schema
|
|
2795
|
+
' if (schema["type"] === "array") {',
|
|
2790
2796
|
" if (!Array.isArray(value)) return schemaError();",
|
|
2791
|
-
' if (typeof schema
|
|
2792
|
-
' if (typeof schema
|
|
2793
|
-
|
|
2794
|
-
|
|
2797
|
+
' if (typeof schema["minItems"] === "number" && value.length < schema["minItems"]) return schemaError();',
|
|
2798
|
+
' if (typeof schema["maxItems"] === "number" && value.length > schema["maxItems"]) return schemaError();',
|
|
2799
|
+
' if (schema["uniqueItems"] === true) { const keys = value.map((item) => JSON.stringify(item)); if (new Set(keys).size !== keys.length) return schemaError(); }',
|
|
2800
|
+
' const tuple = Array.isArray(schema["prefixItems"]) ? schema["prefixItems"] : Array.isArray(schema["items"]) ? schema["items"] : undefined;',
|
|
2795
2801
|
" if (tuple) {",
|
|
2796
|
-
|
|
2797
|
-
|
|
2802
|
+
' if (schema["additionalItems"] === false && value.length > tuple.length) return schemaError();',
|
|
2803
|
+
' return value.map((item, index) => index < tuple.length ? decodeSchemaValue(tuple[index], item, root, new Set<string>(), normalize) : schema["items"] && !Array.isArray(schema["items"]) ? decodeSchemaValue(schema["items"], item, root, new Set<string>(), normalize) : item);',
|
|
2798
2804
|
" }",
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2805
|
+
' if (schema["items"] === undefined || schema["items"] === true) return value;',
|
|
2806
|
+
' if (schema["items"] === false && value.length > 0) return schemaError();',
|
|
2807
|
+
' return value.map((item) => decodeSchemaValue(schema["items"], item, root, new Set<string>(), normalize));',
|
|
2802
2808
|
" }",
|
|
2803
|
-
' if (schema
|
|
2809
|
+
' if (schema["type"] === "string") {',
|
|
2804
2810
|
' if (typeof value !== "string") return schemaError();',
|
|
2805
|
-
' if (typeof schema
|
|
2806
|
-
' if (typeof schema
|
|
2807
|
-
' if (typeof schema
|
|
2808
|
-
|
|
2811
|
+
' if (typeof schema["minLength"] === "number" && value.length < schema["minLength"]) return schemaError();',
|
|
2812
|
+
' if (typeof schema["maxLength"] === "number" && value.length > schema["maxLength"]) return schemaError();',
|
|
2813
|
+
' if (typeof schema["pattern"] === "string") { let matches = false; try { matches = new RegExp(schema["pattern"]).test(value); } catch { return schemaError(); } if (!matches) return schemaError(); }',
|
|
2814
|
+
' if (!matchesFormat(schema["format"], value)) return schemaError();',
|
|
2809
2815
|
" return value;",
|
|
2810
2816
|
" }",
|
|
2811
|
-
' if (schema
|
|
2812
|
-
' if (schema
|
|
2813
|
-
' if (typeof value !== "number" || !Number.isFinite(value) || (schema
|
|
2814
|
-
' if (typeof schema
|
|
2815
|
-
' if (typeof schema
|
|
2816
|
-
' if (typeof schema
|
|
2817
|
-
' if (typeof schema
|
|
2818
|
-
' if (schema
|
|
2819
|
-
' if (schema
|
|
2820
|
-
' if (typeof schema
|
|
2817
|
+
' if (schema["type"] === "boolean") { if (typeof value !== "boolean") return schemaError(); return value; }',
|
|
2818
|
+
' if (schema["type"] === "number" || schema["type"] === "integer") {',
|
|
2819
|
+
' if (typeof value !== "number" || !Number.isFinite(value) || (schema["type"] === "integer" && !Number.isInteger(value))) return schemaError();',
|
|
2820
|
+
' if (typeof schema["minimum"] === "number" && value < schema["minimum"]) return schemaError();',
|
|
2821
|
+
' if (typeof schema["maximum"] === "number" && value > schema["maximum"]) return schemaError();',
|
|
2822
|
+
' if (typeof schema["exclusiveMinimum"] === "number" && value <= schema["exclusiveMinimum"]) return schemaError();',
|
|
2823
|
+
' if (typeof schema["exclusiveMaximum"] === "number" && value >= schema["exclusiveMaximum"]) return schemaError();',
|
|
2824
|
+
' if (schema["exclusiveMinimum"] === true && typeof schema["minimum"] === "number" && value <= schema["minimum"]) return schemaError();',
|
|
2825
|
+
' if (schema["exclusiveMaximum"] === true && typeof schema["maximum"] === "number" && value >= schema["maximum"]) return schemaError();',
|
|
2826
|
+
' if (typeof schema["multipleOf"] === "number" && schema["multipleOf"] > 0 && Math.abs(value / schema["multipleOf"] - Math.round(value / schema["multipleOf"])) > 1e-9) return schemaError();',
|
|
2821
2827
|
" return value;",
|
|
2822
2828
|
" }",
|
|
2823
|
-
' if (schema
|
|
2824
|
-
' if (schema
|
|
2825
|
-
' if (schema
|
|
2829
|
+
' if (schema["type"] === "null") { if (value !== null) return schemaError(); return value; }',
|
|
2830
|
+
' if (schema["type"] === "void" || schema["type"] === "undefined") { if (value !== undefined) return schemaError(); return value; }',
|
|
2831
|
+
' if (schema["type"] === "never") return schemaError();',
|
|
2826
2832
|
" return value;",
|
|
2827
2833
|
"}",
|
|
2828
2834
|
""
|
|
@@ -2896,7 +2902,7 @@ ${procedureMethods.join(`
|
|
|
2896
2902
|
" ...options.headers,",
|
|
2897
2903
|
" };",
|
|
2898
2904
|
' if (options.cookie && !Object.keys(headers).some((key) => key.toLowerCase() === "cookie")) {',
|
|
2899
|
-
' headers
|
|
2905
|
+
' headers["cookie"] = Object.entries(options.cookie).map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`).join("; " );',
|
|
2900
2906
|
" }",
|
|
2901
2907
|
" const interceptors = config.interceptors ?? [];",
|
|
2902
2908
|
" const executeChain = (",
|
|
@@ -3087,7 +3093,7 @@ function renderOpenApi(graph, options) {
|
|
|
3087
3093
|
for (const module of graph.modules) {
|
|
3088
3094
|
for (const controller of module.controllers) {
|
|
3089
3095
|
for (const route of controller.routes) {
|
|
3090
|
-
const documentation = route.data?.openapi;
|
|
3096
|
+
const documentation = route.data?.["openapi"];
|
|
3091
3097
|
if (documentation !== null && typeof documentation === "object" && "hide" in documentation && documentation.hide === true)
|
|
3092
3098
|
continue;
|
|
3093
3099
|
const fullPath = joinRoutePaths(controller.path, route.path);
|
|
@@ -3274,11 +3280,11 @@ function renderOpenApi(graph, options) {
|
|
|
3274
3280
|
"function isUndefinedSchema(value: unknown, seen = new WeakSet<object>(), refs = new Set<string>(), scope?: unknown): boolean {",
|
|
3275
3281
|
" if (!isRecord(value) || seen.has(value)) return false;",
|
|
3276
3282
|
" seen.add(value);",
|
|
3277
|
-
|
|
3283
|
+
' const nextScope = isRecord(value["$defs"]) || isRecord(value["definitions"]) ? value : scope;',
|
|
3278
3284
|
" try {",
|
|
3279
|
-
' if (value
|
|
3280
|
-
' if (Array.isArray(value
|
|
3281
|
-
' const ref = typeof value
|
|
3285
|
+
' if (value["type"] === "undefined") return true;',
|
|
3286
|
+
' if (Array.isArray(value["type"]) && value["type"].length > 0 && value["type"].every((type) => type === "undefined")) return true;',
|
|
3287
|
+
' const ref = typeof value["$ref"] === "string" ? value["$ref"] : undefined;',
|
|
3282
3288
|
" if (ref !== undefined && !refs.has(ref)) {",
|
|
3283
3289
|
" const target = openApiSchemaRefTarget(ref, nextScope);",
|
|
3284
3290
|
" if (target !== undefined) {",
|
|
@@ -3302,10 +3308,10 @@ function renderOpenApi(graph, options) {
|
|
|
3302
3308
|
"function cloneSchema(value: unknown, seen = new WeakSet<object>(), scope?: unknown): OpenApiSchema {",
|
|
3303
3309
|
" if (!isRecord(value)) return {};",
|
|
3304
3310
|
" if (seen.has(value)) return {};",
|
|
3305
|
-
|
|
3311
|
+
' const nextScope = isRecord(value["$defs"]) || isRecord(value["definitions"]) ? value : scope;',
|
|
3306
3312
|
" if (isUndefinedSchema(value, new WeakSet<object>(), new Set<string>(), nextScope)) return {};",
|
|
3307
3313
|
" seen.add(value);",
|
|
3308
|
-
' if (value
|
|
3314
|
+
' if (value["type"] === "void" || value["type"] === "undefined") { seen.delete(value); return {}; }',
|
|
3309
3315
|
" const allowed = new Set([",
|
|
3310
3316
|
' "$id", "$ref", "$schema", "$defs", "definitions", "title", "description", "type", "enum", "const", "examples", "default",',
|
|
3311
3317
|
' "deprecated", "readOnly", "writeOnly", "format", "pattern", "minLength", "maxLength", "minimum",',
|
|
@@ -3352,12 +3358,12 @@ function renderOpenApi(graph, options) {
|
|
|
3352
3358
|
"function schemaAllowsUndefined(value: unknown, seen = new WeakSet<object>(), refs = new Set<string>(), scope?: unknown): boolean {",
|
|
3353
3359
|
" if (!isRecord(value) || seen.has(value)) return false;",
|
|
3354
3360
|
" seen.add(value);",
|
|
3355
|
-
|
|
3361
|
+
' const nextScope = isRecord(value["$defs"]) || isRecord(value["definitions"]) ? value : scope;',
|
|
3356
3362
|
" try {",
|
|
3357
3363
|
' if (Object.getOwnPropertySymbols(value).some((symbol) => String(symbol).toLowerCase().includes("optional"))) return true;',
|
|
3358
|
-
' if (value
|
|
3359
|
-
' if (Array.isArray(value
|
|
3360
|
-
' const ref = typeof value
|
|
3364
|
+
' if (value["type"] === "undefined") return true;',
|
|
3365
|
+
' if (Array.isArray(value["type"]) && value["type"].includes("undefined")) return true;',
|
|
3366
|
+
' const ref = typeof value["$ref"] === "string" ? value["$ref"] : undefined;',
|
|
3361
3367
|
" if (ref !== undefined && !refs.has(ref)) {",
|
|
3362
3368
|
" const target = openApiSchemaRefTarget(ref, nextScope);",
|
|
3363
3369
|
" if (target !== undefined) {",
|
|
@@ -3377,11 +3383,11 @@ function renderOpenApi(graph, options) {
|
|
|
3377
3383
|
"",
|
|
3378
3384
|
"function resolveRegistrySchema(value: unknown, seen = new Set<string>()): OpenApiSchema {",
|
|
3379
3385
|
" const schema = cloneSchema(value);",
|
|
3380
|
-
' const ref = typeof schema
|
|
3386
|
+
' const ref = typeof schema["$ref"] === "string" ? schema["$ref"] : undefined;',
|
|
3381
3387
|
" if (!ref || seen.has(ref)) return schema;",
|
|
3382
3388
|
' const localName = ref.startsWith("#/components/schemas/") ? ref.slice(21) : ref.startsWith("#/$defs/") ? ref.slice(8) : ref.startsWith("#/definitions/") ? ref.slice(14) : ref;',
|
|
3383
3389
|
' if (ref.startsWith("#/$defs/") || ref.startsWith("#/definitions/")) {',
|
|
3384
|
-
' const defs = ref.startsWith("#/$defs/") ? schema
|
|
3390
|
+
' const defs = ref.startsWith("#/$defs/") ? schema["$defs"] : schema["definitions"];',
|
|
3385
3391
|
" if (isRecord(defs) && defs[localName] !== undefined) return resolveRegistrySchema(defs[localName], new Set([...seen, ref]));",
|
|
3386
3392
|
" }",
|
|
3387
3393
|
" for (const [name, candidate] of Object.entries(OPENAPI_SCHEMA_REGISTRY)) {",
|
|
@@ -3394,18 +3400,18 @@ function renderOpenApi(graph, options) {
|
|
|
3394
3400
|
"",
|
|
3395
3401
|
"function schemaProperty(schema: unknown, name: string): OpenApiSchema {",
|
|
3396
3402
|
" const document = resolveRegistrySchema(schema);",
|
|
3397
|
-
|
|
3403
|
+
' const properties = document["properties"];',
|
|
3398
3404
|
' return isRecord(properties) && isRecord(properties[name]) ? properties[name] : { type: "string" };',
|
|
3399
3405
|
"}",
|
|
3400
3406
|
"",
|
|
3401
3407
|
"function schemaPropertyNames(schema: unknown): string[] {",
|
|
3402
3408
|
" const document = resolveRegistrySchema(schema);",
|
|
3403
|
-
|
|
3409
|
+
' return isRecord(document["properties"]) ? Object.keys(document["properties"]).sort() : [];',
|
|
3404
3410
|
"}",
|
|
3405
3411
|
"",
|
|
3406
3412
|
"function schemaRequired(schema: unknown, name: string): boolean {",
|
|
3407
3413
|
" const document = resolveRegistrySchema(schema);",
|
|
3408
|
-
|
|
3414
|
+
' return Array.isArray(document["required"]) && document["required"].includes(name);',
|
|
3409
3415
|
"}",
|
|
3410
3416
|
"",
|
|
3411
3417
|
"function schemaReference(name: string): OpenApiSchema {",
|
|
@@ -4050,24 +4056,24 @@ function assertGraphqlOptions(value) {
|
|
|
4050
4056
|
if (unsupported.length) {
|
|
4051
4057
|
fail(`Unsupported options: ${unsupported.join(", ")}. Configure only schema, documents, scalars and typedDocuments; server schema authoring modes are not supported.`);
|
|
4052
4058
|
}
|
|
4053
|
-
const schema = options
|
|
4059
|
+
const schema = options["schema"];
|
|
4054
4060
|
if (typeof schema !== "string" || !schema.trim() || schema !== schema.trim() || /[\r\n\0]/.test(schema) || /^[a-z][a-z0-9+.-]*:/i.test(schema) && !/^[a-z]:[\\/]/i.test(schema) || ![".graphql", ".gql", ".json"].includes(extname(schema))) {
|
|
4055
4061
|
fail("graphql.schema must be a local .graphql, .gql or .json database snapshot. Export it with graphql-schema; URLs, inline SDL and executable schema sources are not supported.");
|
|
4056
4062
|
}
|
|
4057
|
-
if (options
|
|
4063
|
+
if (options["documents"] !== undefined && (!Array.isArray(options["documents"]) || options["documents"].some((pattern) => typeof pattern !== "string" || !pattern.trim()))) {
|
|
4058
4064
|
fail("graphql.documents must contain local query/fragment glob strings.");
|
|
4059
4065
|
}
|
|
4060
|
-
if (options
|
|
4066
|
+
if (options["typedDocuments"] !== undefined && typeof options["typedDocuments"] !== "boolean") {
|
|
4061
4067
|
fail("graphql.typedDocuments must be a boolean output option.");
|
|
4062
4068
|
}
|
|
4063
|
-
if (options
|
|
4069
|
+
if (options["mutations"] !== undefined && typeof options["mutations"] !== "boolean") {
|
|
4064
4070
|
fail("graphql.mutations must be a boolean opt-in for database-backed mutation documents.");
|
|
4065
4071
|
}
|
|
4066
|
-
if (options
|
|
4067
|
-
if (!options
|
|
4072
|
+
if (options["scalars"] !== undefined) {
|
|
4073
|
+
if (!options["scalars"] || typeof options["scalars"] !== "object" || Array.isArray(options["scalars"])) {
|
|
4068
4074
|
fail("graphql.scalars must be a map of explicit wire types.");
|
|
4069
4075
|
}
|
|
4070
|
-
for (const mapping of Object.values(options
|
|
4076
|
+
for (const mapping of Object.values(options["scalars"])) {
|
|
4071
4077
|
if (typeof mapping === "string" && mapping.trim())
|
|
4072
4078
|
continue;
|
|
4073
4079
|
if (mapping && typeof mapping === "object" && !Array.isArray(mapping) && "input" in mapping && typeof mapping.input === "string" && mapping.input.trim() && "output" in mapping && typeof mapping.output === "string" && mapping.output.trim())
|
|
@@ -4090,7 +4096,7 @@ var init_graphql_options = __esm(() => {
|
|
|
4090
4096
|
|
|
4091
4097
|
// src/graphql-inputs.ts
|
|
4092
4098
|
import { resolve as resolve5 } from "node:path";
|
|
4093
|
-
import * as
|
|
4099
|
+
import * as ts11 from "@typescript/typescript6";
|
|
4094
4100
|
function graphqlInputPaths(options) {
|
|
4095
4101
|
if (!options.graphql)
|
|
4096
4102
|
return [];
|
|
@@ -4101,7 +4107,7 @@ function graphqlInputPaths(options) {
|
|
|
4101
4107
|
}
|
|
4102
4108
|
const root = resolve5(options.rootDir);
|
|
4103
4109
|
const schema = resolve5(root, options.graphql.schema);
|
|
4104
|
-
const documents =
|
|
4110
|
+
const documents = ts11.sys.readDirectory(root, [".graphql", ".gql"], ["**/node_modules/**", "**/.git/**", resolve5(options.outDir)], options.graphql.documents ?? ["**/*.graphql", "**/*.gql"]).map((path) => resolve5(path)).filter((path) => path !== schema);
|
|
4105
4111
|
return [schema, ...[...new Set(documents)].sort()];
|
|
4106
4112
|
}
|
|
4107
4113
|
var init_graphql_inputs = __esm(() => {
|
|
@@ -4109,7 +4115,7 @@ var init_graphql_inputs = __esm(() => {
|
|
|
4109
4115
|
});
|
|
4110
4116
|
|
|
4111
4117
|
// src/graphql-runtime.ts
|
|
4112
|
-
import * as
|
|
4118
|
+
import * as ts12 from "@typescript/typescript6";
|
|
4113
4119
|
import { resolve as resolve6 } from "node:path";
|
|
4114
4120
|
function renderGraphqlValidators(source, operationNames, operationKinds = new Map) {
|
|
4115
4121
|
const fileName = resolve6("/__supacloud_graphql__/contracts.ts");
|
|
@@ -4121,18 +4127,18 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4121
4127
|
noPropertyAccessFromIndexSignature: true,
|
|
4122
4128
|
noFallthroughCasesInSwitch: true,
|
|
4123
4129
|
skipLibCheck: false,
|
|
4124
|
-
target:
|
|
4130
|
+
target: ts12.ScriptTarget.ES2022,
|
|
4125
4131
|
lib: ["lib.es2022.d.ts"],
|
|
4126
4132
|
types: [],
|
|
4127
4133
|
noEmit: true
|
|
4128
4134
|
};
|
|
4129
|
-
const host =
|
|
4135
|
+
const host = ts12.createCompilerHost(options);
|
|
4130
4136
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
4131
|
-
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve6(path) === fileName ?
|
|
4132
|
-
const program =
|
|
4133
|
-
const diagnostics =
|
|
4137
|
+
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve6(path) === fileName ? ts12.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
|
|
4138
|
+
const program = ts12.createProgram([fileName], options, host);
|
|
4139
|
+
const diagnostics = ts12.getPreEmitDiagnostics(program);
|
|
4134
4140
|
if (diagnostics.length) {
|
|
4135
|
-
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) =>
|
|
4141
|
+
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts12.flattenDiagnosticMessageText(item.messageText, `
|
|
4136
4142
|
`)).join("; ")}`);
|
|
4137
4143
|
}
|
|
4138
4144
|
const checker = program.getTypeChecker();
|
|
@@ -4162,25 +4168,25 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4162
4168
|
return name;
|
|
4163
4169
|
}
|
|
4164
4170
|
function expression(type) {
|
|
4165
|
-
if (type.flags &
|
|
4171
|
+
if (type.flags & ts12.TypeFlags.Any)
|
|
4166
4172
|
return unsupported(type);
|
|
4167
|
-
if (type.flags &
|
|
4173
|
+
if (type.flags & ts12.TypeFlags.Unknown)
|
|
4168
4174
|
return "true";
|
|
4169
|
-
if (type.flags &
|
|
4175
|
+
if (type.flags & ts12.TypeFlags.Never)
|
|
4170
4176
|
return "false";
|
|
4171
|
-
if (type.flags &
|
|
4177
|
+
if (type.flags & ts12.TypeFlags.Null)
|
|
4172
4178
|
return "value === null";
|
|
4173
|
-
if (type.flags &
|
|
4179
|
+
if (type.flags & ts12.TypeFlags.Undefined)
|
|
4174
4180
|
return "value === undefined";
|
|
4175
4181
|
if (type.isStringLiteral() || type.isNumberLiteral())
|
|
4176
4182
|
return `value === ${JSON.stringify(type.value)}`;
|
|
4177
|
-
if (type.flags &
|
|
4183
|
+
if (type.flags & ts12.TypeFlags.BooleanLiteral)
|
|
4178
4184
|
return `value === ${checker.typeToString(type)}`;
|
|
4179
|
-
if (type.flags &
|
|
4185
|
+
if (type.flags & ts12.TypeFlags.String)
|
|
4180
4186
|
return 'typeof value === "string"';
|
|
4181
|
-
if (type.flags &
|
|
4187
|
+
if (type.flags & ts12.TypeFlags.Number)
|
|
4182
4188
|
return 'typeof value === "number" && Number.isFinite(value)';
|
|
4183
|
-
if (type.flags &
|
|
4189
|
+
if (type.flags & ts12.TypeFlags.Boolean)
|
|
4184
4190
|
return 'typeof value === "boolean"';
|
|
4185
4191
|
if (type.isUnion())
|
|
4186
4192
|
return type.types.map((part) => `${reference(part)}(value)`).join(" || ");
|
|
@@ -4189,16 +4195,16 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4189
4195
|
if (checker.isTupleType(type))
|
|
4190
4196
|
return unsupported(type);
|
|
4191
4197
|
if (checker.isArrayType(type)) {
|
|
4192
|
-
const item = checker.getIndexTypeOfType(type,
|
|
4198
|
+
const item = checker.getIndexTypeOfType(type, ts12.IndexKind.Number);
|
|
4193
4199
|
if (!item)
|
|
4194
4200
|
return unsupported(type);
|
|
4195
4201
|
return `isGraphqlArray(value) && Array.from(value).every(${reference(item)})`;
|
|
4196
4202
|
}
|
|
4197
|
-
if (type.flags &
|
|
4203
|
+
if (type.flags & ts12.TypeFlags.Object) {
|
|
4198
4204
|
if (type.getCallSignatures().length || type.getConstructSignatures().length)
|
|
4199
4205
|
return unsupported(type);
|
|
4200
4206
|
const indexes = checker.getIndexInfosOfType(type);
|
|
4201
|
-
if (indexes.some((index) => !(index.keyType.flags &
|
|
4207
|
+
if (indexes.some((index) => !(index.keyType.flags & ts12.TypeFlags.String)))
|
|
4202
4208
|
return unsupported(type);
|
|
4203
4209
|
const properties = checker.getPropertiesOfType(type).map((property) => {
|
|
4204
4210
|
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
@@ -4207,7 +4213,7 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4207
4213
|
const check = reference(checker.getTypeOfSymbolAtLocation(property, declaration));
|
|
4208
4214
|
const key = JSON.stringify(property.name);
|
|
4209
4215
|
const present = `Object.prototype.hasOwnProperty.call(value, ${key})`;
|
|
4210
|
-
return property.flags &
|
|
4216
|
+
return property.flags & ts12.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
|
|
4211
4217
|
});
|
|
4212
4218
|
const indexedValues = indexes.map((index) => `Object.values(value).every(${reference(index.type)})`);
|
|
4213
4219
|
return ["isGraphqlRecord(value)", ...properties, ...indexedValues].join(" && ");
|
|
@@ -4345,8 +4351,8 @@ async function renderGraphql(options) {
|
|
|
4345
4351
|
severity: "error",
|
|
4346
4352
|
code,
|
|
4347
4353
|
message: error instanceof Error ? error.message : String(error),
|
|
4348
|
-
|
|
4349
|
-
|
|
4354
|
+
...source === undefined ? {} : { file: localPath(source) },
|
|
4355
|
+
...gql?.locations?.[0]?.line === undefined ? {} : { line: gql.locations[0].line },
|
|
4350
4356
|
suggestion: "Update the role-scoped local schema snapshot or correct the query, then recompile."
|
|
4351
4357
|
});
|
|
4352
4358
|
};
|
|
@@ -4396,8 +4402,8 @@ async function renderGraphql(options) {
|
|
|
4396
4402
|
severity: "error",
|
|
4397
4403
|
code: "graphql-query-only",
|
|
4398
4404
|
message: "GraphQL subscriptions are not supported by the HTTP contract compiler. Use the governed Realtime transport for subscriptions.",
|
|
4399
|
-
|
|
4400
|
-
line: definition.loc
|
|
4405
|
+
...definition.loc ? { file: localPath(definition.loc.source.name) } : {},
|
|
4406
|
+
...definition.loc?.startToken.line === undefined ? {} : { line: definition.loc.startToken.line },
|
|
4401
4407
|
suggestion: "Remove this subscription from the GraphQL documents and use the supported Realtime contract."
|
|
4402
4408
|
});
|
|
4403
4409
|
} else if (definition.operation === "mutation" && !options.graphql.mutations) {
|
|
@@ -4405,8 +4411,8 @@ async function renderGraphql(options) {
|
|
|
4405
4411
|
severity: "error",
|
|
4406
4412
|
code: "graphql-query-only",
|
|
4407
4413
|
message: "GraphQL mutations are disabled by default. Set graphql.mutations to true only after reviewing database grants, RLS, audit and idempotency behavior.",
|
|
4408
|
-
|
|
4409
|
-
line: definition.loc
|
|
4414
|
+
...definition.loc ? { file: localPath(definition.loc.source.name) } : {},
|
|
4415
|
+
...definition.loc?.startToken.line === undefined ? {} : { line: definition.loc.startToken.line },
|
|
4410
4416
|
suggestion: "Keep business writes in the governed Command API, or explicitly opt in with graphql.mutations: true."
|
|
4411
4417
|
});
|
|
4412
4418
|
}
|
|
@@ -25275,6 +25281,12 @@ function createExecutionSnapshot(graph, subjects = graph.modules.map((module) =>
|
|
|
25275
25281
|
contexts: subjects.map((subject) => {
|
|
25276
25282
|
const context = createContextPack(graph, subject);
|
|
25277
25283
|
const owner = graph.modules.find((module) => module.name === context.subject);
|
|
25284
|
+
if (owner === undefined)
|
|
25285
|
+
throw new Error(`Execution context owner is missing: ${context.subject}`);
|
|
25286
|
+
const modules = context.modules.map((module) => {
|
|
25287
|
+
const file = executionSourceFile(module.file);
|
|
25288
|
+
return { name: module.name, ...file === undefined ? {} : { file } };
|
|
25289
|
+
});
|
|
25278
25290
|
return {
|
|
25279
25291
|
subject: context.subject,
|
|
25280
25292
|
aliases: [...new Set([
|
|
@@ -25285,10 +25297,7 @@ function createExecutionSnapshot(graph, subjects = graph.modules.map((module) =>
|
|
|
25285
25297
|
...(owner.jobs ?? []).flatMap((job) => [job.name, job.className, job.serviceKey]),
|
|
25286
25298
|
...owner.queries.flatMap((query) => [query.name, query.className])
|
|
25287
25299
|
])],
|
|
25288
|
-
modules
|
|
25289
|
-
name: module.name,
|
|
25290
|
-
...executionSourceFile(module.file) ? { file: executionSourceFile(module.file) } : {}
|
|
25291
|
-
})),
|
|
25300
|
+
modules,
|
|
25292
25301
|
files: context.files,
|
|
25293
25302
|
diagnostics: context.diagnostics.map((diagnostic) => {
|
|
25294
25303
|
const repair = createDiagnosticRepairPlan([diagnostic])[0];
|
|
@@ -25634,10 +25643,11 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25634
25643
|
const providers = bound(names(module.providers.map((provider) => provider.token)), moduleIndex < APPLICATION_DEVELOPMENT_LIMITS2.modules ? remainingProviders : 0);
|
|
25635
25644
|
remainingProviders -= providers.items.length;
|
|
25636
25645
|
omittedProviders += providers.omitted;
|
|
25646
|
+
const file = executionSourceFile(module.file);
|
|
25637
25647
|
developmentModules.push({
|
|
25638
25648
|
name: module.name,
|
|
25639
25649
|
className: module.className,
|
|
25640
|
-
...
|
|
25650
|
+
...file === undefined ? {} : { file },
|
|
25641
25651
|
...module.tags && module.tags.length > 0 ? { tags: names(module.tags) } : {},
|
|
25642
25652
|
providers: providers.items,
|
|
25643
25653
|
controllers: names(module.controllers.map((controller) => controller.className)),
|
|
@@ -25650,6 +25660,7 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25650
25660
|
for (const route of controller.routes) {
|
|
25651
25661
|
const candidates = module.commands.filter((command) => command.className === route.command || command.name === route.command);
|
|
25652
25662
|
const command = candidates.length === 1 ? candidates[0]?.name : undefined;
|
|
25663
|
+
const kinds = schemaKinds(route);
|
|
25653
25664
|
routes.push({
|
|
25654
25665
|
module: module.name,
|
|
25655
25666
|
method: route.method,
|
|
@@ -25658,7 +25669,7 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25658
25669
|
handler: route.handler,
|
|
25659
25670
|
...command === undefined ? {} : { command },
|
|
25660
25671
|
aspects: (route.aspects ?? []).map((aspect) => aspect.name),
|
|
25661
|
-
...
|
|
25672
|
+
...kinds === undefined ? {} : { schemaKinds: kinds }
|
|
25662
25673
|
});
|
|
25663
25674
|
}
|
|
25664
25675
|
}
|
|
@@ -25691,11 +25702,13 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25691
25702
|
const diagnostics = [];
|
|
25692
25703
|
for (const diagnostic of graph.diagnostics ?? []) {
|
|
25693
25704
|
const repair = createDiagnosticRepairPlan([diagnostic])[0];
|
|
25705
|
+
const file = executionSourceFile(diagnostic.file);
|
|
25706
|
+
const line = Number.isSafeInteger(diagnostic.line) && diagnostic.line !== undefined && diagnostic.line > 0 ? diagnostic.line : undefined;
|
|
25694
25707
|
diagnostics.push({
|
|
25695
25708
|
code: diagnostic.code,
|
|
25696
25709
|
severity: diagnostic.severity,
|
|
25697
|
-
...
|
|
25698
|
-
...
|
|
25710
|
+
...file === undefined ? {} : { file },
|
|
25711
|
+
...line === undefined ? {} : { line },
|
|
25699
25712
|
...repair ? { repair: { type: repair.type, readiness: repair.readiness } } : {}
|
|
25700
25713
|
});
|
|
25701
25714
|
}
|
|
@@ -26214,7 +26227,7 @@ var init_delivery_migration_archive2 = __esm(() => {
|
|
|
26214
26227
|
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
26215
26228
|
import { lstat as lstat2, readFile as readFile6, realpath as realpath4, rename as rename4, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
26216
26229
|
import { dirname as dirname8, isAbsolute as isAbsolute3, relative as relative8, resolve as resolve14, sep as sep8 } from "node:path";
|
|
26217
|
-
import * as
|
|
26230
|
+
import * as ts16 from "@typescript/typescript6";
|
|
26218
26231
|
async function applyDiagnosticFix(fix, options = {}) {
|
|
26219
26232
|
if (!fix || typeof fix.targetFile !== "string")
|
|
26220
26233
|
throw new Error("Invalid DiagnosticFix");
|
|
@@ -26243,7 +26256,7 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26243
26256
|
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
26244
26257
|
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
26245
26258
|
}
|
|
26246
|
-
content = replaceProperty(source, object, fix.property,
|
|
26259
|
+
content = replaceProperty(source, object, fix.property, ts16.factory.createStringLiteral(fix.value));
|
|
26247
26260
|
break;
|
|
26248
26261
|
}
|
|
26249
26262
|
case "add_module_import": {
|
|
@@ -26254,15 +26267,15 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26254
26267
|
source = parse8(file, withImport);
|
|
26255
26268
|
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
26256
26269
|
const imports = property(object, "imports");
|
|
26257
|
-
if (imports && !
|
|
26270
|
+
if (imports && !ts16.isArrayLiteralExpression(imports.initializer)) {
|
|
26258
26271
|
throw new Error("Module imports must be a static array");
|
|
26259
26272
|
}
|
|
26260
|
-
const values = imports &&
|
|
26261
|
-
if (values.some(
|
|
26273
|
+
const values = imports && ts16.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
26274
|
+
if (values.some(ts16.isSpreadElement))
|
|
26262
26275
|
throw new Error("Module imports cannot contain spread elements");
|
|
26263
|
-
content = values.some((value) =>
|
|
26276
|
+
content = values.some((value) => ts16.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts16.factory.createArrayLiteralExpression([
|
|
26264
26277
|
...values,
|
|
26265
|
-
|
|
26278
|
+
ts16.factory.createIdentifier(fix.symbol)
|
|
26266
26279
|
]));
|
|
26267
26280
|
break;
|
|
26268
26281
|
}
|
|
@@ -26274,24 +26287,24 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26274
26287
|
const command = findClass(source, fix.command);
|
|
26275
26288
|
const object = decoratorObject(command, "Command");
|
|
26276
26289
|
const current = property(object, "permission");
|
|
26277
|
-
if (current && (!
|
|
26290
|
+
if (current && (!ts16.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
26278
26291
|
throw new Error("Command permission already exists with a different value");
|
|
26279
26292
|
}
|
|
26280
|
-
content = current ? original : replaceProperty(source, object, "permission",
|
|
26293
|
+
content = current ? original : replaceProperty(source, object, "permission", ts16.factory.createStringLiteral(permission));
|
|
26281
26294
|
break;
|
|
26282
26295
|
}
|
|
26283
26296
|
case "add_route_parameter_binding": {
|
|
26284
26297
|
const controller = findClass(source, fix.controller);
|
|
26285
|
-
const method = unique(controller.members.filter((member) =>
|
|
26286
|
-
const parameter = unique(method.parameters.filter((candidate) =>
|
|
26298
|
+
const method = unique(controller.members.filter((member) => ts16.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
|
|
26299
|
+
const parameter = unique(method.parameters.filter((candidate) => ts16.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
|
|
26287
26300
|
const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
|
|
26288
26301
|
if (!binding)
|
|
26289
26302
|
throw new Error("Invalid route binding");
|
|
26290
|
-
const decorators =
|
|
26303
|
+
const decorators = ts16.getDecorators(parameter) ?? [];
|
|
26291
26304
|
if (decorators.length > 0)
|
|
26292
26305
|
throw new Error("Parameter already has a decorator");
|
|
26293
|
-
const framework = unique(source.statements.filter((statement) =>
|
|
26294
|
-
if (!
|
|
26306
|
+
const framework = unique(source.statements.filter((statement) => ts16.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts16.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
|
|
26307
|
+
if (!ts16.isImportDeclaration(framework) || !ts16.isStringLiteral(framework.moduleSpecifier)) {
|
|
26295
26308
|
throw new Error("Framework import must be static");
|
|
26296
26309
|
}
|
|
26297
26310
|
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
@@ -26317,20 +26330,22 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26317
26330
|
return result;
|
|
26318
26331
|
}
|
|
26319
26332
|
function parse8(file, text) {
|
|
26320
|
-
const result =
|
|
26333
|
+
const result = ts16.transpileModule(text, {
|
|
26321
26334
|
fileName: file,
|
|
26322
26335
|
reportDiagnostics: true,
|
|
26323
|
-
compilerOptions: { target:
|
|
26336
|
+
compilerOptions: { target: ts16.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
26324
26337
|
});
|
|
26325
|
-
if (result.diagnostics?.some((item) => item.category ===
|
|
26338
|
+
if (result.diagnostics?.some((item) => item.category === ts16.DiagnosticCategory.Error)) {
|
|
26326
26339
|
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
26327
26340
|
}
|
|
26328
|
-
return
|
|
26341
|
+
return ts16.createSourceFile(file, text, ts16.ScriptTarget.Latest, true, ts16.ScriptKind.TS);
|
|
26329
26342
|
}
|
|
26330
26343
|
function unique(items, description) {
|
|
26331
|
-
|
|
26344
|
+
const [item] = items;
|
|
26345
|
+
if (items.length !== 1 || item === undefined) {
|
|
26332
26346
|
throw new Error(`Expected exactly one ${description}; found ${items.length}`);
|
|
26333
|
-
|
|
26347
|
+
}
|
|
26348
|
+
return item;
|
|
26334
26349
|
}
|
|
26335
26350
|
function identifier3(value) {
|
|
26336
26351
|
if (!/^[A-Za-z_$][\w$]*$/.test(value))
|
|
@@ -26339,50 +26354,50 @@ function identifier3(value) {
|
|
|
26339
26354
|
function nameOf(name) {
|
|
26340
26355
|
if (!name)
|
|
26341
26356
|
return "";
|
|
26342
|
-
return
|
|
26357
|
+
return ts16.isIdentifier(name) || ts16.isStringLiteral(name) || ts16.isNumericLiteral(name) ? name.text : "";
|
|
26343
26358
|
}
|
|
26344
26359
|
function property(object, key) {
|
|
26345
|
-
if (object.properties.some((item) => !
|
|
26360
|
+
if (object.properties.some((item) => !ts16.isPropertyAssignment(item) || ts16.isComputedPropertyName(item.name))) {
|
|
26346
26361
|
throw new Error("Fix requires explicit static object properties");
|
|
26347
26362
|
}
|
|
26348
|
-
const values = object.properties.filter((item) =>
|
|
26363
|
+
const values = object.properties.filter((item) => ts16.isPropertyAssignment(item) && nameOf(item.name) === key);
|
|
26349
26364
|
if (values.length > 1)
|
|
26350
26365
|
throw new Error(`Duplicate '${key}' property`);
|
|
26351
26366
|
return values[0];
|
|
26352
26367
|
}
|
|
26353
26368
|
function stringProperty(object, key) {
|
|
26354
26369
|
const value = property(object, key)?.initializer;
|
|
26355
|
-
return value &&
|
|
26370
|
+
return value && ts16.isStringLiteral(value) ? value.text : undefined;
|
|
26356
26371
|
}
|
|
26357
26372
|
function replaceProperty(source, object, key, value) {
|
|
26358
26373
|
const previous = property(object, key);
|
|
26359
|
-
const replacement =
|
|
26374
|
+
const replacement = ts16.factory.createPropertyAssignment(key, value);
|
|
26360
26375
|
const properties = object.properties.map((item) => item === previous ? replacement : item);
|
|
26361
26376
|
if (!previous)
|
|
26362
26377
|
properties.push(replacement);
|
|
26363
|
-
const updated =
|
|
26364
|
-
return source.text.slice(0, object.getStart(source)) +
|
|
26378
|
+
const updated = ts16.factory.updateObjectLiteralExpression(object, properties);
|
|
26379
|
+
return source.text.slice(0, object.getStart(source)) + ts16.createPrinter().printNode(ts16.EmitHint.Expression, updated, source) + source.text.slice(object.end);
|
|
26365
26380
|
}
|
|
26366
26381
|
function findClass(source, name) {
|
|
26367
|
-
return unique(source.statements.filter((statement) =>
|
|
26382
|
+
return unique(source.statements.filter((statement) => ts16.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
26368
26383
|
}
|
|
26369
26384
|
function decoratorObject(node, name) {
|
|
26370
|
-
const decorator = unique((
|
|
26371
|
-
const argument =
|
|
26372
|
-
if (!argument || !
|
|
26385
|
+
const decorator = unique((ts16.getDecorators(node) ?? []).filter((item) => ts16.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
|
|
26386
|
+
const argument = ts16.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
|
|
26387
|
+
if (!argument || !ts16.isObjectLiteralExpression(argument))
|
|
26373
26388
|
throw new Error(`@${name} requires a static object`);
|
|
26374
26389
|
return argument;
|
|
26375
26390
|
}
|
|
26376
26391
|
function moduleObjects(source) {
|
|
26377
26392
|
const result = [];
|
|
26378
26393
|
for (const statement of source.statements) {
|
|
26379
|
-
if (
|
|
26394
|
+
if (ts16.isClassDeclaration(statement) && (ts16.getDecorators(statement) ?? []).some((item) => ts16.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
|
|
26380
26395
|
result.push(decoratorObject(statement, "Module"));
|
|
26381
26396
|
}
|
|
26382
|
-
if (
|
|
26397
|
+
if (ts16.isVariableStatement(statement)) {
|
|
26383
26398
|
for (const declaration of statement.declarationList.declarations) {
|
|
26384
26399
|
const call = declaration.initializer;
|
|
26385
|
-
if (call &&
|
|
26400
|
+
if (call && ts16.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts16.isObjectLiteralExpression(call.arguments[0])) {
|
|
26386
26401
|
result.push(call.arguments[0]);
|
|
26387
26402
|
}
|
|
26388
26403
|
}
|
|
@@ -26396,19 +26411,19 @@ function importSymbol(source, path, symbol) {
|
|
|
26396
26411
|
const target = resolve14(dirname8(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
26397
26412
|
if (current === target)
|
|
26398
26413
|
return source.text;
|
|
26399
|
-
const matches = source.statements.filter((item) =>
|
|
26414
|
+
const matches = source.statements.filter((item) => ts16.isImportDeclaration(item) && ts16.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
|
|
26400
26415
|
if (matches.length > 1)
|
|
26401
26416
|
throw new Error(`Ambiguous imports from '${path}'`);
|
|
26402
26417
|
const match = matches[0];
|
|
26403
|
-
if (match &&
|
|
26418
|
+
if (match && ts16.isImportDeclaration(match) && match.importClause?.namedBindings && ts16.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
|
|
26404
26419
|
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
26405
26420
|
return source.text;
|
|
26406
26421
|
const bindings = match.importClause.namedBindings;
|
|
26407
|
-
const updated =
|
|
26422
|
+
const updated = ts16.factory.updateNamedImports(bindings, [
|
|
26408
26423
|
...bindings.elements,
|
|
26409
|
-
|
|
26424
|
+
ts16.factory.createImportSpecifier(false, undefined, ts16.factory.createIdentifier(symbol))
|
|
26410
26425
|
]);
|
|
26411
|
-
return source.text.slice(0, bindings.getStart(source)) +
|
|
26426
|
+
return source.text.slice(0, bindings.getStart(source)) + ts16.createPrinter().printNode(ts16.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
|
|
26412
26427
|
}
|
|
26413
26428
|
if (match)
|
|
26414
26429
|
throw new Error(`Import from '${path}' is not a named value import`);
|
|
@@ -26436,21 +26451,21 @@ function requestIdentifier(input) {
|
|
|
26436
26451
|
}
|
|
26437
26452
|
function decodeMetadata(input) {
|
|
26438
26453
|
const envelope = record6(input);
|
|
26439
|
-
if (Object.keys(envelope).some((key) => key !== "version" && key !== "events") || envelope
|
|
26454
|
+
if (Object.keys(envelope).some((key) => key !== "version" && key !== "events") || envelope["version"] !== 1 || !Array.isArray(envelope["events"]) || envelope["events"].length > EXECUTION_CONTEXT_LIMITS.inputEvents)
|
|
26440
26455
|
return invalid();
|
|
26441
|
-
const events = envelope
|
|
26456
|
+
const events = envelope["events"].map((entry) => {
|
|
26442
26457
|
const event = record6(entry);
|
|
26443
|
-
if (Object.keys(event).some((key) => !["kind", "operation", "stage", "phase", "requestId", "durationMs", "attempt", "traceId"].includes(key)) || event
|
|
26458
|
+
if (Object.keys(event).some((key) => !["kind", "operation", "stage", "phase", "requestId", "durationMs", "attempt", "traceId"].includes(key)) || event["kind"] !== "route" && event["kind"] !== "command" && event["kind"] !== "job" || event["phase"] !== "started" && event["phase"] !== "succeeded" && event["phase"] !== "failed" || !metadataText(event["operation"], 512) || !metadataText(event["stage"], 256) || "requestId" in event && !requestIdentifier(event["requestId"]) || "traceId" in event && !requestIdentifier(event["traceId"]) || "attempt" in event && (typeof event["attempt"] !== "number" || !Number.isInteger(event["attempt"]) || event["attempt"] < 1 || event["attempt"] > 1e6) || "durationMs" in event && (typeof event["durationMs"] !== "number" || !Number.isFinite(event["durationMs"]) || event["durationMs"] < 0 || event["durationMs"] > Number.MAX_SAFE_INTEGER))
|
|
26444
26459
|
return invalid();
|
|
26445
26460
|
return {
|
|
26446
|
-
kind: event
|
|
26447
|
-
operation: event
|
|
26448
|
-
stage: event
|
|
26449
|
-
phase: event
|
|
26450
|
-
...event
|
|
26451
|
-
...event
|
|
26452
|
-
...event
|
|
26453
|
-
...event
|
|
26461
|
+
kind: event["kind"],
|
|
26462
|
+
operation: event["operation"],
|
|
26463
|
+
stage: event["stage"],
|
|
26464
|
+
phase: event["phase"],
|
|
26465
|
+
...event["requestId"] === undefined ? {} : { requestId: event["requestId"] },
|
|
26466
|
+
...event["durationMs"] === undefined ? {} : { durationMs: event["durationMs"] },
|
|
26467
|
+
...event["attempt"] === undefined ? {} : { attempt: event["attempt"] },
|
|
26468
|
+
...event["traceId"] === undefined ? {} : { traceId: event["traceId"] }
|
|
26454
26469
|
};
|
|
26455
26470
|
});
|
|
26456
26471
|
if (Buffer.byteLength(JSON.stringify({ version: 1, events }), "utf8") > EXECUTION_CONTEXT_LIMITS.inputBytes)
|
|
@@ -26615,10 +26630,10 @@ function correlateSnapshot(snapshot, subject, events, requestId) {
|
|
|
26615
26630
|
correlation: "current-graph-only",
|
|
26616
26631
|
deploymentVerified: false,
|
|
26617
26632
|
eventsTrusted: false,
|
|
26618
|
-
modules: modules.slice(0, EXECUTION_CONTEXT_LIMITS.modules).map((module) =>
|
|
26619
|
-
|
|
26620
|
-
|
|
26621
|
-
})
|
|
26633
|
+
modules: modules.slice(0, EXECUTION_CONTEXT_LIMITS.modules).map((module) => {
|
|
26634
|
+
const file = executionSourceFile(module.file);
|
|
26635
|
+
return { name: module.name, ...file === undefined ? {} : { file } };
|
|
26636
|
+
}),
|
|
26622
26637
|
files: files.slice(0, EXECUTION_CONTEXT_LIMITS.files),
|
|
26623
26638
|
executionPlans: [...matchedPlans].slice(0, EXECUTION_CONTEXT_LIMITS.plans),
|
|
26624
26639
|
events: retained,
|
|
@@ -26707,16 +26722,16 @@ async function createDeliveryExecutionContextPack(manifestPath, target, subject,
|
|
|
26707
26722
|
if (!observations || typeof observations !== "object" || Array.isArray(observations))
|
|
26708
26723
|
throw invalid();
|
|
26709
26724
|
const envelope = observations;
|
|
26710
|
-
if (Object.keys(envelope).some((key) => !["version", "events", "delivery"].includes(key)) || !envelope
|
|
26725
|
+
if (Object.keys(envelope).some((key) => !["version", "events", "delivery"].includes(key)) || !envelope["delivery"] || typeof envelope["delivery"] !== "object" || Array.isArray(envelope["delivery"]))
|
|
26711
26726
|
throw invalid();
|
|
26712
|
-
const identity = envelope
|
|
26713
|
-
if (Object.keys(identity).length !== 2 || typeof identity
|
|
26727
|
+
const identity = envelope["delivery"];
|
|
26728
|
+
if (Object.keys(identity).length !== 2 || typeof identity["target"] !== "string" || typeof identity["objectId"] !== "string" || !/^[a-f0-9]{64}$/.test(identity["objectId"]))
|
|
26714
26729
|
throw invalid();
|
|
26715
26730
|
let object;
|
|
26716
26731
|
let snapshot;
|
|
26717
26732
|
try {
|
|
26718
26733
|
const { root, object: found, planned } = await readDeliverySelection(manifestPath, target);
|
|
26719
|
-
if (!found || identity
|
|
26734
|
+
if (!found || identity["target"] !== target || identity["objectId"] !== found.objectId) {
|
|
26720
26735
|
throw new DeliveryContextError("DELIVERY_CONTEXT_IDENTITY_MISMATCH");
|
|
26721
26736
|
}
|
|
26722
26737
|
object = found;
|
|
@@ -26733,7 +26748,7 @@ async function createDeliveryExecutionContextPack(manifestPath, target, subject,
|
|
|
26733
26748
|
throw new DeliveryContextError("DELIVERY_CONTEXT_INTEGRITY_FAILED");
|
|
26734
26749
|
}
|
|
26735
26750
|
const pack = {
|
|
26736
|
-
...executionContextFromSnapshot(snapshot, subject, { version: envelope
|
|
26751
|
+
...executionContextFromSnapshot(snapshot, subject, { version: envelope["version"], events: envelope["events"] }, requestId),
|
|
26737
26752
|
correlation: "verified-build-snapshot",
|
|
26738
26753
|
delivery: { target, objectId: object.objectId, artifactVerified: true }
|
|
26739
26754
|
};
|
|
@@ -26941,7 +26956,7 @@ var init_graphql_schema = __esm(() => {
|
|
|
26941
26956
|
import { createHash as createHash12 } from "node:crypto";
|
|
26942
26957
|
import { mkdir as mkdir6, readFile as readFile14 } from "node:fs/promises";
|
|
26943
26958
|
import { dirname as dirname12, relative as relative12, resolve as resolve24 } from "node:path";
|
|
26944
|
-
import * as
|
|
26959
|
+
import * as ts18 from "@typescript/typescript6";
|
|
26945
26960
|
function hash5(value) {
|
|
26946
26961
|
return createHash12("sha256").update(value).digest("hex");
|
|
26947
26962
|
}
|
|
@@ -26981,20 +26996,20 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
26981
26996
|
const rootDir = resolve24(options.rootDir), outDir = resolve24(options.outDir);
|
|
26982
26997
|
const postgrestTypes = resolve24(rootDir, options.postgrestTypes), drizzleSchema = resolve24(rootDir, options.drizzleSchema);
|
|
26983
26998
|
const snapshot = await readFile14(postgrestTypes, "utf8");
|
|
26984
|
-
const syntax =
|
|
26985
|
-
const database = syntax.statements.find((node) => (
|
|
26999
|
+
const syntax = ts18.createSourceFile(postgrestTypes, snapshot, ts18.ScriptTarget.Latest, true);
|
|
27000
|
+
const database = syntax.statements.find((node) => (ts18.isTypeAliasDeclaration(node) || ts18.isInterfaceDeclaration(node)) && node.name.text === "Database" && node.modifiers?.some((modifier) => modifier.kind === ts18.SyntaxKind.ExportKeyword));
|
|
26986
27001
|
if (!database)
|
|
26987
27002
|
throw new Error("PostgREST snapshot must export Database from the official type generator");
|
|
26988
|
-
const program =
|
|
27003
|
+
const program = ts18.createProgram([postgrestTypes], {
|
|
26989
27004
|
strict: true,
|
|
26990
27005
|
noEmit: true,
|
|
26991
27006
|
skipLibCheck: true,
|
|
26992
27007
|
types: [],
|
|
26993
|
-
target:
|
|
26994
|
-
module:
|
|
26995
|
-
moduleResolution:
|
|
27008
|
+
target: ts18.ScriptTarget.ES2022,
|
|
27009
|
+
module: ts18.ModuleKind.ESNext,
|
|
27010
|
+
moduleResolution: ts18.ModuleResolutionKind.Bundler
|
|
26996
27011
|
});
|
|
26997
|
-
if (
|
|
27012
|
+
if (ts18.getPreEmitDiagnostics(program).length)
|
|
26998
27013
|
throw new Error("PostgREST snapshot has TypeScript errors");
|
|
26999
27014
|
const artifacts = await renderGraphql({
|
|
27000
27015
|
rootDir,
|
|
@@ -27012,11 +27027,11 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
27012
27027
|
};
|
|
27013
27028
|
await addInput(postgrestTypes);
|
|
27014
27029
|
await addInput(drizzleSchema);
|
|
27015
|
-
const drizzleProgram =
|
|
27030
|
+
const drizzleProgram = ts18.createProgram([drizzleSchema], {
|
|
27016
27031
|
noEmit: true,
|
|
27017
|
-
moduleResolution:
|
|
27018
|
-
module:
|
|
27019
|
-
target:
|
|
27032
|
+
moduleResolution: ts18.ModuleResolutionKind.Bundler,
|
|
27033
|
+
module: ts18.ModuleKind.ESNext,
|
|
27034
|
+
target: ts18.ScriptTarget.ES2022,
|
|
27020
27035
|
types: [],
|
|
27021
27036
|
skipLibCheck: true
|
|
27022
27037
|
});
|
|
@@ -27390,7 +27405,6 @@ function readProjectConfig(rootDir) {
|
|
|
27390
27405
|
skipLibCheck: true
|
|
27391
27406
|
},
|
|
27392
27407
|
errors: [],
|
|
27393
|
-
projectReferences: undefined,
|
|
27394
27408
|
configFingerprint: "defaults"
|
|
27395
27409
|
};
|
|
27396
27410
|
}
|
|
@@ -27412,7 +27426,7 @@ function readProjectConfig(rootDir) {
|
|
|
27412
27426
|
return {
|
|
27413
27427
|
options: parsed.options,
|
|
27414
27428
|
errors: parsed.errors,
|
|
27415
|
-
projectReferences: parsed.projectReferences,
|
|
27429
|
+
...parsed.projectReferences === undefined ? {} : { projectReferences: parsed.projectReferences },
|
|
27416
27430
|
configFingerprint: JSON.stringify([...configReads])
|
|
27417
27431
|
};
|
|
27418
27432
|
}
|
|
@@ -30622,7 +30636,7 @@ import { join as join4 } from "node:path";
|
|
|
30622
30636
|
// src/type-safety.ts
|
|
30623
30637
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
30624
30638
|
import { dirname as dirname3, join as join3, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
|
|
30625
|
-
import * as
|
|
30639
|
+
import * as ts10 from "@typescript/typescript6";
|
|
30626
30640
|
|
|
30627
30641
|
// src/sql-safety.ts
|
|
30628
30642
|
import * as ts8 from "@typescript/typescript6";
|
|
@@ -30665,6 +30679,198 @@ function scanDrizzleSql(sourceFile, checker, file, strict) {
|
|
|
30665
30679
|
return diagnostics;
|
|
30666
30680
|
}
|
|
30667
30681
|
|
|
30682
|
+
// src/source-semantics.ts
|
|
30683
|
+
import * as ts9 from "@typescript/typescript6";
|
|
30684
|
+
var SOURCE_SEMANTIC_DIAGNOSTIC_CODES = {
|
|
30685
|
+
"source-unsafe-any": { errorCode: "SC6009", docsUrl: "https://supacloud.dev/errors/SC6009" },
|
|
30686
|
+
"source-floating-promise": { errorCode: "SC6010", docsUrl: "https://supacloud.dev/errors/SC6010" },
|
|
30687
|
+
"source-non-exhaustive-switch": { errorCode: "SC6011", docsUrl: "https://supacloud.dev/errors/SC6011" }
|
|
30688
|
+
};
|
|
30689
|
+
function scanSourceSemantics(source, checker, file, rootDir) {
|
|
30690
|
+
const diagnostics = [];
|
|
30691
|
+
const report = (code, node, message) => {
|
|
30692
|
+
diagnostics.push({
|
|
30693
|
+
severity: "error",
|
|
30694
|
+
code,
|
|
30695
|
+
...SOURCE_SEMANTIC_DIAGNOSTIC_CODES[code],
|
|
30696
|
+
file,
|
|
30697
|
+
message,
|
|
30698
|
+
line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1
|
|
30699
|
+
});
|
|
30700
|
+
};
|
|
30701
|
+
const unsafe = (value, target) => {
|
|
30702
|
+
if (isUnknownBoundary(target, checker) || containsAny(target, checker, new Set, rootDir))
|
|
30703
|
+
return;
|
|
30704
|
+
if (containsAny(checker.getTypeAtLocation(value), checker, new Set, rootDir)) {
|
|
30705
|
+
report("source-unsafe-any", value, "An any-containing value cannot enter a concrete type. Quarantine it as unknown and decode it before use.");
|
|
30706
|
+
}
|
|
30707
|
+
};
|
|
30708
|
+
const declared = (node) => {
|
|
30709
|
+
let hasAnyKeyword = false;
|
|
30710
|
+
const visitType = (child) => {
|
|
30711
|
+
if (child.kind === ts9.SyntaxKind.AnyKeyword)
|
|
30712
|
+
hasAnyKeyword = true;
|
|
30713
|
+
ts9.forEachChild(child, visitType);
|
|
30714
|
+
};
|
|
30715
|
+
visitType(node);
|
|
30716
|
+
if (!hasAnyKeyword && containsAny(checker.getTypeAtLocation(node), checker, new Set, rootDir)) {
|
|
30717
|
+
report("source-unsafe-any", node, "Declared application types must not hide any through aliases or generic arguments.");
|
|
30718
|
+
}
|
|
30719
|
+
};
|
|
30720
|
+
const visit = (node) => {
|
|
30721
|
+
if (ts9.isTypeAliasDeclaration(node))
|
|
30722
|
+
declared(node.type);
|
|
30723
|
+
if ((ts9.isVariableDeclaration(node) || ts9.isParameter(node) || ts9.isPropertyDeclaration(node) || ts9.isPropertySignature(node)) && node.type)
|
|
30724
|
+
declared(node.type);
|
|
30725
|
+
if (ts9.isVariableDeclaration(node) && node.initializer) {
|
|
30726
|
+
const type = checker.getTypeAtLocation(node.name);
|
|
30727
|
+
if (node.type)
|
|
30728
|
+
unsafe(node.initializer, type);
|
|
30729
|
+
else if (ts9.isIdentifier(node.name) && !ts9.isArrowFunction(node.initializer) && !ts9.isFunctionExpression(node.initializer) && !(type.flags & ts9.TypeFlags.Any) && containsAny(type, checker, new Set, rootDir)) {
|
|
30730
|
+
report("source-unsafe-any", node.name, "Inferred values must not contain any, including nested and generic result types.");
|
|
30731
|
+
}
|
|
30732
|
+
}
|
|
30733
|
+
if (ts9.isPropertyDeclaration(node) && !node.type && node.initializer && containsAny(checker.getTypeAtLocation(node.name), checker, new Set, rootDir)) {
|
|
30734
|
+
report("source-unsafe-any", node.name, "Inferred class fields must not propagate any. Decode the value or quarantine it as unknown.");
|
|
30735
|
+
}
|
|
30736
|
+
if ((ts9.isFunctionDeclaration(node) || ts9.isMethodDeclaration(node) || ts9.isArrowFunction(node) || ts9.isFunctionExpression(node)) && !node.type && node.body) {
|
|
30737
|
+
const signature = checker.getSignatureFromDeclaration(node);
|
|
30738
|
+
if (signature && containsAny(checker.getReturnTypeOfSignature(signature), checker, new Set, rootDir)) {
|
|
30739
|
+
report("source-unsafe-any", node.name ?? node, "Inferred function results must not propagate any. Return unknown at the boundary or a decoded concrete result.");
|
|
30740
|
+
}
|
|
30741
|
+
}
|
|
30742
|
+
if (ts9.isFunctionLike(node) && node.type)
|
|
30743
|
+
declared(node.type);
|
|
30744
|
+
if (ts9.isBinaryExpression(node) && node.operatorToken.kind === ts9.SyntaxKind.EqualsToken) {
|
|
30745
|
+
unsafe(node.right, checker.getTypeAtLocation(node.left));
|
|
30746
|
+
}
|
|
30747
|
+
if (ts9.isAsExpression(node) || ts9.isTypeAssertionExpression(node)) {
|
|
30748
|
+
unsafe(node.expression, checker.getTypeAtLocation(node));
|
|
30749
|
+
}
|
|
30750
|
+
if (ts9.isReturnStatement(node) && node.expression) {
|
|
30751
|
+
let owner = node.parent;
|
|
30752
|
+
while (owner && !ts9.isFunctionLike(owner))
|
|
30753
|
+
owner = owner.parent;
|
|
30754
|
+
if (owner && ts9.isFunctionLike(owner) && owner.type) {
|
|
30755
|
+
const signature = checker.getSignatureFromDeclaration(owner);
|
|
30756
|
+
if (signature)
|
|
30757
|
+
unsafe(node.expression, checker.getReturnTypeOfSignature(signature));
|
|
30758
|
+
}
|
|
30759
|
+
}
|
|
30760
|
+
if (ts9.isCallExpression(node)) {
|
|
30761
|
+
const signature = checker.getResolvedSignature(node);
|
|
30762
|
+
const parameters = signature?.getParameters() ?? [];
|
|
30763
|
+
node.arguments.forEach((argument, index) => {
|
|
30764
|
+
const parameter = parameters[index] ?? parameters.at(-1);
|
|
30765
|
+
if (!parameter)
|
|
30766
|
+
return;
|
|
30767
|
+
const type = checker.getTypeOfSymbolAtLocation(parameter, node);
|
|
30768
|
+
const declaration = parameter.valueDeclaration;
|
|
30769
|
+
const rest = declaration && ts9.isParameter(declaration) && declaration.dotDotDotToken;
|
|
30770
|
+
const target = rest ? checker.getIndexTypeOfType(type, ts9.IndexKind.Number) ?? type : type;
|
|
30771
|
+
unsafe(argument, target);
|
|
30772
|
+
});
|
|
30773
|
+
}
|
|
30774
|
+
if (ts9.isExpressionStatement(node)) {
|
|
30775
|
+
const expression = unwrap(node.expression);
|
|
30776
|
+
if (isPromise(checker.getTypeAtLocation(expression), checker, expression) && !handlesRejection(expression, checker)) {
|
|
30777
|
+
report("source-floating-promise", node, "Promise work must be awaited, returned, or have a callable rejection handler. void does not establish cancellation ownership.");
|
|
30778
|
+
}
|
|
30779
|
+
}
|
|
30780
|
+
if (ts9.isSwitchStatement(node)) {
|
|
30781
|
+
const type = checker.getTypeAtLocation(node.expression);
|
|
30782
|
+
const members = type.isUnion() ? type.types : [type];
|
|
30783
|
+
if (members.every(isFiniteLiteral)) {
|
|
30784
|
+
const cases = node.caseBlock.clauses.filter(ts9.isCaseClause);
|
|
30785
|
+
const missing = members.filter((member) => !cases.some((clause) => sameLiteral(member, checker.getTypeAtLocation(clause.expression))));
|
|
30786
|
+
if (missing.length > 0) {
|
|
30787
|
+
report("source-non-exhaustive-switch", node.expression, `Switch is missing cases for ${missing.map((member) => checker.typeToString(member)).join(", ")}. A default branch does not replace explicit union cases.`);
|
|
30788
|
+
}
|
|
30789
|
+
}
|
|
30790
|
+
}
|
|
30791
|
+
ts9.forEachChild(node, visit);
|
|
30792
|
+
};
|
|
30793
|
+
visit(source);
|
|
30794
|
+
return diagnostics;
|
|
30795
|
+
}
|
|
30796
|
+
function containsAny(type, checker, seen, rootDir) {
|
|
30797
|
+
if (type.flags & ts9.TypeFlags.Any)
|
|
30798
|
+
return true;
|
|
30799
|
+
if (seen.has(type))
|
|
30800
|
+
return false;
|
|
30801
|
+
seen.add(type);
|
|
30802
|
+
if (type.isUnionOrIntersection())
|
|
30803
|
+
return type.types.some((part) => containsAny(part, checker, seen, rootDir));
|
|
30804
|
+
const declarations = type.getSymbol()?.declarations ?? [];
|
|
30805
|
+
if (declarations.some((declaration) => ts9.isClassDeclaration(declaration) && (declaration.getSourceFile().isDeclarationFile || declaration.getSourceFile().fileName.replaceAll("\\", "/").includes("/node_modules/"))))
|
|
30806
|
+
return false;
|
|
30807
|
+
const arguments_ = isTypeReference2(type) ? checker.getTypeArguments(type) : type.aliasTypeArguments ?? [];
|
|
30808
|
+
if (arguments_.some((argument) => containsAny(argument, checker, seen, rootDir)))
|
|
30809
|
+
return true;
|
|
30810
|
+
if (checker.getSignaturesOfType(type, ts9.SignatureKind.Call).some((signature) => {
|
|
30811
|
+
const declaration = signature.getDeclaration();
|
|
30812
|
+
return declaration !== undefined && isWithinRoot(declaration.getSourceFile().fileName, rootDir) && (containsAny(checker.getReturnTypeOfSignature(signature), checker, seen, rootDir) || signature.getParameters().some((parameter) => containsAny(checker.getTypeOfSymbolAtLocation(parameter, declaration), checker, seen, rootDir)));
|
|
30813
|
+
}))
|
|
30814
|
+
return true;
|
|
30815
|
+
return checker.getPropertiesOfType(type).some((property) => {
|
|
30816
|
+
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
30817
|
+
return declaration !== undefined && isWithinRoot(declaration.getSourceFile().fileName, rootDir) && containsAny(checker.getTypeOfSymbolAtLocation(property, declaration), checker, seen, rootDir);
|
|
30818
|
+
});
|
|
30819
|
+
}
|
|
30820
|
+
function isWithinRoot(file, rootDir) {
|
|
30821
|
+
const normalizedFile = file.replaceAll("\\", "/");
|
|
30822
|
+
const normalizedRoot = rootDir.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
30823
|
+
return normalizedFile === normalizedRoot || normalizedFile.startsWith(`${normalizedRoot}/`);
|
|
30824
|
+
}
|
|
30825
|
+
function isUnknownBoundary(type, checker) {
|
|
30826
|
+
if (type.flags & (ts9.TypeFlags.Unknown | ts9.TypeFlags.Void))
|
|
30827
|
+
return true;
|
|
30828
|
+
const promised = promiseArgument(type, checker);
|
|
30829
|
+
return promised !== undefined && Boolean(promised.flags & ts9.TypeFlags.Unknown);
|
|
30830
|
+
}
|
|
30831
|
+
function unwrap(expression) {
|
|
30832
|
+
while (ts9.isParenthesizedExpression(expression) || ts9.isVoidExpression(expression))
|
|
30833
|
+
expression = expression.expression;
|
|
30834
|
+
return expression;
|
|
30835
|
+
}
|
|
30836
|
+
function isPromise(type, checker, node) {
|
|
30837
|
+
return type.isUnion() ? type.types.some((part) => isPromise(part, checker, node)) : promiseArgument(type, checker) !== undefined;
|
|
30838
|
+
}
|
|
30839
|
+
function handlesRejection(expression, checker) {
|
|
30840
|
+
if (!ts9.isCallExpression(expression) || !ts9.isPropertyAccessExpression(expression.expression))
|
|
30841
|
+
return false;
|
|
30842
|
+
const { name, expression: receiver } = expression.expression;
|
|
30843
|
+
if (!isPromise(checker.getTypeAtLocation(receiver), checker, receiver))
|
|
30844
|
+
return false;
|
|
30845
|
+
const handler = name.text === "catch" ? expression.arguments[0] : name.text === "then" ? expression.arguments[1] : undefined;
|
|
30846
|
+
return handler !== undefined && checker.getTypeAtLocation(handler).getCallSignatures().length > 0;
|
|
30847
|
+
}
|
|
30848
|
+
function isFiniteLiteral(type) {
|
|
30849
|
+
return Boolean(type.flags & (ts9.TypeFlags.StringLiteral | ts9.TypeFlags.NumberLiteral | ts9.TypeFlags.BigIntLiteral | ts9.TypeFlags.BooleanLiteral | ts9.TypeFlags.Null | ts9.TypeFlags.Undefined));
|
|
30850
|
+
}
|
|
30851
|
+
function sameLiteral(left, right) {
|
|
30852
|
+
if (left.flags !== right.flags)
|
|
30853
|
+
return false;
|
|
30854
|
+
if (left.isStringLiteral() && right.isStringLiteral())
|
|
30855
|
+
return left.value === right.value;
|
|
30856
|
+
if (left.isNumberLiteral() && right.isNumberLiteral())
|
|
30857
|
+
return left.value === right.value;
|
|
30858
|
+
return left === right;
|
|
30859
|
+
}
|
|
30860
|
+
function isTypeReference2(type) {
|
|
30861
|
+
return Boolean(type.flags & ts9.TypeFlags.Object) && "objectFlags" in type && typeof type.objectFlags === "number" && Boolean(type.objectFlags & ts9.ObjectFlags.Reference) && "target" in type;
|
|
30862
|
+
}
|
|
30863
|
+
function promiseArgument(type, checker) {
|
|
30864
|
+
if (type.flags & (ts9.TypeFlags.Any | ts9.TypeFlags.Unknown | ts9.TypeFlags.Never))
|
|
30865
|
+
return;
|
|
30866
|
+
const then = checker.getPropertyOfType(type, "then");
|
|
30867
|
+
const declaration = then?.valueDeclaration ?? then?.declarations?.[0];
|
|
30868
|
+
if (!then || !declaration || checker.getTypeOfSymbolAtLocation(then, declaration).getCallSignatures().length === 0)
|
|
30869
|
+
return;
|
|
30870
|
+
const awaited = checker.getAwaitedType(type);
|
|
30871
|
+
return awaited !== type ? awaited : undefined;
|
|
30872
|
+
}
|
|
30873
|
+
|
|
30668
30874
|
// src/type-safety.ts
|
|
30669
30875
|
var DEFAULT_EXCLUDES = [
|
|
30670
30876
|
"**/*.test.ts",
|
|
@@ -30679,6 +30885,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
30679
30885
|
];
|
|
30680
30886
|
var TYPE_SAFETY_DIAGNOSTIC_CODES = {
|
|
30681
30887
|
...SQL_SAFETY_DIAGNOSTIC_CODES,
|
|
30888
|
+
...SOURCE_SEMANTIC_DIAGNOSTIC_CODES,
|
|
30682
30889
|
"generated-any": { errorCode: "SC6001", docsUrl: "https://supacloud.dev/errors/SC6001" },
|
|
30683
30890
|
"source-any": { errorCode: "SC6002", docsUrl: "https://supacloud.dev/errors/SC6002" },
|
|
30684
30891
|
"source-type-assertion": { errorCode: "SC6003", docsUrl: "https://supacloud.dev/errors/SC6003" },
|
|
@@ -30691,7 +30898,7 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
30691
30898
|
for (const [file, content] of Object.entries(artifacts)) {
|
|
30692
30899
|
if (content === undefined)
|
|
30693
30900
|
continue;
|
|
30694
|
-
const sourceFile =
|
|
30901
|
+
const sourceFile = ts10.createSourceFile(file, content, ts10.ScriptTarget.Latest, true, ts10.ScriptKind.TS);
|
|
30695
30902
|
for (const node of descendantsOfKind2(sourceFile, isAnyKeyword)) {
|
|
30696
30903
|
diagnostics.push(makeDiagnostic("generated-any", `生成产物 ${file} 包含 any;严格生成模式要求使用 unknown、具体接口或泛型约束。`, sourceFile, node, strict));
|
|
30697
30904
|
}
|
|
@@ -30700,36 +30907,58 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
30700
30907
|
}
|
|
30701
30908
|
function scanProductionSource(options) {
|
|
30702
30909
|
const rootDir = resolve3(options.rootDir);
|
|
30703
|
-
const configPath =
|
|
30910
|
+
const configPath = ts10.findConfigFile(rootDir, ts10.sys.fileExists) ?? join3(rootDir, "tsconfig.json");
|
|
30704
30911
|
const projectConfig = existsSync2(configPath) ? readProjectConfig2(configPath) : {
|
|
30705
30912
|
options: {
|
|
30706
30913
|
strict: true,
|
|
30914
|
+
experimentalDecorators: true,
|
|
30707
30915
|
skipLibCheck: true,
|
|
30708
|
-
target:
|
|
30709
|
-
module:
|
|
30710
|
-
moduleResolution:
|
|
30916
|
+
target: ts10.ScriptTarget.ES2022,
|
|
30917
|
+
module: ts10.ModuleKind.ESNext,
|
|
30918
|
+
moduleResolution: ts10.ModuleResolutionKind.Bundler
|
|
30711
30919
|
},
|
|
30712
30920
|
errors: []
|
|
30713
30921
|
};
|
|
30714
30922
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
30715
|
-
const rootNames =
|
|
30716
|
-
const compilerOptions = {
|
|
30717
|
-
|
|
30923
|
+
const rootNames = ts10.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist"], include).filter((file) => isProductionSourcePath(rootDir, file, [...DEFAULT_EXCLUDES, ...options.exclude ?? []]));
|
|
30924
|
+
const compilerOptions = {
|
|
30925
|
+
...projectConfig.options,
|
|
30926
|
+
noCheck: false,
|
|
30927
|
+
strict: true,
|
|
30928
|
+
noImplicitAny: true,
|
|
30929
|
+
strictNullChecks: true,
|
|
30930
|
+
strictFunctionTypes: true,
|
|
30931
|
+
strictBindCallApply: true,
|
|
30932
|
+
strictPropertyInitialization: true,
|
|
30933
|
+
strictBuiltinIteratorReturn: true,
|
|
30934
|
+
noImplicitThis: true,
|
|
30935
|
+
useUnknownInCatchVariables: true,
|
|
30936
|
+
alwaysStrict: true,
|
|
30937
|
+
noUncheckedIndexedAccess: true,
|
|
30938
|
+
exactOptionalPropertyTypes: true,
|
|
30939
|
+
noImplicitOverride: true,
|
|
30940
|
+
noPropertyAccessFromIndexSignature: true,
|
|
30941
|
+
noFallthroughCasesInSwitch: true,
|
|
30942
|
+
forceConsistentCasingInFileNames: true,
|
|
30943
|
+
noEmit: true
|
|
30944
|
+
};
|
|
30945
|
+
const host = ts10.createCompilerHost(compilerOptions);
|
|
30718
30946
|
host.getCurrentDirectory = () => dirname3(configPath);
|
|
30719
|
-
const program =
|
|
30947
|
+
const program = ts10.createProgram(rootNames, compilerOptions, host);
|
|
30720
30948
|
const outDir = options.outDir ? normalizeRelative(rootDir, options.outDir) : undefined;
|
|
30721
30949
|
const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
|
|
30722
30950
|
const sourceFiles = program.getSourceFiles().filter((sourceFile) => isProductionSource(rootDir, sourceFile, excludes, outDir));
|
|
30723
30951
|
const diagnostics = [...projectConfig.errors, ...program.getOptionsDiagnostics()].map((diagnostic) => ({
|
|
30724
30952
|
severity: "error",
|
|
30725
30953
|
code: "source-config",
|
|
30726
|
-
message:
|
|
30954
|
+
message: ts10.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
30727
30955
|
`),
|
|
30728
30956
|
file: diagnostic.file ? normalizeRelative(rootDir, diagnostic.file.fileName) : normalizeRelative(rootDir, configPath),
|
|
30729
30957
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
30730
30958
|
errorCode: `TS${diagnostic.code}`
|
|
30731
30959
|
}));
|
|
30732
30960
|
const checker = program.getTypeChecker();
|
|
30961
|
+
const moduleResolutionCodes = new Set([2307, 2688, 2792]);
|
|
30733
30962
|
for (const diagnostic of [
|
|
30734
30963
|
...program.getGlobalDiagnostics(),
|
|
30735
30964
|
...sourceFiles.flatMap((sourceFile) => [
|
|
@@ -30739,8 +30968,8 @@ function scanProductionSource(options) {
|
|
|
30739
30968
|
]) {
|
|
30740
30969
|
diagnostics.push({
|
|
30741
30970
|
severity: "error",
|
|
30742
|
-
code: "source-typescript",
|
|
30743
|
-
message:
|
|
30971
|
+
code: moduleResolutionCodes.has(diagnostic.code) ? "source-config" : "source-typescript",
|
|
30972
|
+
message: ts10.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
30744
30973
|
`),
|
|
30745
30974
|
...diagnostic.file ? { file: normalizeRelative(rootDir, diagnostic.file.fileName) } : {},
|
|
30746
30975
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
@@ -30749,10 +30978,11 @@ function scanProductionSource(options) {
|
|
|
30749
30978
|
}
|
|
30750
30979
|
for (const sourceFile of sourceFiles) {
|
|
30751
30980
|
scanSourceFile(sourceFile, checker, rootDir, diagnostics, options.strict ?? false);
|
|
30981
|
+
diagnostics.push(...scanSourceSemantics(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), rootDir));
|
|
30752
30982
|
diagnostics.push(...scanDrizzleSql(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), options.strict ?? false));
|
|
30753
|
-
const scanner =
|
|
30754
|
-
for (let kind = scanner.scan();kind !==
|
|
30755
|
-
if ((kind ===
|
|
30983
|
+
const scanner = ts10.createScanner(ts10.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
|
|
30984
|
+
for (let kind = scanner.scan();kind !== ts10.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
|
|
30985
|
+
if ((kind === ts10.SyntaxKind.SingleLineCommentTrivia || kind === ts10.SyntaxKind.MultiLineCommentTrivia) && /@ts-(?:ignore|nocheck|expect-error)\b/.test(scanner.getTokenText())) {
|
|
30756
30986
|
diagnostics.push({
|
|
30757
30987
|
severity: "error",
|
|
30758
30988
|
code: "source-type-suppression",
|
|
@@ -30772,22 +31002,22 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
30772
31002
|
diagnostics.push(makeDiagnostic("source-any", "生产源码使用了显式 any;请改用 unknown、具体接口或泛型约束。", sourceFile, node, strict, rootDir));
|
|
30773
31003
|
}
|
|
30774
31004
|
for (const node of descendants(sourceFile)) {
|
|
30775
|
-
if (
|
|
30776
|
-
if (
|
|
31005
|
+
if (ts10.isAsExpression(node)) {
|
|
31006
|
+
if (ts10.isAsExpression(node.parent) || ts10.isTypeAssertionExpression(node.parent))
|
|
30777
31007
|
continue;
|
|
30778
31008
|
const assertedType = node.type.getText(sourceFile);
|
|
30779
31009
|
if (assertedType === "const")
|
|
30780
31010
|
continue;
|
|
30781
31011
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
30782
|
-
} else if (
|
|
30783
|
-
if (
|
|
31012
|
+
} else if (ts10.isTypeAssertionExpression(node)) {
|
|
31013
|
+
if (ts10.isAsExpression(node.parent) || ts10.isTypeAssertionExpression(node.parent))
|
|
30784
31014
|
continue;
|
|
30785
31015
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
30786
|
-
} else if (
|
|
31016
|
+
} else if (ts10.isNonNullExpression(node)) {
|
|
30787
31017
|
diagnostics.push(makeDiagnostic("source-non-null-assertion", `生产源码包含非空断言 ${node.getText(sourceFile)};请显式处理 null/undefined。`, sourceFile, node, strict, rootDir));
|
|
30788
31018
|
}
|
|
30789
31019
|
}
|
|
30790
|
-
for (const declaration of descendantsOfKind2(sourceFile,
|
|
31020
|
+
for (const declaration of descendantsOfKind2(sourceFile, ts10.isVariableDeclaration)) {
|
|
30791
31021
|
const initializer = declaration.initializer;
|
|
30792
31022
|
if (!initializer || declaration.type)
|
|
30793
31023
|
continue;
|
|
@@ -30803,11 +31033,11 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
30803
31033
|
if (isLetDeclaration(declaration) && isLiteralSyntax(initializer) && !isLiteralType(declarationType)) {
|
|
30804
31034
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `变量 ${declaration.name.getText(sourceFile)} 的字面量类型从 ${checker.typeToString(initializerType, initializer)} 隐式宽化为 ${checker.typeToString(declarationType, declaration)};请补充类型或使用 const。`, sourceFile, declaration, strict, rootDir));
|
|
30805
31035
|
}
|
|
30806
|
-
if (
|
|
31036
|
+
if (ts10.isObjectLiteralExpression(initializer) && isConstDeclaration(declaration) && initializer.getText(sourceFile).length > 0 && initializer.properties.some((property) => ts10.isPropertyAssignment(property) && property.initializer !== undefined && !ts10.isAsExpression(property.initializer) && isLiteralExpression(property.initializer))) {
|
|
30807
31037
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `常量对象 ${declaration.name.getText(sourceFile)} 的字面量属性会隐式宽化;请补充对象类型或使用 as const。`, sourceFile, declaration, strict, rootDir));
|
|
30808
31038
|
}
|
|
30809
31039
|
}
|
|
30810
|
-
for (const parameter of descendantsOfKind2(sourceFile,
|
|
31040
|
+
for (const parameter of descendantsOfKind2(sourceFile, ts10.isParameter)) {
|
|
30811
31041
|
if (parameter.type)
|
|
30812
31042
|
continue;
|
|
30813
31043
|
for (const name of bindingNames(parameter.name)) {
|
|
@@ -30818,10 +31048,10 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
30818
31048
|
}
|
|
30819
31049
|
}
|
|
30820
31050
|
function readProjectConfig2(configPath) {
|
|
30821
|
-
const config =
|
|
31051
|
+
const config = ts10.readConfigFile(configPath, (file) => readFileSync2(file, "utf8"));
|
|
30822
31052
|
if (config.error)
|
|
30823
31053
|
return { options: {}, errors: [config.error] };
|
|
30824
|
-
const parsed =
|
|
31054
|
+
const parsed = ts10.parseJsonConfigFileContent(config.config, ts10.sys, dirname3(configPath));
|
|
30825
31055
|
return { options: parsed.options, errors: parsed.errors };
|
|
30826
31056
|
}
|
|
30827
31057
|
function isProductionSource(rootDir, sourceFile, excludes, outDir) {
|
|
@@ -30841,42 +31071,42 @@ function globMatches(value, pattern) {
|
|
|
30841
31071
|
return new RegExp(`^${escaped}$`).test(value);
|
|
30842
31072
|
}
|
|
30843
31073
|
function bindingNames(name) {
|
|
30844
|
-
if (
|
|
31074
|
+
if (ts10.isIdentifier(name))
|
|
30845
31075
|
return [name];
|
|
30846
|
-
return name.elements.flatMap((element) =>
|
|
31076
|
+
return name.elements.flatMap((element) => ts10.isBindingElement(element) ? bindingNames(element.name) : []);
|
|
30847
31077
|
}
|
|
30848
31078
|
function isLiteralExpression(node) {
|
|
30849
31079
|
if (!node)
|
|
30850
31080
|
return false;
|
|
30851
31081
|
return [
|
|
30852
|
-
|
|
30853
|
-
|
|
30854
|
-
|
|
30855
|
-
|
|
31082
|
+
ts10.SyntaxKind.StringLiteral,
|
|
31083
|
+
ts10.SyntaxKind.NumericLiteral,
|
|
31084
|
+
ts10.SyntaxKind.TrueKeyword,
|
|
31085
|
+
ts10.SyntaxKind.FalseKeyword
|
|
30856
31086
|
].includes(node.kind);
|
|
30857
31087
|
}
|
|
30858
31088
|
function isLiteralSyntax(node) {
|
|
30859
|
-
return
|
|
31089
|
+
return ts10.isStringLiteral(node) || ts10.isNumericLiteral(node) || node.kind === ts10.SyntaxKind.TrueKeyword || node.kind === ts10.SyntaxKind.FalseKeyword;
|
|
30860
31090
|
}
|
|
30861
31091
|
function isLiteralType(type) {
|
|
30862
|
-
return (type.flags & (
|
|
31092
|
+
return (type.flags & (ts10.TypeFlags.StringLiteral | ts10.TypeFlags.NumberLiteral | ts10.TypeFlags.BooleanLiteral | ts10.TypeFlags.BigIntLiteral)) !== 0;
|
|
30863
31093
|
}
|
|
30864
31094
|
function isAnyType(type) {
|
|
30865
|
-
return (type.flags &
|
|
31095
|
+
return (type.flags & ts10.TypeFlags.Any) !== 0;
|
|
30866
31096
|
}
|
|
30867
31097
|
function isLetDeclaration(declaration) {
|
|
30868
|
-
return
|
|
31098
|
+
return ts10.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts10.NodeFlags.Let) !== 0;
|
|
30869
31099
|
}
|
|
30870
31100
|
function isConstDeclaration(declaration) {
|
|
30871
|
-
return
|
|
31101
|
+
return ts10.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts10.NodeFlags.Const) !== 0;
|
|
30872
31102
|
}
|
|
30873
31103
|
function descendants(root) {
|
|
30874
31104
|
const result = [];
|
|
30875
31105
|
const visit = (node) => {
|
|
30876
31106
|
result.push(node);
|
|
30877
|
-
|
|
31107
|
+
ts10.forEachChild(node, visit);
|
|
30878
31108
|
};
|
|
30879
|
-
|
|
31109
|
+
ts10.forEachChild(root, visit);
|
|
30880
31110
|
return result;
|
|
30881
31111
|
}
|
|
30882
31112
|
function descendantsOfKind2(root, predicate) {
|
|
@@ -30884,9 +31114,9 @@ function descendantsOfKind2(root, predicate) {
|
|
|
30884
31114
|
const visit = (node) => {
|
|
30885
31115
|
if (predicate(node))
|
|
30886
31116
|
result.push(node);
|
|
30887
|
-
|
|
31117
|
+
ts10.forEachChild(node, visit);
|
|
30888
31118
|
};
|
|
30889
|
-
|
|
31119
|
+
ts10.forEachChild(root, visit);
|
|
30890
31120
|
return result;
|
|
30891
31121
|
}
|
|
30892
31122
|
function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir) {
|
|
@@ -30894,7 +31124,7 @@ function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir)
|
|
|
30894
31124
|
const file = typeof fileOrSourceFile === "string" ? fileOrSourceFile : rootDir ? normalizeRelative(rootDir, fileOrSourceFile.fileName) : fileOrSourceFile.fileName;
|
|
30895
31125
|
const meta = TYPE_SAFETY_DIAGNOSTIC_CODES[code];
|
|
30896
31126
|
return {
|
|
30897
|
-
severity: strict ? "error" : "warn",
|
|
31127
|
+
severity: strict || code === "source-any" || code === "generated-any" ? "error" : "warn",
|
|
30898
31128
|
code,
|
|
30899
31129
|
message,
|
|
30900
31130
|
file,
|
|
@@ -30907,7 +31137,7 @@ function normalizeRelative(rootDir, filePath) {
|
|
|
30907
31137
|
return relative3(rootDir, filePath).split(sep3).join("/").replace(/^\.\//, "");
|
|
30908
31138
|
}
|
|
30909
31139
|
function isAnyKeyword(node) {
|
|
30910
|
-
return node.kind ===
|
|
31140
|
+
return node.kind === ts10.SyntaxKind.AnyKeyword;
|
|
30911
31141
|
}
|
|
30912
31142
|
|
|
30913
31143
|
// src/compile.ts
|
|
@@ -31068,11 +31298,12 @@ async function compileProject(options) {
|
|
|
31068
31298
|
}, options.strict ?? false));
|
|
31069
31299
|
}
|
|
31070
31300
|
const hasErrors = diagnostics.some((diagnostic) => diagnostic.severity === "error");
|
|
31301
|
+
const hasTypeErrors = diagnostics.some(({ severity, code }) => severity === "error" && (code.startsWith("source-") || code === "generated-any"));
|
|
31071
31302
|
const generatedOptions = {
|
|
31072
31303
|
...options,
|
|
31073
31304
|
...options.cache ? { artifactHashes: options.cache.generatedHashes } : {}
|
|
31074
31305
|
};
|
|
31075
|
-
const written = !hasErrors || options.writeOnError === true ? await writeRenderedApplication(rendered, generatedOptions) : [];
|
|
31306
|
+
const written = !hasErrors || options.writeOnError === true && !hasTypeErrors ? await writeRenderedApplication(rendered, generatedOptions) : [];
|
|
31076
31307
|
if (!hasErrors) {
|
|
31077
31308
|
for (const [filename, content] of Object.entries(graphql.files)) {
|
|
31078
31309
|
const path = join4(options.outDir, filename);
|
|
@@ -31169,8 +31400,8 @@ async function checkProject(options) {
|
|
|
31169
31400
|
}
|
|
31170
31401
|
function resolveTypeSafety(options) {
|
|
31171
31402
|
return {
|
|
31172
|
-
noAnyInGenerated:
|
|
31173
|
-
scanProductionSource:
|
|
31403
|
+
noAnyInGenerated: true,
|
|
31404
|
+
scanProductionSource: true,
|
|
31174
31405
|
...options.typeSafety?.exclude ? { exclude: options.typeSafety.exclude } : {}
|
|
31175
31406
|
};
|
|
31176
31407
|
}
|
|
@@ -31425,7 +31656,7 @@ function formatDeliveryPlan(result) {
|
|
|
31425
31656
|
import { mkdir as mkdir3, mkdtemp, readFile as readFile5, realpath as realpath3, rename as rename3, rm as rm2 } from "node:fs/promises";
|
|
31426
31657
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
31427
31658
|
import { dirname as dirname7, join as join9, relative as relative7, resolve as resolve13, sep as sep7 } from "node:path";
|
|
31428
|
-
import * as
|
|
31659
|
+
import * as ts15 from "@typescript/typescript6";
|
|
31429
31660
|
|
|
31430
31661
|
// src/delivery-build-schema.ts
|
|
31431
31662
|
init_delivery_build_schema();
|
|
@@ -31467,22 +31698,22 @@ init_delivery_files2();
|
|
|
31467
31698
|
import { isBuiltin } from "node:module";
|
|
31468
31699
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
31469
31700
|
import { join as join7, resolve as resolve10 } from "node:path";
|
|
31470
|
-
import * as
|
|
31701
|
+
import * as ts14 from "@typescript/typescript6";
|
|
31471
31702
|
|
|
31472
31703
|
// src/delivery-imports.ts
|
|
31473
|
-
import * as
|
|
31704
|
+
import * as ts13 from "@typescript/typescript6";
|
|
31474
31705
|
function staticDeliveryImports(path, contents) {
|
|
31475
31706
|
if (!/\.[cm]?[jt]sx?$/.test(path))
|
|
31476
31707
|
return contents;
|
|
31477
|
-
const source =
|
|
31708
|
+
const source = ts13.createSourceFile(path, new TextDecoder().decode(contents), ts13.ScriptTarget.Latest, true);
|
|
31478
31709
|
const computed = [];
|
|
31479
31710
|
function scan(node) {
|
|
31480
|
-
if (
|
|
31711
|
+
if (ts13.isCallExpression(node) && (node.expression.kind === ts13.SyntaxKind.ImportKeyword || ts13.isIdentifier(node.expression) && node.expression.text === "require")) {
|
|
31481
31712
|
const argument = node.arguments[0];
|
|
31482
|
-
if (!argument || !
|
|
31713
|
+
if (!argument || !ts13.isStringLiteral(argument) && !ts13.isNoSubstitutionTemplateLiteral(argument))
|
|
31483
31714
|
computed.push(node);
|
|
31484
31715
|
}
|
|
31485
|
-
|
|
31716
|
+
ts13.forEachChild(node, scan);
|
|
31486
31717
|
}
|
|
31487
31718
|
scan(source);
|
|
31488
31719
|
if (computed.length === 0)
|
|
@@ -31490,36 +31721,36 @@ function staticDeliveryImports(path, contents) {
|
|
|
31490
31721
|
const reject = () => {
|
|
31491
31722
|
throw new Error("Computed module loading is not supported in independent delivery bundles.");
|
|
31492
31723
|
};
|
|
31493
|
-
if (!
|
|
31724
|
+
if (!ts13.isExternalModule(source))
|
|
31494
31725
|
return reject();
|
|
31495
|
-
const host =
|
|
31726
|
+
const host = ts13.createCompilerHost({ noLib: true, noResolve: true, allowJs: true });
|
|
31496
31727
|
host.getSourceFile = (name) => name === path ? source : undefined;
|
|
31497
|
-
const checker =
|
|
31728
|
+
const checker = ts13.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, host).getTypeChecker();
|
|
31498
31729
|
const replacements = new Map;
|
|
31499
31730
|
const removed = new Set;
|
|
31500
31731
|
for (const call of computed) {
|
|
31501
31732
|
let visit = function(node) {
|
|
31502
|
-
const referenced =
|
|
31503
|
-
if (
|
|
31733
|
+
const referenced = ts13.isIdentifier(node) ? ts13.isShorthandPropertyAssignment(node.parent) ? checker.getShorthandAssignmentValueSymbol(node.parent) : ts13.isExportSpecifier(node.parent) ? checker.getExportSpecifierLocalTargetSymbol(node.parent) : checker.getSymbolAtLocation(node) : undefined;
|
|
31734
|
+
if (ts13.isIdentifier(node) && node !== declarationName && referenced === symbol) {
|
|
31504
31735
|
const use = node.parent;
|
|
31505
|
-
if (!
|
|
31736
|
+
if (!ts13.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
|
|
31506
31737
|
return reject();
|
|
31507
31738
|
const value = use.arguments[0];
|
|
31508
|
-
if (!value || !
|
|
31739
|
+
if (!value || !ts13.isStringLiteral(value) && !ts13.isNoSubstitutionTemplateLiteral(value))
|
|
31509
31740
|
return reject();
|
|
31510
31741
|
references++;
|
|
31511
|
-
replacements.set(use,
|
|
31742
|
+
replacements.set(use, ts13.factory.createCallExpression(call.expression, undefined, [value]));
|
|
31512
31743
|
}
|
|
31513
|
-
|
|
31744
|
+
ts13.forEachChild(node, visit);
|
|
31514
31745
|
};
|
|
31515
31746
|
const statement = call.parent;
|
|
31516
31747
|
const block = statement.parent;
|
|
31517
31748
|
const declaration = block.parent;
|
|
31518
|
-
if (call.expression.kind !==
|
|
31749
|
+
if (call.expression.kind !== ts13.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts13.isReturnStatement(statement) || !ts13.isBlock(block) || block.statements.length !== 1 || !ts13.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
|
|
31519
31750
|
return reject();
|
|
31520
31751
|
const parameter = declaration.parameters[0];
|
|
31521
31752
|
const argument = call.arguments[0];
|
|
31522
|
-
if (!parameter || !
|
|
31753
|
+
if (!parameter || !ts13.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts13.isIdentifier(argument) || checker.getSymbolAtLocation(argument) !== checker.getSymbolAtLocation(parameter.name))
|
|
31523
31754
|
return reject();
|
|
31524
31755
|
const symbol = checker.getSymbolAtLocation(declaration.name);
|
|
31525
31756
|
if (!symbol || symbol.declarations?.length !== 1)
|
|
@@ -31531,22 +31762,22 @@ function staticDeliveryImports(path, contents) {
|
|
|
31531
31762
|
return reject();
|
|
31532
31763
|
removed.add(declaration);
|
|
31533
31764
|
}
|
|
31534
|
-
const transformed =
|
|
31765
|
+
const transformed = ts13.transform(source, [(context) => {
|
|
31535
31766
|
const visit = (node) => {
|
|
31536
|
-
if (
|
|
31767
|
+
if (ts13.isFunctionDeclaration(node) && removed.has(node))
|
|
31537
31768
|
return;
|
|
31538
|
-
const replacement =
|
|
31769
|
+
const replacement = ts13.isCallExpression(node) ? replacements.get(node) : undefined;
|
|
31539
31770
|
if (replacement)
|
|
31540
31771
|
return replacement;
|
|
31541
|
-
return
|
|
31772
|
+
return ts13.visitEachChild(node, visit, context);
|
|
31542
31773
|
};
|
|
31543
|
-
return (node) =>
|
|
31774
|
+
return (node) => ts13.visitNode(node, visit, ts13.isSourceFile) ?? node;
|
|
31544
31775
|
}]);
|
|
31545
31776
|
try {
|
|
31546
31777
|
const transformedSource = transformed.transformed[0];
|
|
31547
31778
|
if (!transformedSource)
|
|
31548
31779
|
return reject();
|
|
31549
|
-
return new TextEncoder().encode(
|
|
31780
|
+
return new TextEncoder().encode(ts13.createPrinter().printFile(transformedSource));
|
|
31550
31781
|
} finally {
|
|
31551
31782
|
transformed.dispose();
|
|
31552
31783
|
}
|
|
@@ -31694,16 +31925,16 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
31694
31925
|
const bytes = new Uint8Array(await output.arrayBuffer());
|
|
31695
31926
|
if (/\.[cm]?js$/.test(path)) {
|
|
31696
31927
|
let check = function(node) {
|
|
31697
|
-
const specifier =
|
|
31698
|
-
if (specifier &&
|
|
31928
|
+
const specifier = ts14.isImportDeclaration(node) || ts14.isExportDeclaration(node) ? node.moduleSpecifier : ts14.isCallExpression(node) && (node.expression.kind === ts14.SyntaxKind.ImportKeyword || ts14.isIdentifier(node.expression) && /^(?:__)?require$/.test(node.expression.text) || ts14.isPropertyAccessExpression(node.expression) && node.expression.name.text === "require" && ts14.isMetaProperty(node.expression.expression) && node.expression.expression.keywordToken === ts14.SyntaxKind.ImportKeyword) ? node.arguments[0] : undefined;
|
|
31929
|
+
if (specifier && ts14.isStringLiteralLike(specifier)) {
|
|
31699
31930
|
if (!isBuiltin(specifier.text) && specifier.text !== "bun" && !specifier.text.startsWith("bun:")) {
|
|
31700
31931
|
throw new Error("Independent bundles cannot retain external package imports.");
|
|
31701
31932
|
}
|
|
31702
31933
|
runtimeImports.add(specifier.text);
|
|
31703
31934
|
}
|
|
31704
|
-
|
|
31935
|
+
ts14.forEachChild(node, check);
|
|
31705
31936
|
};
|
|
31706
|
-
const source =
|
|
31937
|
+
const source = ts14.createSourceFile(path, new TextDecoder().decode(bytes), ts14.ScriptTarget.Latest, true);
|
|
31707
31938
|
check(source);
|
|
31708
31939
|
}
|
|
31709
31940
|
files.set(`bundle/${path}`, bytes);
|
|
@@ -31722,16 +31953,16 @@ function renderDeliveryRuntimeIdentity() {
|
|
|
31722
31953
|
return `
|
|
31723
31954
|
function deliveryRuntimeIdentity(kind: "http" | "worker") {
|
|
31724
31955
|
const env = deliveryProcess.env;
|
|
31725
|
-
if (env
|
|
31956
|
+
if (env["SUPACLOUD_ACTIVATION_ID"] === undefined) return null;
|
|
31726
31957
|
const identity = {
|
|
31727
31958
|
schema: "supacloud.application-runtime.v1",
|
|
31728
|
-
project_ref: env
|
|
31729
|
-
application_id: env
|
|
31730
|
-
environment_id: env
|
|
31731
|
-
release_id: env
|
|
31732
|
-
activation_id: env
|
|
31733
|
-
target: env
|
|
31734
|
-
object_id: env
|
|
31959
|
+
project_ref: env["SUPACLOUD_PROJECT_REF"],
|
|
31960
|
+
application_id: env["SUPACLOUD_APPLICATION_ID"],
|
|
31961
|
+
environment_id: env["SUPACLOUD_ENVIRONMENT_ID"],
|
|
31962
|
+
release_id: env["SUPACLOUD_RELEASE_ID"],
|
|
31963
|
+
activation_id: env["SUPACLOUD_ACTIVATION_ID"],
|
|
31964
|
+
target: env["SUPACLOUD_TARGET"],
|
|
31965
|
+
object_id: env["SUPACLOUD_OBJECT_ID"],
|
|
31735
31966
|
kind, pid: deliveryProcess.pid,
|
|
31736
31967
|
};
|
|
31737
31968
|
const matches = (value: string | undefined, pattern: RegExp) => typeof value === "string" && pattern.test(value);
|
|
@@ -31764,8 +31995,8 @@ interface DeliveryHttpHost {
|
|
|
31764
31995
|
|
|
31765
31996
|
async function startDeliveryHttp(signal: AbortSignal, shutdownTimeout: number, startDeadline: () => void) {
|
|
31766
31997
|
const identity = deliveryRuntimeIdentity("http");
|
|
31767
|
-
const port = Number(deliveryProcess.env
|
|
31768
|
-
const hostname = deliveryProcess.env
|
|
31998
|
+
const port = Number(deliveryProcess.env["PORT"] ?? "3000");
|
|
31999
|
+
const hostname = deliveryProcess.env["HOST"] ?? "127.0.0.1";
|
|
31769
32000
|
if (!Number.isInteger(port) || port < 0 || port > 65535 || hostname.length === 0) {
|
|
31770
32001
|
throw new Error("Invalid delivery HTTP listener configuration.");
|
|
31771
32002
|
}
|
|
@@ -31833,7 +32064,7 @@ async function startDeliveryHttp(signal: AbortSignal, shutdownTimeout: number, s
|
|
|
31833
32064
|
|
|
31834
32065
|
{
|
|
31835
32066
|
const lifecycle = new AbortController();
|
|
31836
|
-
const shutdownTimeout = Number(deliveryProcess.env
|
|
32067
|
+
const shutdownTimeout = Number(deliveryProcess.env["SHUTDOWN_TIMEOUT_MS"] ?? "10000");
|
|
31837
32068
|
let running: Awaited<ReturnType<typeof startDeliveryHttp>>;
|
|
31838
32069
|
let deadline: ReturnType<typeof setTimeout> | undefined;
|
|
31839
32070
|
const finish = (failed: boolean) => {
|
|
@@ -31901,7 +32132,7 @@ interface DeliveryWorkerHost {
|
|
|
31901
32132
|
|
|
31902
32133
|
{
|
|
31903
32134
|
const lifecycle = new AbortController();
|
|
31904
|
-
const shutdownTimeout = Number(deliveryProcess.env
|
|
32135
|
+
const shutdownTimeout = Number(deliveryProcess.env["SHUTDOWN_TIMEOUT_MS"] ?? "10000");
|
|
31905
32136
|
let host: DeliveryWorkerHost | undefined;
|
|
31906
32137
|
let running = false;
|
|
31907
32138
|
let runtimeFailed = false;
|
|
@@ -31969,7 +32200,7 @@ interface DeliveryWorkerHost {
|
|
|
31969
32200
|
const candidate = await createHost(createCompiledModules(), { signal: lifecycle.signal });
|
|
31970
32201
|
if (!candidate || typeof candidate.close !== "function") throw new Error("Invalid delivery worker host.");
|
|
31971
32202
|
host = candidate;
|
|
31972
|
-
const execution = deliveryProcess.env
|
|
32203
|
+
const execution = deliveryProcess.env["SUPACLOUD_WORKER_EXECUTION"];
|
|
31973
32204
|
if (execution) {
|
|
31974
32205
|
const expected: unknown = JSON.parse(Buffer.from(execution, "base64").toString("utf8"));
|
|
31975
32206
|
if (!deliveryPolicyEqual(host.execution, expected) || typeof host.health !== "function" || !host.failure) {
|
|
@@ -32073,7 +32304,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
32073
32304
|
const settings = parseDeliveryOptions(delivery);
|
|
32074
32305
|
if (typeof Bun === "undefined")
|
|
32075
32306
|
throw new Error("Independent delivery builds require Bun.");
|
|
32076
|
-
const configPath =
|
|
32307
|
+
const configPath = ts15.findConfigFile(resolve13(options.rootDir), ts15.sys.fileExists);
|
|
32077
32308
|
if (!configPath)
|
|
32078
32309
|
throw new Error("Independent delivery builds require a project tsconfig.json.");
|
|
32079
32310
|
const lexicalProject = dirname7(configPath);
|
|
@@ -32089,8 +32320,8 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
32089
32320
|
if (inside(generatedRoot, sourceRoot))
|
|
32090
32321
|
throw new Error("Output must not contain the application source root.");
|
|
32091
32322
|
const configInputs = new Map;
|
|
32092
|
-
const parsedConfig =
|
|
32093
|
-
...
|
|
32323
|
+
const parsedConfig = ts15.getParsedCommandLineOfConfigFile(await realpath3(configPath), {}, {
|
|
32324
|
+
...ts15.sys,
|
|
32094
32325
|
readFile(path) {
|
|
32095
32326
|
const contents = readFileSync3(path, "utf8");
|
|
32096
32327
|
configInputs.set(resolve13(path), digest(contents));
|
|
@@ -32210,7 +32441,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
32210
32441
|
for (const [name, contents] of Object.entries(generated))
|
|
32211
32442
|
await writeArtifact(stage, `generated/${name}`, contents);
|
|
32212
32443
|
{
|
|
32213
|
-
const program =
|
|
32444
|
+
const program = ts15.createProgram({
|
|
32214
32445
|
rootNames: [
|
|
32215
32446
|
...parsedConfig.fileNames.filter((path) => !inside(generatedRoot, path)),
|
|
32216
32447
|
...Object.keys(generated).map((name) => join9(stage, "generated", name))
|
|
@@ -32218,12 +32449,12 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
32218
32449
|
options: { ...parsedConfig.options, rootDir: project },
|
|
32219
32450
|
...parsedConfig.projectReferences ? { projectReferences: parsedConfig.projectReferences } : {}
|
|
32220
32451
|
});
|
|
32221
|
-
const diagnostics =
|
|
32222
|
-
if (diagnostics.some((item) => item.category ===
|
|
32223
|
-
return failed(diagnostics.filter((item) => item.category ===
|
|
32452
|
+
const diagnostics = ts15.getPreEmitDiagnostics(program);
|
|
32453
|
+
if (diagnostics.some((item) => item.category === ts15.DiagnosticCategory.Error)) {
|
|
32454
|
+
return failed(diagnostics.filter((item) => item.category === ts15.DiagnosticCategory.Error).map((item) => ({
|
|
32224
32455
|
severity: "error",
|
|
32225
32456
|
code: "delivery-generated-type-error",
|
|
32226
|
-
message:
|
|
32457
|
+
message: ts15.flattenDiagnosticMessageText(item.messageText, `
|
|
32227
32458
|
`),
|
|
32228
32459
|
...item.file ? { file: item.file.fileName } : {}
|
|
32229
32460
|
})));
|
|
@@ -32618,19 +32849,7 @@ function createIncrementalCompiler() {
|
|
|
32618
32849
|
const snapshot = !options.graphql && changedPaths && previousSnapshot && previousSnapshot.optionsKey === optionsKey ? await updateSnapshot(previousSnapshot, options, changedPaths) : await createSnapshot(options);
|
|
32619
32850
|
const changedFiles = changedPaths && previousSnapshot ? diffFiles(previousSnapshot.files, snapshot.files) : diffFiles(previousSnapshot?.files, snapshot.files);
|
|
32620
32851
|
const activeCache = options.cache ?? cache;
|
|
32621
|
-
const cacheHit = Boolean(previousSnapshot && previousSnapshot.optionsKey === snapshot.optionsKey && previousCache === activeCache && changedFiles.length === 0)
|
|
32622
|
-
if (cacheHit && previousResult) {
|
|
32623
|
-
return {
|
|
32624
|
-
...previousResult,
|
|
32625
|
-
stats: {
|
|
32626
|
-
cacheHit: true,
|
|
32627
|
-
changedFiles: [],
|
|
32628
|
-
affectedModules: [],
|
|
32629
|
-
reusedModules: previousResult.graph.modules.map((m) => m.name),
|
|
32630
|
-
reanalyzedModules: []
|
|
32631
|
-
}
|
|
32632
|
-
};
|
|
32633
|
-
}
|
|
32852
|
+
const cacheHit = Boolean(previousSnapshot && previousSnapshot.optionsKey === snapshot.optionsKey && previousCache === activeCache && changedFiles.length === 0);
|
|
32634
32853
|
if (!activeCache.dependencyGraph && previousResult) {
|
|
32635
32854
|
activeCache.dependencyGraph = new ModuleDependencyGraph(previousResult.graph.modules);
|
|
32636
32855
|
}
|
|
@@ -32646,7 +32865,7 @@ function createIncrementalCompiler() {
|
|
|
32646
32865
|
activeCache.dependencyGraph = new ModuleDependencyGraph(result.graph.modules);
|
|
32647
32866
|
}
|
|
32648
32867
|
const stats = {
|
|
32649
|
-
cacheHit:
|
|
32868
|
+
cacheHit: cacheHit && !result.diagnostics.some(({ severity }) => severity === "error"),
|
|
32650
32869
|
changedFiles,
|
|
32651
32870
|
affectedModules,
|
|
32652
32871
|
reusedModules,
|
|
@@ -33044,7 +33263,7 @@ function watchProject(options) {
|
|
|
33044
33263
|
// src/migrations.ts
|
|
33045
33264
|
import { rename as rename5, readFile as readFile9, writeFile as writeFile4, rm as rm3 } from "node:fs/promises";
|
|
33046
33265
|
import { relative as relative11, resolve as resolve18 } from "node:path";
|
|
33047
|
-
import * as
|
|
33266
|
+
import * as ts17 from "@typescript/typescript6";
|
|
33048
33267
|
|
|
33049
33268
|
// src/migration-policy.ts
|
|
33050
33269
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
@@ -33052,7 +33271,7 @@ import { readFileSync as readFileSync4 } from "node:fs";
|
|
|
33052
33271
|
import { resolve as resolve17 } from "node:path";
|
|
33053
33272
|
|
|
33054
33273
|
// src/migration-app-version.ts
|
|
33055
|
-
var MIGRATION_APP_VERSION = "0.
|
|
33274
|
+
var MIGRATION_APP_VERSION = "0.25.0";
|
|
33056
33275
|
|
|
33057
33276
|
// src/migration-elysia-version.ts
|
|
33058
33277
|
var MIGRATION_ELYSIA_VERSION = "0.29.0";
|
|
@@ -33096,29 +33315,29 @@ async function checkMigrationDependencies(rootDir) {
|
|
|
33096
33315
|
// src/migrations.ts
|
|
33097
33316
|
var ROUTE_DECORATORS2 = new Set(["Get", "Post", "Put", "Patch", "Delete", "Head", "Options"]);
|
|
33098
33317
|
var MIGRATION_COMPILER_OPTIONS = {
|
|
33099
|
-
target:
|
|
33100
|
-
module:
|
|
33101
|
-
moduleResolution:
|
|
33318
|
+
target: ts17.ScriptTarget.ES2022,
|
|
33319
|
+
module: ts17.ModuleKind.ESNext,
|
|
33320
|
+
moduleResolution: ts17.ModuleResolutionKind.Bundler,
|
|
33102
33321
|
noEmit: true,
|
|
33103
33322
|
skipLibCheck: true
|
|
33104
33323
|
};
|
|
33105
33324
|
function migrationCompilerOptions(rootDir) {
|
|
33106
33325
|
if (!rootDir)
|
|
33107
33326
|
return MIGRATION_COMPILER_OPTIONS;
|
|
33108
|
-
const configPath =
|
|
33327
|
+
const configPath = ts17.findConfigFile(rootDir, ts17.sys.fileExists);
|
|
33109
33328
|
if (!configPath)
|
|
33110
33329
|
return MIGRATION_COMPILER_OPTIONS;
|
|
33111
33330
|
const configHost = {
|
|
33112
|
-
...
|
|
33331
|
+
...ts17.sys,
|
|
33113
33332
|
onUnRecoverableConfigFileDiagnostic: (_diagnostic) => {}
|
|
33114
33333
|
};
|
|
33115
|
-
const parsed =
|
|
33334
|
+
const parsed = ts17.getParsedCommandLineOfConfigFile(configPath, {}, configHost);
|
|
33116
33335
|
if (!parsed || parsed.errors.length > 0)
|
|
33117
33336
|
return MIGRATION_COMPILER_OPTIONS;
|
|
33118
33337
|
return { ...parsed.options, noEmit: true, skipLibCheck: true };
|
|
33119
33338
|
}
|
|
33120
33339
|
function propertyName2(property) {
|
|
33121
|
-
if (
|
|
33340
|
+
if (ts17.isIdentifier(property) || ts17.isStringLiteral(property) || ts17.isNumericLiteral(property))
|
|
33122
33341
|
return property.text;
|
|
33123
33342
|
return;
|
|
33124
33343
|
}
|
|
@@ -33128,7 +33347,7 @@ function lineOf2(sourceFile, node) {
|
|
|
33128
33347
|
function resolveSymbol(symbol, checker) {
|
|
33129
33348
|
if (!symbol)
|
|
33130
33349
|
return;
|
|
33131
|
-
for (let guard = 0;guard < 4 && (symbol.flags &
|
|
33350
|
+
for (let guard = 0;guard < 4 && (symbol.flags & ts17.SymbolFlags.Alias) !== 0; guard += 1) {
|
|
33132
33351
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
33133
33352
|
if (aliased === symbol)
|
|
33134
33353
|
break;
|
|
@@ -33137,12 +33356,12 @@ function resolveSymbol(symbol, checker) {
|
|
|
33137
33356
|
return symbol;
|
|
33138
33357
|
}
|
|
33139
33358
|
function symbolForExpression(expression, checker) {
|
|
33140
|
-
const location =
|
|
33359
|
+
const location = ts17.isIdentifier(expression) ? expression : ts17.isPropertyAccessExpression(expression) ? expression.name : ts17.isElementAccessExpression(expression) && expression.argumentExpression && ts17.isStringLiteral(expression.argumentExpression) ? expression : undefined;
|
|
33141
33360
|
return location ? resolveSymbol(checker.getSymbolAtLocation(location), checker) : undefined;
|
|
33142
33361
|
}
|
|
33143
33362
|
function unwrapExpression(expression) {
|
|
33144
33363
|
let current = expression;
|
|
33145
|
-
while (
|
|
33364
|
+
while (ts17.isAsExpression(current) || ts17.isSatisfiesExpression(current) || ts17.isParenthesizedExpression(current) || ts17.isTypeAssertionExpression(current)) {
|
|
33146
33365
|
current = current.expression;
|
|
33147
33366
|
}
|
|
33148
33367
|
return current;
|
|
@@ -33157,7 +33376,7 @@ function isRouteDecoratorCall(node, checker) {
|
|
|
33157
33376
|
if (node.arguments.length < 2)
|
|
33158
33377
|
return false;
|
|
33159
33378
|
const name = node.expression.getText(node.getSourceFile());
|
|
33160
|
-
if (
|
|
33379
|
+
if (ts17.isIdentifier(node.expression) && ROUTE_DECORATORS2.has(node.expression.text))
|
|
33161
33380
|
return true;
|
|
33162
33381
|
if (ROUTE_DECORATORS2.has(name))
|
|
33163
33382
|
return true;
|
|
@@ -33171,14 +33390,14 @@ function resolveStaticObjectLiteral2(input, checker, seen = new Set) {
|
|
|
33171
33390
|
if (seen.has(expression))
|
|
33172
33391
|
return;
|
|
33173
33392
|
seen.add(expression);
|
|
33174
|
-
if (
|
|
33393
|
+
if (ts17.isObjectLiteralExpression(expression))
|
|
33175
33394
|
return expression;
|
|
33176
|
-
if (
|
|
33395
|
+
if (ts17.isCallExpression(expression) && isDefineRouteContractCall(expression, checker)) {
|
|
33177
33396
|
return resolveStaticObjectLiteral2(expression.arguments[0], checker, seen);
|
|
33178
33397
|
}
|
|
33179
33398
|
const symbol = symbolForExpression(expression, checker);
|
|
33180
33399
|
for (const declaration of symbol?.declarations ?? []) {
|
|
33181
|
-
if (
|
|
33400
|
+
if (ts17.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
33182
33401
|
const resolved = resolveStaticObjectLiteral2(declaration.initializer, checker, seen);
|
|
33183
33402
|
if (resolved)
|
|
33184
33403
|
return resolved;
|
|
@@ -33192,7 +33411,7 @@ function displayFile(rootDir, fileName) {
|
|
|
33192
33411
|
}
|
|
33193
33412
|
function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
33194
33413
|
const compilerOptions = migrationCompilerOptions(rootDir);
|
|
33195
|
-
const host =
|
|
33414
|
+
const host = ts17.createCompilerHost(compilerOptions);
|
|
33196
33415
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
33197
33416
|
const fileExists = host.fileExists.bind(host);
|
|
33198
33417
|
const readFile = host.readFile.bind(host);
|
|
@@ -33201,16 +33420,16 @@ function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
|
33201
33420
|
host.readFile = (fileName) => sourceOverrides.get(resolve18(fileName)) ?? readFile(fileName);
|
|
33202
33421
|
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
33203
33422
|
const source = sourceOverrides.get(resolve18(fileName));
|
|
33204
|
-
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) :
|
|
33423
|
+
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts17.createSourceFile(fileName, source, languageVersion, true);
|
|
33205
33424
|
};
|
|
33206
33425
|
host.getCurrentDirectory = () => rootDir ?? currentDirectory();
|
|
33207
|
-
return
|
|
33426
|
+
return ts17.createProgram(fileNames, compilerOptions, host);
|
|
33208
33427
|
}
|
|
33209
33428
|
function routeResponseProperties(object) {
|
|
33210
|
-
const responseProperties = object.properties.filter((property) =>
|
|
33429
|
+
const responseProperties = object.properties.filter((property) => ts17.isPropertyAssignment(property) && propertyName2(property.name) === "response");
|
|
33211
33430
|
return {
|
|
33212
33431
|
response: responseProperties[0],
|
|
33213
|
-
hasResponses: object.properties.some((property) => (
|
|
33432
|
+
hasResponses: object.properties.some((property) => (ts17.isPropertyAssignment(property) || ts17.isShorthandPropertyAssignment(property)) && propertyName2(property.name) === "responses"),
|
|
33214
33433
|
duplicateResponse: responseProperties.length > 1
|
|
33215
33434
|
};
|
|
33216
33435
|
}
|
|
@@ -33230,7 +33449,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
33230
33449
|
if (!includedFiles.has(sourcePath))
|
|
33231
33450
|
continue;
|
|
33232
33451
|
const visit = (node) => {
|
|
33233
|
-
if (
|
|
33452
|
+
if (ts17.isCallExpression(node) && isRouteDecoratorCall(node, checker)) {
|
|
33234
33453
|
const options = node.arguments[1];
|
|
33235
33454
|
const object = options && resolveStaticObjectLiteral2(options, checker);
|
|
33236
33455
|
if (object) {
|
|
@@ -33250,7 +33469,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
33250
33469
|
}
|
|
33251
33470
|
}
|
|
33252
33471
|
}
|
|
33253
|
-
|
|
33472
|
+
ts17.forEachChild(node, visit);
|
|
33254
33473
|
};
|
|
33255
33474
|
visit(sourceFile);
|
|
33256
33475
|
}
|
|
@@ -33417,7 +33636,7 @@ async function migrateProject(options) {
|
|
|
33417
33636
|
}
|
|
33418
33637
|
}
|
|
33419
33638
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
33420
|
-
const files =
|
|
33639
|
+
const files = ts17.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist", "generated"], include).sort();
|
|
33421
33640
|
const results = [];
|
|
33422
33641
|
const issues = [];
|
|
33423
33642
|
const pendingWrites = new Map;
|
|
@@ -33560,30 +33779,30 @@ function resolveSchema(value, document, seen = new Set) {
|
|
|
33560
33779
|
const schema = recordValue(value);
|
|
33561
33780
|
if (!schema)
|
|
33562
33781
|
return;
|
|
33563
|
-
const ref = stringValue(schema
|
|
33782
|
+
const ref = stringValue(schema["$ref"]);
|
|
33564
33783
|
if (!ref || !ref.startsWith("#/components/schemas/"))
|
|
33565
33784
|
return schema;
|
|
33566
33785
|
if (seen.has(ref))
|
|
33567
33786
|
return schema;
|
|
33568
33787
|
const name = decodeJsonPointerPart(ref.slice("#/components/schemas/".length));
|
|
33569
|
-
const components = recordValue(document
|
|
33570
|
-
const schemas = recordValue(components?.schemas);
|
|
33788
|
+
const components = recordValue(document["components"]);
|
|
33789
|
+
const schemas = recordValue(components?.["schemas"]);
|
|
33571
33790
|
const target = schemas?.[name];
|
|
33572
33791
|
if (target === undefined)
|
|
33573
33792
|
return schema;
|
|
33574
33793
|
return resolveSchema(target, document, new Set([...seen, ref]));
|
|
33575
33794
|
}
|
|
33576
33795
|
function schemaEnum(value) {
|
|
33577
|
-
return Array.isArray(value?.enum) ? value
|
|
33796
|
+
return Array.isArray(value?.["enum"]) ? value["enum"] : undefined;
|
|
33578
33797
|
}
|
|
33579
33798
|
function schemaProperties(value) {
|
|
33580
|
-
return recordValue(value?.properties);
|
|
33799
|
+
return recordValue(value?.["properties"]);
|
|
33581
33800
|
}
|
|
33582
33801
|
function schemaRequired(value) {
|
|
33583
|
-
return new Set(arrayValue(value?.required).filter((item) => typeof item === "string"));
|
|
33802
|
+
return new Set(arrayValue(value?.["required"]).filter((item) => typeof item === "string"));
|
|
33584
33803
|
}
|
|
33585
33804
|
function schemaType(value) {
|
|
33586
|
-
return value?.type;
|
|
33805
|
+
return value?.["type"];
|
|
33587
33806
|
}
|
|
33588
33807
|
function addChange(changes, change) {
|
|
33589
33808
|
if (changes.some((item) => item.kind === change.kind && item.code === change.code && item.path === change.path && item.message === change.message))
|
|
@@ -33627,7 +33846,7 @@ function compareSchema(baseValue, currentValue, baseDocument, currentDocument, p
|
|
|
33627
33846
|
if (baseProperties && currentProperties) {
|
|
33628
33847
|
for (const name of sortedKeys2(baseProperties)) {
|
|
33629
33848
|
if (currentProperties[name] === undefined) {
|
|
33630
|
-
const inputRemovalIsBreaking = baseSchema
|
|
33849
|
+
const inputRemovalIsBreaking = baseSchema["additionalProperties"] === false;
|
|
33631
33850
|
if (direction === "output" || inputRemovalIsBreaking) {
|
|
33632
33851
|
addChange(changes, {
|
|
33633
33852
|
kind: "breaking",
|
|
@@ -33654,7 +33873,7 @@ function compareSchema(baseValue, currentValue, baseDocument, currentDocument, p
|
|
|
33654
33873
|
});
|
|
33655
33874
|
}
|
|
33656
33875
|
}
|
|
33657
|
-
if (baseSchema
|
|
33876
|
+
if (baseSchema["additionalProperties"] !== false && currentSchema["additionalProperties"] === false) {
|
|
33658
33877
|
addChange(changes, {
|
|
33659
33878
|
kind: "breaking",
|
|
33660
33879
|
code: "request-additional-properties-rejected",
|
|
@@ -33677,13 +33896,13 @@ function compareSchema(baseValue, currentValue, baseDocument, currentDocument, p
|
|
|
33677
33896
|
}
|
|
33678
33897
|
function parameterKey(value) {
|
|
33679
33898
|
const parameter = recordValue(value);
|
|
33680
|
-
const name = stringValue(parameter?.name);
|
|
33681
|
-
const location = stringValue(parameter?.in);
|
|
33899
|
+
const name = stringValue(parameter?.["name"]);
|
|
33900
|
+
const location = stringValue(parameter?.["in"]);
|
|
33682
33901
|
return name && location ? `${location}:${name}` : undefined;
|
|
33683
33902
|
}
|
|
33684
33903
|
function operationParameters(pathItem, operation) {
|
|
33685
33904
|
const result = new Map;
|
|
33686
|
-
for (const source of [pathItem
|
|
33905
|
+
for (const source of [pathItem["parameters"], operation["parameters"]]) {
|
|
33687
33906
|
for (const item of arrayValue(source)) {
|
|
33688
33907
|
const parameter = recordValue(item);
|
|
33689
33908
|
const key = parameterKey(parameter);
|
|
@@ -33694,7 +33913,7 @@ function operationParameters(pathItem, operation) {
|
|
|
33694
33913
|
return result;
|
|
33695
33914
|
}
|
|
33696
33915
|
function parameterSchema(value) {
|
|
33697
|
-
return value
|
|
33916
|
+
return value["schema"];
|
|
33698
33917
|
}
|
|
33699
33918
|
function compareParameters(basePathItem, currentPathItem, baseOperation, currentOperation, baseDocument, currentDocument, path, changes) {
|
|
33700
33919
|
const baseParameters = operationParameters(basePathItem, baseOperation);
|
|
@@ -33711,7 +33930,7 @@ function compareParameters(basePathItem, currentPathItem, baseOperation, current
|
|
|
33711
33930
|
});
|
|
33712
33931
|
continue;
|
|
33713
33932
|
}
|
|
33714
|
-
if (currentParameter
|
|
33933
|
+
if (currentParameter["required"] === true && baseParameter["required"] !== true) {
|
|
33715
33934
|
addChange(changes, {
|
|
33716
33935
|
kind: "breaking",
|
|
33717
33936
|
code: "parameter-required",
|
|
@@ -33730,16 +33949,16 @@ function compareParameters(basePathItem, currentPathItem, baseOperation, current
|
|
|
33730
33949
|
if (!parameter)
|
|
33731
33950
|
continue;
|
|
33732
33951
|
addChange(changes, {
|
|
33733
|
-
kind: parameter
|
|
33734
|
-
code: parameter
|
|
33952
|
+
kind: parameter["required"] === true ? "breaking" : "non-breaking",
|
|
33953
|
+
code: parameter["required"] === true ? "parameter-required" : "parameter-added",
|
|
33735
33954
|
path: `${path}.parameters.${key}`,
|
|
33736
|
-
message: parameter
|
|
33955
|
+
message: parameter["required"] === true ? "A new required parameter was added." : "An optional parameter was added."
|
|
33737
33956
|
});
|
|
33738
33957
|
}
|
|
33739
33958
|
}
|
|
33740
33959
|
function compareRequestBody(baseOperation, currentOperation, baseDocument, currentDocument, path, changes) {
|
|
33741
|
-
const baseBody = recordValue(baseOperation
|
|
33742
|
-
const currentBody = recordValue(currentOperation
|
|
33960
|
+
const baseBody = recordValue(baseOperation["requestBody"]);
|
|
33961
|
+
const currentBody = recordValue(currentOperation["requestBody"]);
|
|
33743
33962
|
if (!baseBody || !currentBody) {
|
|
33744
33963
|
if (baseBody && !currentBody) {
|
|
33745
33964
|
addChange(changes, {
|
|
@@ -33748,7 +33967,7 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
33748
33967
|
path: `${path}.requestBody`,
|
|
33749
33968
|
message: "A request body from the previous contract was removed."
|
|
33750
33969
|
});
|
|
33751
|
-
} else if (!baseBody && currentBody?.required === true) {
|
|
33970
|
+
} else if (!baseBody && currentBody?.["required"] === true) {
|
|
33752
33971
|
addChange(changes, {
|
|
33753
33972
|
kind: "breaking",
|
|
33754
33973
|
code: "request-body-required",
|
|
@@ -33765,7 +33984,7 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
33765
33984
|
}
|
|
33766
33985
|
return;
|
|
33767
33986
|
}
|
|
33768
|
-
if (currentBody
|
|
33987
|
+
if (currentBody["required"] === true && baseBody["required"] !== true) {
|
|
33769
33988
|
addChange(changes, {
|
|
33770
33989
|
kind: "breaking",
|
|
33771
33990
|
code: "request-body-required",
|
|
@@ -33773,8 +33992,8 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
33773
33992
|
message: "An optional request body became required."
|
|
33774
33993
|
});
|
|
33775
33994
|
}
|
|
33776
|
-
const baseContent = recordValue(baseBody
|
|
33777
|
-
const currentContent = recordValue(currentBody
|
|
33995
|
+
const baseContent = recordValue(baseBody["content"]);
|
|
33996
|
+
const currentContent = recordValue(currentBody["content"]);
|
|
33778
33997
|
for (const mediaType of sortedKeys2(baseContent)) {
|
|
33779
33998
|
const baseMedia = recordValue(baseContent?.[mediaType]);
|
|
33780
33999
|
const currentMedia = recordValue(currentContent?.[mediaType]);
|
|
@@ -33787,14 +34006,14 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
33787
34006
|
});
|
|
33788
34007
|
continue;
|
|
33789
34008
|
}
|
|
33790
|
-
if (baseMedia
|
|
33791
|
-
compareSchema(baseMedia
|
|
34009
|
+
if (baseMedia["schema"] !== undefined && currentMedia["schema"] !== undefined) {
|
|
34010
|
+
compareSchema(baseMedia["schema"], currentMedia["schema"], baseDocument, currentDocument, `${path}.requestBody.content.${mediaType}.schema`, "input", changes);
|
|
33792
34011
|
}
|
|
33793
34012
|
}
|
|
33794
34013
|
}
|
|
33795
34014
|
function compareResponses(baseOperation, currentOperation, baseDocument, currentDocument, path, changes) {
|
|
33796
|
-
const baseResponses = recordValue(baseOperation
|
|
33797
|
-
const currentResponses = recordValue(currentOperation
|
|
34015
|
+
const baseResponses = recordValue(baseOperation["responses"]);
|
|
34016
|
+
const currentResponses = recordValue(currentOperation["responses"]);
|
|
33798
34017
|
for (const status of sortedKeys2(baseResponses)) {
|
|
33799
34018
|
const baseResponse = recordValue(baseResponses?.[status]);
|
|
33800
34019
|
const currentResponse = recordValue(currentResponses?.[status]);
|
|
@@ -33807,8 +34026,8 @@ function compareResponses(baseOperation, currentOperation, baseDocument, current
|
|
|
33807
34026
|
});
|
|
33808
34027
|
continue;
|
|
33809
34028
|
}
|
|
33810
|
-
const baseContent = recordValue(baseResponse
|
|
33811
|
-
const currentContent = recordValue(currentResponse
|
|
34029
|
+
const baseContent = recordValue(baseResponse["content"]);
|
|
34030
|
+
const currentContent = recordValue(currentResponse["content"]);
|
|
33812
34031
|
for (const mediaType of sortedKeys2(baseContent)) {
|
|
33813
34032
|
const baseMedia = recordValue(baseContent?.[mediaType]);
|
|
33814
34033
|
const currentMedia = recordValue(currentContent?.[mediaType]);
|
|
@@ -33821,8 +34040,8 @@ function compareResponses(baseOperation, currentOperation, baseDocument, current
|
|
|
33821
34040
|
});
|
|
33822
34041
|
continue;
|
|
33823
34042
|
}
|
|
33824
|
-
if (baseMedia
|
|
33825
|
-
compareSchema(baseMedia
|
|
34043
|
+
if (baseMedia["schema"] !== undefined && currentMedia["schema"] !== undefined) {
|
|
34044
|
+
compareSchema(baseMedia["schema"], currentMedia["schema"], baseDocument, currentDocument, `${path}.responses.${status}.content.${mediaType}.schema`, "output", changes);
|
|
33826
34045
|
}
|
|
33827
34046
|
}
|
|
33828
34047
|
}
|
|
@@ -33841,8 +34060,8 @@ function compareOperation(basePathItem, currentPathItem, baseOperation, currentO
|
|
|
33841
34060
|
compareParameters(basePathItem, currentPathItem, baseOperation, currentOperation, baseDocument, currentDocument, path, changes);
|
|
33842
34061
|
compareRequestBody(baseOperation, currentOperation, baseDocument, currentDocument, path, changes);
|
|
33843
34062
|
compareResponses(baseOperation, currentOperation, baseDocument, currentDocument, path, changes);
|
|
33844
|
-
const baseSecurity = baseOperation
|
|
33845
|
-
const currentSecurity = currentOperation
|
|
34063
|
+
const baseSecurity = baseOperation["security"];
|
|
34064
|
+
const currentSecurity = currentOperation["security"];
|
|
33846
34065
|
if (Array.isArray(currentSecurity) && currentSecurity.length > 0 && (!Array.isArray(baseSecurity) || baseSecurity.length === 0)) {
|
|
33847
34066
|
addChange(changes, {
|
|
33848
34067
|
kind: "breaking",
|
|
@@ -33853,8 +34072,8 @@ function compareOperation(basePathItem, currentPathItem, baseOperation, currentO
|
|
|
33853
34072
|
}
|
|
33854
34073
|
}
|
|
33855
34074
|
function compareComponents(baseDocument, currentDocument, changes) {
|
|
33856
|
-
const baseComponents = recordValue(baseDocument
|
|
33857
|
-
const currentComponents = recordValue(currentDocument
|
|
34075
|
+
const baseComponents = recordValue(baseDocument["components"]);
|
|
34076
|
+
const currentComponents = recordValue(currentDocument["components"]);
|
|
33858
34077
|
for (const group of COMPONENT_GROUPS) {
|
|
33859
34078
|
const baseGroup = recordValue(baseComponents?.[group]);
|
|
33860
34079
|
const currentGroup = recordValue(currentComponents?.[group]);
|
|
@@ -33881,10 +34100,10 @@ function compareComponents(baseDocument, currentDocument, changes) {
|
|
|
33881
34100
|
}
|
|
33882
34101
|
}
|
|
33883
34102
|
function parseOpenApiDocument(value) {
|
|
33884
|
-
if (!isRecord(value) || typeof value
|
|
34103
|
+
if (!isRecord(value) || typeof value["openapi"] !== "string" || !/^3\.[0-9]+(?:\.[0-9]+)?$/.test(value["openapi"]) || !isRecord(value["info"]) || !isRecord(value["paths"])) {
|
|
33885
34104
|
throw new OpenApiDocumentError;
|
|
33886
34105
|
}
|
|
33887
|
-
return { ...value, openapi: value
|
|
34106
|
+
return { ...value, openapi: value["openapi"], info: value["info"], paths: value["paths"] };
|
|
33888
34107
|
}
|
|
33889
34108
|
function serializeOpenApiJson(document, space = 2) {
|
|
33890
34109
|
const parsed = parseOpenApiDocument(document);
|
|
@@ -33933,7 +34152,7 @@ async function loadGeneratedOpenApiDocument(modulePath) {
|
|
|
33933
34152
|
const loaded = await import(moduleUrl.href);
|
|
33934
34153
|
if (!isRecord(loaded))
|
|
33935
34154
|
throw new OpenApiDocumentError;
|
|
33936
|
-
return parseOpenApiDocument(loaded
|
|
34155
|
+
return parseOpenApiDocument(loaded["OPENAPI_DOCUMENT"]);
|
|
33937
34156
|
} catch (error) {
|
|
33938
34157
|
if (error instanceof OpenApiDocumentError)
|
|
33939
34158
|
throw error;
|
|
@@ -34093,16 +34312,19 @@ async function assessMigration(options) {
|
|
|
34093
34312
|
};
|
|
34094
34313
|
try {
|
|
34095
34314
|
const parsed = JSON.parse(await readFile11(contractsManifestPath, "utf8"));
|
|
34096
|
-
if (!isRecord2(parsed) || parsed
|
|
34315
|
+
if (!isRecord2(parsed) || parsed["version"] !== 1)
|
|
34097
34316
|
throw new Error("invalid manifest");
|
|
34317
|
+
const commands = arrayLength(parsed["commands"]);
|
|
34318
|
+
const routes = arrayLength(parsed["routes"]);
|
|
34319
|
+
const permissions = arrayLength(parsed["permissions"]);
|
|
34098
34320
|
contractsManifest = {
|
|
34099
34321
|
path: contractsManifestPath,
|
|
34100
34322
|
present: true,
|
|
34101
34323
|
sha256: await sha2562(contractsManifestPath),
|
|
34102
34324
|
version: 1,
|
|
34103
|
-
...
|
|
34104
|
-
...
|
|
34105
|
-
...
|
|
34325
|
+
...commands === undefined ? {} : { commands },
|
|
34326
|
+
...routes === undefined ? {} : { routes },
|
|
34327
|
+
...permissions === undefined ? {} : { permissions }
|
|
34106
34328
|
};
|
|
34107
34329
|
} catch {
|
|
34108
34330
|
findings.push({
|
|
@@ -34355,10 +34577,10 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
|
|
|
34355
34577
|
...resolved.detectOrphanModules === undefined ? {} : { detectOrphanModules: resolved.detectOrphanModules },
|
|
34356
34578
|
effect: resolved.effect === undefined ? { ...DEFAULT_SUPACLOUD_CONFIG.effect } : { ...DEFAULT_SUPACLOUD_CONFIG.effect, ...resolved.effect },
|
|
34357
34579
|
treeShakeUnusedProviders: resolved.treeShakeUnusedProviders ?? DEFAULT_SUPACLOUD_CONFIG.treeShakeUnusedProviders,
|
|
34358
|
-
graphql
|
|
34580
|
+
...resolved.graphql === undefined || resolved.graphql === false ? {} : { graphql: {
|
|
34359
34581
|
...resolved.graphql,
|
|
34360
34582
|
schema: resolve21(cwd, resolved.graphql.schema)
|
|
34361
|
-
}
|
|
34583
|
+
} }
|
|
34362
34584
|
};
|
|
34363
34585
|
}
|
|
34364
34586
|
async function loadSupacloudConfig(cwd = process.cwd()) {
|
|
@@ -34520,15 +34742,20 @@ function checkGraphqlCompatibility(schema, documents, policy = {}) {
|
|
|
34520
34742
|
try {
|
|
34521
34743
|
parsed = parse9(document.source);
|
|
34522
34744
|
} catch (error) {
|
|
34523
|
-
diagnostics.push({
|
|
34745
|
+
diagnostics.push({
|
|
34746
|
+
severity: "error",
|
|
34747
|
+
code: "graphql-document-invalid",
|
|
34748
|
+
message: error instanceof Error ? error.message : String(error),
|
|
34749
|
+
...document.path === undefined ? {} : { file: document.path }
|
|
34750
|
+
});
|
|
34524
34751
|
continue;
|
|
34525
34752
|
}
|
|
34526
34753
|
diagnostics.push(...validate2(schema, parsed).map((error) => ({
|
|
34527
34754
|
severity: "error",
|
|
34528
34755
|
code: "graphql-validation",
|
|
34529
34756
|
message: error.message,
|
|
34530
|
-
file: document.path,
|
|
34531
|
-
line: error.locations
|
|
34757
|
+
...document.path === undefined ? {} : { file: document.path },
|
|
34758
|
+
...error.locations?.[0]?.line === undefined ? {} : { line: error.locations[0].line }
|
|
34532
34759
|
})));
|
|
34533
34760
|
const fragmentDefinitions = new Map(parsed.definitions.filter((definition) => definition.kind === Kind2.FRAGMENT_DEFINITION).map((definition) => [definition.name.value, definition]));
|
|
34534
34761
|
for (const definition of parsed.definitions) {
|
|
@@ -34536,7 +34763,10 @@ function checkGraphqlCompatibility(schema, documents, policy = {}) {
|
|
|
34536
34763
|
continue;
|
|
34537
34764
|
const result = operationReport(schema, definition, fragmentDefinitions, policy);
|
|
34538
34765
|
operations.push(result.report);
|
|
34539
|
-
diagnostics.push(...result.diagnostics.map((item) => ({
|
|
34766
|
+
diagnostics.push(...result.diagnostics.map((item) => ({
|
|
34767
|
+
...item,
|
|
34768
|
+
...document.path === undefined ? {} : { file: document.path }
|
|
34769
|
+
})));
|
|
34540
34770
|
}
|
|
34541
34771
|
}
|
|
34542
34772
|
return { ok: diagnostics.every((item) => item.severity !== "error"), features: graphqlFeatureMatrix(schema), operations, diagnostics };
|