@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/cli.js
CHANGED
|
@@ -35,8 +35,8 @@ function getModuleBoundaryProfile(name) {
|
|
|
35
35
|
...profile,
|
|
36
36
|
rules: profile.rules.map((rule) => ({
|
|
37
37
|
...rule,
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
...rule.onlyDependOnLibsWithTags === undefined ? {} : { onlyDependOnLibsWithTags: [...rule.onlyDependOnLibsWithTags] },
|
|
39
|
+
...rule.bannedDependenciesWithTags === undefined ? {} : { bannedDependenciesWithTags: [...rule.bannedDependenciesWithTags] }
|
|
40
40
|
}))
|
|
41
41
|
};
|
|
42
42
|
}
|
|
@@ -252,7 +252,13 @@ var REQUEST_CONTEXT_TOKEN_NAME = "supacloud.request-context", JOB_CONTEXT_TOKEN_
|
|
|
252
252
|
function validateFeatureSpec(spec, module) {
|
|
253
253
|
const diagnostics = [];
|
|
254
254
|
const error = (code, message) => {
|
|
255
|
-
diagnostics.push({
|
|
255
|
+
diagnostics.push({
|
|
256
|
+
severity: "error",
|
|
257
|
+
code,
|
|
258
|
+
message,
|
|
259
|
+
...spec.file === undefined ? {} : { file: spec.file },
|
|
260
|
+
...spec.line === undefined ? {} : { line: spec.line }
|
|
261
|
+
});
|
|
256
262
|
};
|
|
257
263
|
if (!spec.name.trim() || spec.states.length === 0 || spec.states.some((state) => !state.trim()) || new Set(spec.states).size !== spec.states.length) {
|
|
258
264
|
error("invalid-feature-states", "Feature name and states must be non-empty; states must be unique.");
|
|
@@ -290,7 +296,7 @@ function validateFeatureSpec(spec, module) {
|
|
|
290
296
|
const routes = module.controllers.flatMap((controller) => controller.routes.filter((route) => `${route.method} ${joinRoutePaths(controller.path, route.path)}` === transition.route));
|
|
291
297
|
if (routes.length !== 1) {
|
|
292
298
|
error("feature-route-unresolved", `Transition ${transition.name} must reference exactly one route '${transition.route}' in module ${module.name}.`);
|
|
293
|
-
} else if (command && routes[0]
|
|
299
|
+
} else if (command && routes[0]?.command !== command.className) {
|
|
294
300
|
error("feature-route-drift", `Route ${transition.route} is not bound to ${command.className}.`);
|
|
295
301
|
}
|
|
296
302
|
}
|
|
@@ -2658,7 +2664,7 @@ ${procedureMethods.join(`
|
|
|
2658
2664
|
"",
|
|
2659
2665
|
"function selectResponseSchema(status: number, schemas: Readonly<Record<string, unknown>>): unknown {",
|
|
2660
2666
|
" const family = `${Math.floor(status / 100)}xx`;",
|
|
2661
|
-
|
|
2667
|
+
' return schemas[String(status)] ?? schemas[family] ?? schemas[family.toUpperCase()] ?? schemas["default"];',
|
|
2662
2668
|
"}",
|
|
2663
2669
|
"",
|
|
2664
2670
|
...usesValue ? [
|
|
@@ -2686,16 +2692,16 @@ ${procedureMethods.join(`
|
|
|
2686
2692
|
"function schemaReferenceTarget(ref: string, root: unknown): unknown {",
|
|
2687
2693
|
' 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;',
|
|
2688
2694
|
" if (localRef !== undefined && isRecord(root)) {",
|
|
2689
|
-
' const defs = ref.startsWith("#/definitions/") ? root
|
|
2695
|
+
' const defs = ref.startsWith("#/definitions/") ? root["definitions"] : ref.startsWith("#/components/schemas/") ? root["components"] : root["$defs"];',
|
|
2690
2696
|
' if (ref.startsWith("#/components/schemas/") && isRecord(defs)) {',
|
|
2691
|
-
|
|
2697
|
+
' const components = defs["schemas"];',
|
|
2692
2698
|
" if (isRecord(components) && components[localRef] !== undefined) return components[localRef];",
|
|
2693
2699
|
" } else if (isRecord(defs) && defs[localRef] !== undefined) return defs[localRef];",
|
|
2694
2700
|
" }",
|
|
2695
2701
|
" for (const entry of API_SCHEMAS as readonly { name: string; schema: unknown }[]) {",
|
|
2696
2702
|
" if (entry.name === ref) return entry.schema;",
|
|
2697
2703
|
" if (!isRecord(entry.schema)) continue;",
|
|
2698
|
-
|
|
2704
|
+
' if (entry.schema["$id"] === ref || entry.schema["$id"] === localRef) return entry.schema;',
|
|
2699
2705
|
' for (const key of ["$defs", "definitions"] as const) {',
|
|
2700
2706
|
" const defs = entry.schema[key];",
|
|
2701
2707
|
" if (isRecord(defs) && localRef !== undefined && defs[localRef] !== undefined) return defs[localRef];",
|
|
@@ -2722,52 +2728,52 @@ ${procedureMethods.join(`
|
|
|
2722
2728
|
" if (schema === true) return value;",
|
|
2723
2729
|
" if (schema === false || !isRecord(schema)) return schemaError();",
|
|
2724
2730
|
' 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");',
|
|
2725
|
-
' if (typeof schema
|
|
2726
|
-
|
|
2727
|
-
|
|
2731
|
+
' if (typeof schema["$ref"] === "string") {',
|
|
2732
|
+
' if (seenRefs.has(schema["$ref"])) return schemaError();',
|
|
2733
|
+
' const target = schemaReferenceTarget(schema["$ref"], root);',
|
|
2728
2734
|
" if (target === undefined) return schemaError();",
|
|
2729
|
-
|
|
2735
|
+
' const nextRefs = new Set(seenRefs); nextRefs.add(schema["$ref"]);',
|
|
2730
2736
|
" return decodeSchemaValue(target, value, root, nextRefs, normalize);",
|
|
2731
2737
|
" }",
|
|
2732
|
-
|
|
2733
|
-
' if (Object.hasOwn(schema, "const") && !sameJsonValue(schema
|
|
2734
|
-
|
|
2735
|
-
|
|
2738
|
+
' if (schema["nullable"] === true && value === null) return value;',
|
|
2739
|
+
' if (Object.hasOwn(schema, "const") && !sameJsonValue(schema["const"], value)) return schemaError();',
|
|
2740
|
+
' if (Array.isArray(schema["enum"]) && !schema["enum"].some((entry) => sameJsonValue(entry, value))) return schemaError();',
|
|
2741
|
+
' if (Array.isArray(schema["anyOf"])) {',
|
|
2736
2742
|
" const matches: unknown[] = [];",
|
|
2737
|
-
|
|
2743
|
+
' for (const variant of schema["anyOf"]) { try { matches.push(decodeSchemaValue(variant, value, root, new Set(seenRefs), normalize)); } catch {} }',
|
|
2738
2744
|
" if (matches.length === 0) return schemaError();",
|
|
2739
2745
|
" return matches[0];",
|
|
2740
2746
|
" }",
|
|
2741
|
-
|
|
2747
|
+
' if (Array.isArray(schema["oneOf"])) {',
|
|
2742
2748
|
" const matches: unknown[] = [];",
|
|
2743
|
-
|
|
2749
|
+
' for (const variant of schema["oneOf"]) { try { matches.push(decodeSchemaValue(variant, value, root, new Set(seenRefs), normalize)); } catch {} }',
|
|
2744
2750
|
" if (matches.length !== 1) return schemaError();",
|
|
2745
2751
|
" return matches[0];",
|
|
2746
2752
|
" }",
|
|
2747
|
-
|
|
2753
|
+
' if (Array.isArray(schema["allOf"])) {',
|
|
2748
2754
|
" let output: unknown = value;",
|
|
2749
|
-
|
|
2755
|
+
' for (const variant of schema["allOf"]) {',
|
|
2750
2756
|
" const decoded = decodeSchemaValue(variant, value, root, new Set(seenRefs), normalize);",
|
|
2751
2757
|
" output = isRecord(output) && isRecord(decoded) ? { ...output, ...decoded } : decoded;",
|
|
2752
2758
|
" }",
|
|
2753
2759
|
" return output;",
|
|
2754
2760
|
" }",
|
|
2755
|
-
|
|
2756
|
-
|
|
2761
|
+
' if (schema["not"] !== undefined) {',
|
|
2762
|
+
' try { decodeSchemaValue(schema["not"], value, root, new Set(seenRefs), normalize); } catch { return value; }',
|
|
2757
2763
|
" return schemaError();",
|
|
2758
2764
|
" }",
|
|
2759
|
-
|
|
2760
|
-
|
|
2765
|
+
' if (Array.isArray(schema["type"])) {',
|
|
2766
|
+
' for (const type of schema["type"]) { try { return decodeSchemaValue({ ...schema, type }, value, root, new Set(seenRefs), normalize); } catch {} }',
|
|
2761
2767
|
" return schemaError();",
|
|
2762
2768
|
" }",
|
|
2763
|
-
' if (schema
|
|
2769
|
+
' if (schema["type"] === "object" || (schema["type"] === undefined && (isRecord(schema["properties"]) || schema["required"] !== undefined))) {',
|
|
2764
2770
|
" if (!isRecord(value)) return schemaError();",
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2771
|
+
' const properties = isRecord(schema["properties"]) ? schema["properties"] : {};',
|
|
2772
|
+
' const patterns = isRecord(schema["patternProperties"]) ? schema["patternProperties"] : {};',
|
|
2773
|
+
' const required = Array.isArray(schema["required"]) ? schema["required"] : [];',
|
|
2768
2774
|
' for (const name of required) if (typeof name === "string" && !Object.hasOwn(value, name)) return schemaError();',
|
|
2769
|
-
' if (typeof schema
|
|
2770
|
-
' if (typeof schema
|
|
2775
|
+
' if (typeof schema["minProperties"] === "number" && Object.keys(value).length < schema["minProperties"]) return schemaError();',
|
|
2776
|
+
' if (typeof schema["maxProperties"] === "number" && Object.keys(value).length > schema["maxProperties"]) return schemaError();',
|
|
2771
2777
|
" const output: Record<string, unknown> = {};",
|
|
2772
2778
|
" for (const [name, item] of Object.entries(value)) {",
|
|
2773
2779
|
" const propertySchema = properties[name];",
|
|
@@ -2778,52 +2784,52 @@ ${procedureMethods.join(`
|
|
|
2778
2784
|
" if (applies) { output[name] = decodeSchemaValue(patternSchema, item, root, new Set<string>(), normalize); matched = true; }",
|
|
2779
2785
|
" }",
|
|
2780
2786
|
" if (matched) continue;",
|
|
2781
|
-
|
|
2787
|
+
' if (schema["additionalProperties"] === false || schema["unevaluatedProperties"] === false || schema["additionalProperties"] === undefined) {',
|
|
2782
2788
|
" if (normalize) continue;",
|
|
2783
2789
|
" return schemaError();",
|
|
2784
2790
|
" }",
|
|
2785
|
-
|
|
2786
|
-
|
|
2791
|
+
' if (isRecord(schema["additionalProperties"])) output[name] = decodeSchemaValue(schema["additionalProperties"], item, root, new Set<string>(), normalize);',
|
|
2792
|
+
' else if (schema["additionalProperties"] === true) output[name] = item;',
|
|
2787
2793
|
" }",
|
|
2788
2794
|
" return output;",
|
|
2789
2795
|
" }",
|
|
2790
|
-
' if (schema
|
|
2796
|
+
' if (schema["type"] === "array") {',
|
|
2791
2797
|
" if (!Array.isArray(value)) return schemaError();",
|
|
2792
|
-
' if (typeof schema
|
|
2793
|
-
' if (typeof schema
|
|
2794
|
-
|
|
2795
|
-
|
|
2798
|
+
' if (typeof schema["minItems"] === "number" && value.length < schema["minItems"]) return schemaError();',
|
|
2799
|
+
' if (typeof schema["maxItems"] === "number" && value.length > schema["maxItems"]) return schemaError();',
|
|
2800
|
+
' if (schema["uniqueItems"] === true) { const keys = value.map((item) => JSON.stringify(item)); if (new Set(keys).size !== keys.length) return schemaError(); }',
|
|
2801
|
+
' const tuple = Array.isArray(schema["prefixItems"]) ? schema["prefixItems"] : Array.isArray(schema["items"]) ? schema["items"] : undefined;',
|
|
2796
2802
|
" if (tuple) {",
|
|
2797
|
-
|
|
2798
|
-
|
|
2803
|
+
' if (schema["additionalItems"] === false && value.length > tuple.length) return schemaError();',
|
|
2804
|
+
' 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);',
|
|
2799
2805
|
" }",
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2806
|
+
' if (schema["items"] === undefined || schema["items"] === true) return value;',
|
|
2807
|
+
' if (schema["items"] === false && value.length > 0) return schemaError();',
|
|
2808
|
+
' return value.map((item) => decodeSchemaValue(schema["items"], item, root, new Set<string>(), normalize));',
|
|
2803
2809
|
" }",
|
|
2804
|
-
' if (schema
|
|
2810
|
+
' if (schema["type"] === "string") {',
|
|
2805
2811
|
' if (typeof value !== "string") return schemaError();',
|
|
2806
|
-
' if (typeof schema
|
|
2807
|
-
' if (typeof schema
|
|
2808
|
-
' if (typeof schema
|
|
2809
|
-
|
|
2812
|
+
' if (typeof schema["minLength"] === "number" && value.length < schema["minLength"]) return schemaError();',
|
|
2813
|
+
' if (typeof schema["maxLength"] === "number" && value.length > schema["maxLength"]) return schemaError();',
|
|
2814
|
+
' if (typeof schema["pattern"] === "string") { let matches = false; try { matches = new RegExp(schema["pattern"]).test(value); } catch { return schemaError(); } if (!matches) return schemaError(); }',
|
|
2815
|
+
' if (!matchesFormat(schema["format"], value)) return schemaError();',
|
|
2810
2816
|
" return value;",
|
|
2811
2817
|
" }",
|
|
2812
|
-
' if (schema
|
|
2813
|
-
' if (schema
|
|
2814
|
-
' if (typeof value !== "number" || !Number.isFinite(value) || (schema
|
|
2815
|
-
' if (typeof schema
|
|
2816
|
-
' if (typeof schema
|
|
2817
|
-
' if (typeof schema
|
|
2818
|
-
' if (typeof schema
|
|
2819
|
-
' if (schema
|
|
2820
|
-
' if (schema
|
|
2821
|
-
' if (typeof schema
|
|
2818
|
+
' if (schema["type"] === "boolean") { if (typeof value !== "boolean") return schemaError(); return value; }',
|
|
2819
|
+
' if (schema["type"] === "number" || schema["type"] === "integer") {',
|
|
2820
|
+
' if (typeof value !== "number" || !Number.isFinite(value) || (schema["type"] === "integer" && !Number.isInteger(value))) return schemaError();',
|
|
2821
|
+
' if (typeof schema["minimum"] === "number" && value < schema["minimum"]) return schemaError();',
|
|
2822
|
+
' if (typeof schema["maximum"] === "number" && value > schema["maximum"]) return schemaError();',
|
|
2823
|
+
' if (typeof schema["exclusiveMinimum"] === "number" && value <= schema["exclusiveMinimum"]) return schemaError();',
|
|
2824
|
+
' if (typeof schema["exclusiveMaximum"] === "number" && value >= schema["exclusiveMaximum"]) return schemaError();',
|
|
2825
|
+
' if (schema["exclusiveMinimum"] === true && typeof schema["minimum"] === "number" && value <= schema["minimum"]) return schemaError();',
|
|
2826
|
+
' if (schema["exclusiveMaximum"] === true && typeof schema["maximum"] === "number" && value >= schema["maximum"]) return schemaError();',
|
|
2827
|
+
' if (typeof schema["multipleOf"] === "number" && schema["multipleOf"] > 0 && Math.abs(value / schema["multipleOf"] - Math.round(value / schema["multipleOf"])) > 1e-9) return schemaError();',
|
|
2822
2828
|
" return value;",
|
|
2823
2829
|
" }",
|
|
2824
|
-
' if (schema
|
|
2825
|
-
' if (schema
|
|
2826
|
-
' if (schema
|
|
2830
|
+
' if (schema["type"] === "null") { if (value !== null) return schemaError(); return value; }',
|
|
2831
|
+
' if (schema["type"] === "void" || schema["type"] === "undefined") { if (value !== undefined) return schemaError(); return value; }',
|
|
2832
|
+
' if (schema["type"] === "never") return schemaError();',
|
|
2827
2833
|
" return value;",
|
|
2828
2834
|
"}",
|
|
2829
2835
|
""
|
|
@@ -2897,7 +2903,7 @@ ${procedureMethods.join(`
|
|
|
2897
2903
|
" ...options.headers,",
|
|
2898
2904
|
" };",
|
|
2899
2905
|
' if (options.cookie && !Object.keys(headers).some((key) => key.toLowerCase() === "cookie")) {',
|
|
2900
|
-
' headers
|
|
2906
|
+
' headers["cookie"] = Object.entries(options.cookie).map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`).join("; " );',
|
|
2901
2907
|
" }",
|
|
2902
2908
|
" const interceptors = config.interceptors ?? [];",
|
|
2903
2909
|
" const executeChain = (",
|
|
@@ -3088,7 +3094,7 @@ function renderOpenApi(graph, options) {
|
|
|
3088
3094
|
for (const module of graph.modules) {
|
|
3089
3095
|
for (const controller of module.controllers) {
|
|
3090
3096
|
for (const route of controller.routes) {
|
|
3091
|
-
const documentation = route.data?.openapi;
|
|
3097
|
+
const documentation = route.data?.["openapi"];
|
|
3092
3098
|
if (documentation !== null && typeof documentation === "object" && "hide" in documentation && documentation.hide === true)
|
|
3093
3099
|
continue;
|
|
3094
3100
|
const fullPath = joinRoutePaths(controller.path, route.path);
|
|
@@ -3275,11 +3281,11 @@ function renderOpenApi(graph, options) {
|
|
|
3275
3281
|
"function isUndefinedSchema(value: unknown, seen = new WeakSet<object>(), refs = new Set<string>(), scope?: unknown): boolean {",
|
|
3276
3282
|
" if (!isRecord(value) || seen.has(value)) return false;",
|
|
3277
3283
|
" seen.add(value);",
|
|
3278
|
-
|
|
3284
|
+
' const nextScope = isRecord(value["$defs"]) || isRecord(value["definitions"]) ? value : scope;',
|
|
3279
3285
|
" try {",
|
|
3280
|
-
' if (value
|
|
3281
|
-
' if (Array.isArray(value
|
|
3282
|
-
' const ref = typeof value
|
|
3286
|
+
' if (value["type"] === "undefined") return true;',
|
|
3287
|
+
' if (Array.isArray(value["type"]) && value["type"].length > 0 && value["type"].every((type) => type === "undefined")) return true;',
|
|
3288
|
+
' const ref = typeof value["$ref"] === "string" ? value["$ref"] : undefined;',
|
|
3283
3289
|
" if (ref !== undefined && !refs.has(ref)) {",
|
|
3284
3290
|
" const target = openApiSchemaRefTarget(ref, nextScope);",
|
|
3285
3291
|
" if (target !== undefined) {",
|
|
@@ -3303,10 +3309,10 @@ function renderOpenApi(graph, options) {
|
|
|
3303
3309
|
"function cloneSchema(value: unknown, seen = new WeakSet<object>(), scope?: unknown): OpenApiSchema {",
|
|
3304
3310
|
" if (!isRecord(value)) return {};",
|
|
3305
3311
|
" if (seen.has(value)) return {};",
|
|
3306
|
-
|
|
3312
|
+
' const nextScope = isRecord(value["$defs"]) || isRecord(value["definitions"]) ? value : scope;',
|
|
3307
3313
|
" if (isUndefinedSchema(value, new WeakSet<object>(), new Set<string>(), nextScope)) return {};",
|
|
3308
3314
|
" seen.add(value);",
|
|
3309
|
-
' if (value
|
|
3315
|
+
' if (value["type"] === "void" || value["type"] === "undefined") { seen.delete(value); return {}; }',
|
|
3310
3316
|
" const allowed = new Set([",
|
|
3311
3317
|
' "$id", "$ref", "$schema", "$defs", "definitions", "title", "description", "type", "enum", "const", "examples", "default",',
|
|
3312
3318
|
' "deprecated", "readOnly", "writeOnly", "format", "pattern", "minLength", "maxLength", "minimum",',
|
|
@@ -3353,12 +3359,12 @@ function renderOpenApi(graph, options) {
|
|
|
3353
3359
|
"function schemaAllowsUndefined(value: unknown, seen = new WeakSet<object>(), refs = new Set<string>(), scope?: unknown): boolean {",
|
|
3354
3360
|
" if (!isRecord(value) || seen.has(value)) return false;",
|
|
3355
3361
|
" seen.add(value);",
|
|
3356
|
-
|
|
3362
|
+
' const nextScope = isRecord(value["$defs"]) || isRecord(value["definitions"]) ? value : scope;',
|
|
3357
3363
|
" try {",
|
|
3358
3364
|
' if (Object.getOwnPropertySymbols(value).some((symbol) => String(symbol).toLowerCase().includes("optional"))) return true;',
|
|
3359
|
-
' if (value
|
|
3360
|
-
' if (Array.isArray(value
|
|
3361
|
-
' const ref = typeof value
|
|
3365
|
+
' if (value["type"] === "undefined") return true;',
|
|
3366
|
+
' if (Array.isArray(value["type"]) && value["type"].includes("undefined")) return true;',
|
|
3367
|
+
' const ref = typeof value["$ref"] === "string" ? value["$ref"] : undefined;',
|
|
3362
3368
|
" if (ref !== undefined && !refs.has(ref)) {",
|
|
3363
3369
|
" const target = openApiSchemaRefTarget(ref, nextScope);",
|
|
3364
3370
|
" if (target !== undefined) {",
|
|
@@ -3378,11 +3384,11 @@ function renderOpenApi(graph, options) {
|
|
|
3378
3384
|
"",
|
|
3379
3385
|
"function resolveRegistrySchema(value: unknown, seen = new Set<string>()): OpenApiSchema {",
|
|
3380
3386
|
" const schema = cloneSchema(value);",
|
|
3381
|
-
' const ref = typeof schema
|
|
3387
|
+
' const ref = typeof schema["$ref"] === "string" ? schema["$ref"] : undefined;',
|
|
3382
3388
|
" if (!ref || seen.has(ref)) return schema;",
|
|
3383
3389
|
' const localName = ref.startsWith("#/components/schemas/") ? ref.slice(21) : ref.startsWith("#/$defs/") ? ref.slice(8) : ref.startsWith("#/definitions/") ? ref.slice(14) : ref;',
|
|
3384
3390
|
' if (ref.startsWith("#/$defs/") || ref.startsWith("#/definitions/")) {',
|
|
3385
|
-
' const defs = ref.startsWith("#/$defs/") ? schema
|
|
3391
|
+
' const defs = ref.startsWith("#/$defs/") ? schema["$defs"] : schema["definitions"];',
|
|
3386
3392
|
" if (isRecord(defs) && defs[localName] !== undefined) return resolveRegistrySchema(defs[localName], new Set([...seen, ref]));",
|
|
3387
3393
|
" }",
|
|
3388
3394
|
" for (const [name, candidate] of Object.entries(OPENAPI_SCHEMA_REGISTRY)) {",
|
|
@@ -3395,18 +3401,18 @@ function renderOpenApi(graph, options) {
|
|
|
3395
3401
|
"",
|
|
3396
3402
|
"function schemaProperty(schema: unknown, name: string): OpenApiSchema {",
|
|
3397
3403
|
" const document = resolveRegistrySchema(schema);",
|
|
3398
|
-
|
|
3404
|
+
' const properties = document["properties"];',
|
|
3399
3405
|
' return isRecord(properties) && isRecord(properties[name]) ? properties[name] : { type: "string" };',
|
|
3400
3406
|
"}",
|
|
3401
3407
|
"",
|
|
3402
3408
|
"function schemaPropertyNames(schema: unknown): string[] {",
|
|
3403
3409
|
" const document = resolveRegistrySchema(schema);",
|
|
3404
|
-
|
|
3410
|
+
' return isRecord(document["properties"]) ? Object.keys(document["properties"]).sort() : [];',
|
|
3405
3411
|
"}",
|
|
3406
3412
|
"",
|
|
3407
3413
|
"function schemaRequired(schema: unknown, name: string): boolean {",
|
|
3408
3414
|
" const document = resolveRegistrySchema(schema);",
|
|
3409
|
-
|
|
3415
|
+
' return Array.isArray(document["required"]) && document["required"].includes(name);',
|
|
3410
3416
|
"}",
|
|
3411
3417
|
"",
|
|
3412
3418
|
"function schemaReference(name: string): OpenApiSchema {",
|
|
@@ -4051,24 +4057,24 @@ function assertGraphqlOptions(value) {
|
|
|
4051
4057
|
if (unsupported.length) {
|
|
4052
4058
|
fail(`Unsupported options: ${unsupported.join(", ")}. Configure only schema, documents, scalars and typedDocuments; server schema authoring modes are not supported.`);
|
|
4053
4059
|
}
|
|
4054
|
-
const schema = options
|
|
4060
|
+
const schema = options["schema"];
|
|
4055
4061
|
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))) {
|
|
4056
4062
|
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.");
|
|
4057
4063
|
}
|
|
4058
|
-
if (options
|
|
4064
|
+
if (options["documents"] !== undefined && (!Array.isArray(options["documents"]) || options["documents"].some((pattern) => typeof pattern !== "string" || !pattern.trim()))) {
|
|
4059
4065
|
fail("graphql.documents must contain local query/fragment glob strings.");
|
|
4060
4066
|
}
|
|
4061
|
-
if (options
|
|
4067
|
+
if (options["typedDocuments"] !== undefined && typeof options["typedDocuments"] !== "boolean") {
|
|
4062
4068
|
fail("graphql.typedDocuments must be a boolean output option.");
|
|
4063
4069
|
}
|
|
4064
|
-
if (options
|
|
4070
|
+
if (options["mutations"] !== undefined && typeof options["mutations"] !== "boolean") {
|
|
4065
4071
|
fail("graphql.mutations must be a boolean opt-in for database-backed mutation documents.");
|
|
4066
4072
|
}
|
|
4067
|
-
if (options
|
|
4068
|
-
if (!options
|
|
4073
|
+
if (options["scalars"] !== undefined) {
|
|
4074
|
+
if (!options["scalars"] || typeof options["scalars"] !== "object" || Array.isArray(options["scalars"])) {
|
|
4069
4075
|
fail("graphql.scalars must be a map of explicit wire types.");
|
|
4070
4076
|
}
|
|
4071
|
-
for (const mapping of Object.values(options
|
|
4077
|
+
for (const mapping of Object.values(options["scalars"])) {
|
|
4072
4078
|
if (typeof mapping === "string" && mapping.trim())
|
|
4073
4079
|
continue;
|
|
4074
4080
|
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())
|
|
@@ -4091,7 +4097,7 @@ var init_graphql_options = __esm(() => {
|
|
|
4091
4097
|
|
|
4092
4098
|
// src/graphql-inputs.ts
|
|
4093
4099
|
import { resolve as resolve5 } from "node:path";
|
|
4094
|
-
import * as
|
|
4100
|
+
import * as ts11 from "@typescript/typescript6";
|
|
4095
4101
|
function graphqlInputPaths(options) {
|
|
4096
4102
|
if (!options.graphql)
|
|
4097
4103
|
return [];
|
|
@@ -4102,7 +4108,7 @@ function graphqlInputPaths(options) {
|
|
|
4102
4108
|
}
|
|
4103
4109
|
const root = resolve5(options.rootDir);
|
|
4104
4110
|
const schema = resolve5(root, options.graphql.schema);
|
|
4105
|
-
const documents =
|
|
4111
|
+
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);
|
|
4106
4112
|
return [schema, ...[...new Set(documents)].sort()];
|
|
4107
4113
|
}
|
|
4108
4114
|
var init_graphql_inputs = __esm(() => {
|
|
@@ -4110,7 +4116,7 @@ var init_graphql_inputs = __esm(() => {
|
|
|
4110
4116
|
});
|
|
4111
4117
|
|
|
4112
4118
|
// src/graphql-runtime.ts
|
|
4113
|
-
import * as
|
|
4119
|
+
import * as ts12 from "@typescript/typescript6";
|
|
4114
4120
|
import { resolve as resolve6 } from "node:path";
|
|
4115
4121
|
function renderGraphqlValidators(source, operationNames, operationKinds = new Map) {
|
|
4116
4122
|
const fileName = resolve6("/__supacloud_graphql__/contracts.ts");
|
|
@@ -4122,18 +4128,18 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4122
4128
|
noPropertyAccessFromIndexSignature: true,
|
|
4123
4129
|
noFallthroughCasesInSwitch: true,
|
|
4124
4130
|
skipLibCheck: false,
|
|
4125
|
-
target:
|
|
4131
|
+
target: ts12.ScriptTarget.ES2022,
|
|
4126
4132
|
lib: ["lib.es2022.d.ts"],
|
|
4127
4133
|
types: [],
|
|
4128
4134
|
noEmit: true
|
|
4129
4135
|
};
|
|
4130
|
-
const host =
|
|
4136
|
+
const host = ts12.createCompilerHost(options);
|
|
4131
4137
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
4132
|
-
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve6(path) === fileName ?
|
|
4133
|
-
const program =
|
|
4134
|
-
const diagnostics =
|
|
4138
|
+
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve6(path) === fileName ? ts12.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
|
|
4139
|
+
const program = ts12.createProgram([fileName], options, host);
|
|
4140
|
+
const diagnostics = ts12.getPreEmitDiagnostics(program);
|
|
4135
4141
|
if (diagnostics.length) {
|
|
4136
|
-
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) =>
|
|
4142
|
+
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts12.flattenDiagnosticMessageText(item.messageText, `
|
|
4137
4143
|
`)).join("; ")}`);
|
|
4138
4144
|
}
|
|
4139
4145
|
const checker = program.getTypeChecker();
|
|
@@ -4163,25 +4169,25 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4163
4169
|
return name;
|
|
4164
4170
|
}
|
|
4165
4171
|
function expression(type) {
|
|
4166
|
-
if (type.flags &
|
|
4172
|
+
if (type.flags & ts12.TypeFlags.Any)
|
|
4167
4173
|
return unsupported(type);
|
|
4168
|
-
if (type.flags &
|
|
4174
|
+
if (type.flags & ts12.TypeFlags.Unknown)
|
|
4169
4175
|
return "true";
|
|
4170
|
-
if (type.flags &
|
|
4176
|
+
if (type.flags & ts12.TypeFlags.Never)
|
|
4171
4177
|
return "false";
|
|
4172
|
-
if (type.flags &
|
|
4178
|
+
if (type.flags & ts12.TypeFlags.Null)
|
|
4173
4179
|
return "value === null";
|
|
4174
|
-
if (type.flags &
|
|
4180
|
+
if (type.flags & ts12.TypeFlags.Undefined)
|
|
4175
4181
|
return "value === undefined";
|
|
4176
4182
|
if (type.isStringLiteral() || type.isNumberLiteral())
|
|
4177
4183
|
return `value === ${JSON.stringify(type.value)}`;
|
|
4178
|
-
if (type.flags &
|
|
4184
|
+
if (type.flags & ts12.TypeFlags.BooleanLiteral)
|
|
4179
4185
|
return `value === ${checker.typeToString(type)}`;
|
|
4180
|
-
if (type.flags &
|
|
4186
|
+
if (type.flags & ts12.TypeFlags.String)
|
|
4181
4187
|
return 'typeof value === "string"';
|
|
4182
|
-
if (type.flags &
|
|
4188
|
+
if (type.flags & ts12.TypeFlags.Number)
|
|
4183
4189
|
return 'typeof value === "number" && Number.isFinite(value)';
|
|
4184
|
-
if (type.flags &
|
|
4190
|
+
if (type.flags & ts12.TypeFlags.Boolean)
|
|
4185
4191
|
return 'typeof value === "boolean"';
|
|
4186
4192
|
if (type.isUnion())
|
|
4187
4193
|
return type.types.map((part) => `${reference(part)}(value)`).join(" || ");
|
|
@@ -4190,16 +4196,16 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4190
4196
|
if (checker.isTupleType(type))
|
|
4191
4197
|
return unsupported(type);
|
|
4192
4198
|
if (checker.isArrayType(type)) {
|
|
4193
|
-
const item = checker.getIndexTypeOfType(type,
|
|
4199
|
+
const item = checker.getIndexTypeOfType(type, ts12.IndexKind.Number);
|
|
4194
4200
|
if (!item)
|
|
4195
4201
|
return unsupported(type);
|
|
4196
4202
|
return `isGraphqlArray(value) && Array.from(value).every(${reference(item)})`;
|
|
4197
4203
|
}
|
|
4198
|
-
if (type.flags &
|
|
4204
|
+
if (type.flags & ts12.TypeFlags.Object) {
|
|
4199
4205
|
if (type.getCallSignatures().length || type.getConstructSignatures().length)
|
|
4200
4206
|
return unsupported(type);
|
|
4201
4207
|
const indexes = checker.getIndexInfosOfType(type);
|
|
4202
|
-
if (indexes.some((index) => !(index.keyType.flags &
|
|
4208
|
+
if (indexes.some((index) => !(index.keyType.flags & ts12.TypeFlags.String)))
|
|
4203
4209
|
return unsupported(type);
|
|
4204
4210
|
const properties = checker.getPropertiesOfType(type).map((property) => {
|
|
4205
4211
|
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
@@ -4208,7 +4214,7 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
|
|
|
4208
4214
|
const check = reference(checker.getTypeOfSymbolAtLocation(property, declaration));
|
|
4209
4215
|
const key = JSON.stringify(property.name);
|
|
4210
4216
|
const present = `Object.prototype.hasOwnProperty.call(value, ${key})`;
|
|
4211
|
-
return property.flags &
|
|
4217
|
+
return property.flags & ts12.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
|
|
4212
4218
|
});
|
|
4213
4219
|
const indexedValues = indexes.map((index) => `Object.values(value).every(${reference(index.type)})`);
|
|
4214
4220
|
return ["isGraphqlRecord(value)", ...properties, ...indexedValues].join(" && ");
|
|
@@ -4346,8 +4352,8 @@ async function renderGraphql(options) {
|
|
|
4346
4352
|
severity: "error",
|
|
4347
4353
|
code,
|
|
4348
4354
|
message: error instanceof Error ? error.message : String(error),
|
|
4349
|
-
|
|
4350
|
-
|
|
4355
|
+
...source === undefined ? {} : { file: localPath(source) },
|
|
4356
|
+
...gql?.locations?.[0]?.line === undefined ? {} : { line: gql.locations[0].line },
|
|
4351
4357
|
suggestion: "Update the role-scoped local schema snapshot or correct the query, then recompile."
|
|
4352
4358
|
});
|
|
4353
4359
|
};
|
|
@@ -4397,8 +4403,8 @@ async function renderGraphql(options) {
|
|
|
4397
4403
|
severity: "error",
|
|
4398
4404
|
code: "graphql-query-only",
|
|
4399
4405
|
message: "GraphQL subscriptions are not supported by the HTTP contract compiler. Use the governed Realtime transport for subscriptions.",
|
|
4400
|
-
|
|
4401
|
-
line: definition.loc
|
|
4406
|
+
...definition.loc ? { file: localPath(definition.loc.source.name) } : {},
|
|
4407
|
+
...definition.loc?.startToken.line === undefined ? {} : { line: definition.loc.startToken.line },
|
|
4402
4408
|
suggestion: "Remove this subscription from the GraphQL documents and use the supported Realtime contract."
|
|
4403
4409
|
});
|
|
4404
4410
|
} else if (definition.operation === "mutation" && !options.graphql.mutations) {
|
|
@@ -4406,8 +4412,8 @@ async function renderGraphql(options) {
|
|
|
4406
4412
|
severity: "error",
|
|
4407
4413
|
code: "graphql-query-only",
|
|
4408
4414
|
message: "GraphQL mutations are disabled by default. Set graphql.mutations to true only after reviewing database grants, RLS, audit and idempotency behavior.",
|
|
4409
|
-
|
|
4410
|
-
line: definition.loc
|
|
4415
|
+
...definition.loc ? { file: localPath(definition.loc.source.name) } : {},
|
|
4416
|
+
...definition.loc?.startToken.line === undefined ? {} : { line: definition.loc.startToken.line },
|
|
4411
4417
|
suggestion: "Keep business writes in the governed Command API, or explicitly opt in with graphql.mutations: true."
|
|
4412
4418
|
});
|
|
4413
4419
|
}
|
|
@@ -14823,6 +14829,12 @@ function createExecutionSnapshot(graph, subjects = graph.modules.map((module) =>
|
|
|
14823
14829
|
contexts: subjects.map((subject) => {
|
|
14824
14830
|
const context = createContextPack(graph, subject);
|
|
14825
14831
|
const owner = graph.modules.find((module) => module.name === context.subject);
|
|
14832
|
+
if (owner === undefined)
|
|
14833
|
+
throw new Error(`Execution context owner is missing: ${context.subject}`);
|
|
14834
|
+
const modules = context.modules.map((module) => {
|
|
14835
|
+
const file = executionSourceFile(module.file);
|
|
14836
|
+
return { name: module.name, ...file === undefined ? {} : { file } };
|
|
14837
|
+
});
|
|
14826
14838
|
return {
|
|
14827
14839
|
subject: context.subject,
|
|
14828
14840
|
aliases: [...new Set([
|
|
@@ -14833,10 +14845,7 @@ function createExecutionSnapshot(graph, subjects = graph.modules.map((module) =>
|
|
|
14833
14845
|
...(owner.jobs ?? []).flatMap((job) => [job.name, job.className, job.serviceKey]),
|
|
14834
14846
|
...owner.queries.flatMap((query) => [query.name, query.className])
|
|
14835
14847
|
])],
|
|
14836
|
-
modules
|
|
14837
|
-
name: module.name,
|
|
14838
|
-
...executionSourceFile(module.file) ? { file: executionSourceFile(module.file) } : {}
|
|
14839
|
-
})),
|
|
14848
|
+
modules,
|
|
14840
14849
|
files: context.files,
|
|
14841
14850
|
diagnostics: context.diagnostics.map((diagnostic) => {
|
|
14842
14851
|
const repair = createDiagnosticRepairPlan([diagnostic])[0];
|
|
@@ -15001,21 +15010,21 @@ function requestIdentifier(input) {
|
|
|
15001
15010
|
}
|
|
15002
15011
|
function decodeMetadata(input) {
|
|
15003
15012
|
const envelope = record4(input);
|
|
15004
|
-
if (Object.keys(envelope).some((key) => key !== "version" && key !== "events") || envelope
|
|
15013
|
+
if (Object.keys(envelope).some((key) => key !== "version" && key !== "events") || envelope["version"] !== 1 || !Array.isArray(envelope["events"]) || envelope["events"].length > EXECUTION_CONTEXT_LIMITS.inputEvents)
|
|
15005
15014
|
return invalid();
|
|
15006
|
-
const events = envelope
|
|
15015
|
+
const events = envelope["events"].map((entry) => {
|
|
15007
15016
|
const event = record4(entry);
|
|
15008
|
-
if (Object.keys(event).some((key) => !["kind", "operation", "stage", "phase", "requestId", "durationMs", "attempt", "traceId"].includes(key)) || event
|
|
15017
|
+
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))
|
|
15009
15018
|
return invalid();
|
|
15010
15019
|
return {
|
|
15011
|
-
kind: event
|
|
15012
|
-
operation: event
|
|
15013
|
-
stage: event
|
|
15014
|
-
phase: event
|
|
15015
|
-
...event
|
|
15016
|
-
...event
|
|
15017
|
-
...event
|
|
15018
|
-
...event
|
|
15020
|
+
kind: event["kind"],
|
|
15021
|
+
operation: event["operation"],
|
|
15022
|
+
stage: event["stage"],
|
|
15023
|
+
phase: event["phase"],
|
|
15024
|
+
...event["requestId"] === undefined ? {} : { requestId: event["requestId"] },
|
|
15025
|
+
...event["durationMs"] === undefined ? {} : { durationMs: event["durationMs"] },
|
|
15026
|
+
...event["attempt"] === undefined ? {} : { attempt: event["attempt"] },
|
|
15027
|
+
...event["traceId"] === undefined ? {} : { traceId: event["traceId"] }
|
|
15019
15028
|
};
|
|
15020
15029
|
});
|
|
15021
15030
|
if (Buffer.byteLength(JSON.stringify({ version: 1, events }), "utf8") > EXECUTION_CONTEXT_LIMITS.inputBytes)
|
|
@@ -15180,10 +15189,10 @@ function correlateSnapshot(snapshot, subject, events, requestId) {
|
|
|
15180
15189
|
correlation: "current-graph-only",
|
|
15181
15190
|
deploymentVerified: false,
|
|
15182
15191
|
eventsTrusted: false,
|
|
15183
|
-
modules: modules.slice(0, EXECUTION_CONTEXT_LIMITS.modules).map((module) =>
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
})
|
|
15192
|
+
modules: modules.slice(0, EXECUTION_CONTEXT_LIMITS.modules).map((module) => {
|
|
15193
|
+
const file = executionSourceFile(module.file);
|
|
15194
|
+
return { name: module.name, ...file === undefined ? {} : { file } };
|
|
15195
|
+
}),
|
|
15187
15196
|
files: files.slice(0, EXECUTION_CONTEXT_LIMITS.files),
|
|
15188
15197
|
executionPlans: [...matchedPlans].slice(0, EXECUTION_CONTEXT_LIMITS.plans),
|
|
15189
15198
|
events: retained,
|
|
@@ -25387,10 +25396,11 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25387
25396
|
const providers = bound(names(module.providers.map((provider) => provider.token)), moduleIndex < APPLICATION_DEVELOPMENT_LIMITS2.modules ? remainingProviders : 0);
|
|
25388
25397
|
remainingProviders -= providers.items.length;
|
|
25389
25398
|
omittedProviders += providers.omitted;
|
|
25399
|
+
const file = executionSourceFile(module.file);
|
|
25390
25400
|
developmentModules.push({
|
|
25391
25401
|
name: module.name,
|
|
25392
25402
|
className: module.className,
|
|
25393
|
-
...
|
|
25403
|
+
...file === undefined ? {} : { file },
|
|
25394
25404
|
...module.tags && module.tags.length > 0 ? { tags: names(module.tags) } : {},
|
|
25395
25405
|
providers: providers.items,
|
|
25396
25406
|
controllers: names(module.controllers.map((controller) => controller.className)),
|
|
@@ -25403,6 +25413,7 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25403
25413
|
for (const route of controller.routes) {
|
|
25404
25414
|
const candidates = module.commands.filter((command) => command.className === route.command || command.name === route.command);
|
|
25405
25415
|
const command = candidates.length === 1 ? candidates[0]?.name : undefined;
|
|
25416
|
+
const kinds = schemaKinds(route);
|
|
25406
25417
|
routes.push({
|
|
25407
25418
|
module: module.name,
|
|
25408
25419
|
method: route.method,
|
|
@@ -25411,7 +25422,7 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25411
25422
|
handler: route.handler,
|
|
25412
25423
|
...command === undefined ? {} : { command },
|
|
25413
25424
|
aspects: (route.aspects ?? []).map((aspect) => aspect.name),
|
|
25414
|
-
...
|
|
25425
|
+
...kinds === undefined ? {} : { schemaKinds: kinds }
|
|
25415
25426
|
});
|
|
25416
25427
|
}
|
|
25417
25428
|
}
|
|
@@ -25444,11 +25455,13 @@ function createApplicationDevelopmentContext(graph, options = {}) {
|
|
|
25444
25455
|
const diagnostics = [];
|
|
25445
25456
|
for (const diagnostic of graph.diagnostics ?? []) {
|
|
25446
25457
|
const repair = createDiagnosticRepairPlan([diagnostic])[0];
|
|
25458
|
+
const file = executionSourceFile(diagnostic.file);
|
|
25459
|
+
const line = Number.isSafeInteger(diagnostic.line) && diagnostic.line !== undefined && diagnostic.line > 0 ? diagnostic.line : undefined;
|
|
25447
25460
|
diagnostics.push({
|
|
25448
25461
|
code: diagnostic.code,
|
|
25449
25462
|
severity: diagnostic.severity,
|
|
25450
|
-
...
|
|
25451
|
-
...
|
|
25463
|
+
...file === undefined ? {} : { file },
|
|
25464
|
+
...line === undefined ? {} : { line },
|
|
25452
25465
|
...repair ? { repair: { type: repair.type, readiness: repair.readiness } } : {}
|
|
25453
25466
|
});
|
|
25454
25467
|
}
|
|
@@ -26138,16 +26151,16 @@ async function createDeliveryExecutionContextPack(manifestPath, target, subject,
|
|
|
26138
26151
|
if (!observations || typeof observations !== "object" || Array.isArray(observations))
|
|
26139
26152
|
throw invalid();
|
|
26140
26153
|
const envelope = observations;
|
|
26141
|
-
if (Object.keys(envelope).some((key) => !["version", "events", "delivery"].includes(key)) || !envelope
|
|
26154
|
+
if (Object.keys(envelope).some((key) => !["version", "events", "delivery"].includes(key)) || !envelope["delivery"] || typeof envelope["delivery"] !== "object" || Array.isArray(envelope["delivery"]))
|
|
26142
26155
|
throw invalid();
|
|
26143
|
-
const identity = envelope
|
|
26144
|
-
if (Object.keys(identity).length !== 2 || typeof identity
|
|
26156
|
+
const identity = envelope["delivery"];
|
|
26157
|
+
if (Object.keys(identity).length !== 2 || typeof identity["target"] !== "string" || typeof identity["objectId"] !== "string" || !/^[a-f0-9]{64}$/.test(identity["objectId"]))
|
|
26145
26158
|
throw invalid();
|
|
26146
26159
|
let object;
|
|
26147
26160
|
let snapshot;
|
|
26148
26161
|
try {
|
|
26149
26162
|
const { root, object: found, planned } = await readDeliverySelection(manifestPath, target);
|
|
26150
|
-
if (!found || identity
|
|
26163
|
+
if (!found || identity["target"] !== target || identity["objectId"] !== found.objectId) {
|
|
26151
26164
|
throw new DeliveryContextError("DELIVERY_CONTEXT_IDENTITY_MISMATCH");
|
|
26152
26165
|
}
|
|
26153
26166
|
object = found;
|
|
@@ -26164,7 +26177,7 @@ async function createDeliveryExecutionContextPack(manifestPath, target, subject,
|
|
|
26164
26177
|
throw new DeliveryContextError("DELIVERY_CONTEXT_INTEGRITY_FAILED");
|
|
26165
26178
|
}
|
|
26166
26179
|
const pack = {
|
|
26167
|
-
...executionContextFromSnapshot(snapshot, subject, { version: envelope
|
|
26180
|
+
...executionContextFromSnapshot(snapshot, subject, { version: envelope["version"], events: envelope["events"] }, requestId),
|
|
26168
26181
|
correlation: "verified-build-snapshot",
|
|
26169
26182
|
delivery: { target, objectId: object.objectId, artifactVerified: true }
|
|
26170
26183
|
};
|
|
@@ -26193,7 +26206,7 @@ var init_delivery_context = __esm(() => {
|
|
|
26193
26206
|
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
26194
26207
|
import { lstat as lstat2, readFile as readFile5, realpath as realpath3, rename as rename3, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
26195
26208
|
import { dirname as dirname8, isAbsolute as isAbsolute4, relative as relative9, resolve as resolve14, sep as sep9 } from "node:path";
|
|
26196
|
-
import * as
|
|
26209
|
+
import * as ts13 from "@typescript/typescript6";
|
|
26197
26210
|
async function applyDiagnosticFix(fix, options = {}) {
|
|
26198
26211
|
if (!fix || typeof fix.targetFile !== "string")
|
|
26199
26212
|
throw new Error("Invalid DiagnosticFix");
|
|
@@ -26222,7 +26235,7 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26222
26235
|
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
26223
26236
|
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
26224
26237
|
}
|
|
26225
|
-
content = replaceProperty(source, object, fix.property,
|
|
26238
|
+
content = replaceProperty(source, object, fix.property, ts13.factory.createStringLiteral(fix.value));
|
|
26226
26239
|
break;
|
|
26227
26240
|
}
|
|
26228
26241
|
case "add_module_import": {
|
|
@@ -26233,15 +26246,15 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26233
26246
|
source = parse8(file, withImport);
|
|
26234
26247
|
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
26235
26248
|
const imports = property(object, "imports");
|
|
26236
|
-
if (imports && !
|
|
26249
|
+
if (imports && !ts13.isArrayLiteralExpression(imports.initializer)) {
|
|
26237
26250
|
throw new Error("Module imports must be a static array");
|
|
26238
26251
|
}
|
|
26239
|
-
const values = imports &&
|
|
26240
|
-
if (values.some(
|
|
26252
|
+
const values = imports && ts13.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
26253
|
+
if (values.some(ts13.isSpreadElement))
|
|
26241
26254
|
throw new Error("Module imports cannot contain spread elements");
|
|
26242
|
-
content = values.some((value) =>
|
|
26255
|
+
content = values.some((value) => ts13.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts13.factory.createArrayLiteralExpression([
|
|
26243
26256
|
...values,
|
|
26244
|
-
|
|
26257
|
+
ts13.factory.createIdentifier(fix.symbol)
|
|
26245
26258
|
]));
|
|
26246
26259
|
break;
|
|
26247
26260
|
}
|
|
@@ -26253,24 +26266,24 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26253
26266
|
const command = findClass(source, fix.command);
|
|
26254
26267
|
const object = decoratorObject(command, "Command");
|
|
26255
26268
|
const current = property(object, "permission");
|
|
26256
|
-
if (current && (!
|
|
26269
|
+
if (current && (!ts13.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
26257
26270
|
throw new Error("Command permission already exists with a different value");
|
|
26258
26271
|
}
|
|
26259
|
-
content = current ? original : replaceProperty(source, object, "permission",
|
|
26272
|
+
content = current ? original : replaceProperty(source, object, "permission", ts13.factory.createStringLiteral(permission));
|
|
26260
26273
|
break;
|
|
26261
26274
|
}
|
|
26262
26275
|
case "add_route_parameter_binding": {
|
|
26263
26276
|
const controller = findClass(source, fix.controller);
|
|
26264
|
-
const method = unique(controller.members.filter((member) =>
|
|
26265
|
-
const parameter = unique(method.parameters.filter((candidate) =>
|
|
26277
|
+
const method = unique(controller.members.filter((member) => ts13.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
|
|
26278
|
+
const parameter = unique(method.parameters.filter((candidate) => ts13.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
|
|
26266
26279
|
const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
|
|
26267
26280
|
if (!binding)
|
|
26268
26281
|
throw new Error("Invalid route binding");
|
|
26269
|
-
const decorators =
|
|
26282
|
+
const decorators = ts13.getDecorators(parameter) ?? [];
|
|
26270
26283
|
if (decorators.length > 0)
|
|
26271
26284
|
throw new Error("Parameter already has a decorator");
|
|
26272
|
-
const framework = unique(source.statements.filter((statement) =>
|
|
26273
|
-
if (!
|
|
26285
|
+
const framework = unique(source.statements.filter((statement) => ts13.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts13.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
|
|
26286
|
+
if (!ts13.isImportDeclaration(framework) || !ts13.isStringLiteral(framework.moduleSpecifier)) {
|
|
26274
26287
|
throw new Error("Framework import must be static");
|
|
26275
26288
|
}
|
|
26276
26289
|
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
@@ -26296,20 +26309,22 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
26296
26309
|
return result;
|
|
26297
26310
|
}
|
|
26298
26311
|
function parse8(file, text) {
|
|
26299
|
-
const result =
|
|
26312
|
+
const result = ts13.transpileModule(text, {
|
|
26300
26313
|
fileName: file,
|
|
26301
26314
|
reportDiagnostics: true,
|
|
26302
|
-
compilerOptions: { target:
|
|
26315
|
+
compilerOptions: { target: ts13.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
26303
26316
|
});
|
|
26304
|
-
if (result.diagnostics?.some((item) => item.category ===
|
|
26317
|
+
if (result.diagnostics?.some((item) => item.category === ts13.DiagnosticCategory.Error)) {
|
|
26305
26318
|
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
26306
26319
|
}
|
|
26307
|
-
return
|
|
26320
|
+
return ts13.createSourceFile(file, text, ts13.ScriptTarget.Latest, true, ts13.ScriptKind.TS);
|
|
26308
26321
|
}
|
|
26309
26322
|
function unique(items, description) {
|
|
26310
|
-
|
|
26323
|
+
const [item] = items;
|
|
26324
|
+
if (items.length !== 1 || item === undefined) {
|
|
26311
26325
|
throw new Error(`Expected exactly one ${description}; found ${items.length}`);
|
|
26312
|
-
|
|
26326
|
+
}
|
|
26327
|
+
return item;
|
|
26313
26328
|
}
|
|
26314
26329
|
function identifier3(value) {
|
|
26315
26330
|
if (!/^[A-Za-z_$][\w$]*$/.test(value))
|
|
@@ -26318,50 +26333,50 @@ function identifier3(value) {
|
|
|
26318
26333
|
function nameOf(name) {
|
|
26319
26334
|
if (!name)
|
|
26320
26335
|
return "";
|
|
26321
|
-
return
|
|
26336
|
+
return ts13.isIdentifier(name) || ts13.isStringLiteral(name) || ts13.isNumericLiteral(name) ? name.text : "";
|
|
26322
26337
|
}
|
|
26323
26338
|
function property(object, key) {
|
|
26324
|
-
if (object.properties.some((item) => !
|
|
26339
|
+
if (object.properties.some((item) => !ts13.isPropertyAssignment(item) || ts13.isComputedPropertyName(item.name))) {
|
|
26325
26340
|
throw new Error("Fix requires explicit static object properties");
|
|
26326
26341
|
}
|
|
26327
|
-
const values = object.properties.filter((item) =>
|
|
26342
|
+
const values = object.properties.filter((item) => ts13.isPropertyAssignment(item) && nameOf(item.name) === key);
|
|
26328
26343
|
if (values.length > 1)
|
|
26329
26344
|
throw new Error(`Duplicate '${key}' property`);
|
|
26330
26345
|
return values[0];
|
|
26331
26346
|
}
|
|
26332
26347
|
function stringProperty(object, key) {
|
|
26333
26348
|
const value = property(object, key)?.initializer;
|
|
26334
|
-
return value &&
|
|
26349
|
+
return value && ts13.isStringLiteral(value) ? value.text : undefined;
|
|
26335
26350
|
}
|
|
26336
26351
|
function replaceProperty(source, object, key, value) {
|
|
26337
26352
|
const previous = property(object, key);
|
|
26338
|
-
const replacement =
|
|
26353
|
+
const replacement = ts13.factory.createPropertyAssignment(key, value);
|
|
26339
26354
|
const properties = object.properties.map((item) => item === previous ? replacement : item);
|
|
26340
26355
|
if (!previous)
|
|
26341
26356
|
properties.push(replacement);
|
|
26342
|
-
const updated =
|
|
26343
|
-
return source.text.slice(0, object.getStart(source)) +
|
|
26357
|
+
const updated = ts13.factory.updateObjectLiteralExpression(object, properties);
|
|
26358
|
+
return source.text.slice(0, object.getStart(source)) + ts13.createPrinter().printNode(ts13.EmitHint.Expression, updated, source) + source.text.slice(object.end);
|
|
26344
26359
|
}
|
|
26345
26360
|
function findClass(source, name) {
|
|
26346
|
-
return unique(source.statements.filter((statement) =>
|
|
26361
|
+
return unique(source.statements.filter((statement) => ts13.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
26347
26362
|
}
|
|
26348
26363
|
function decoratorObject(node, name) {
|
|
26349
|
-
const decorator = unique((
|
|
26350
|
-
const argument =
|
|
26351
|
-
if (!argument || !
|
|
26364
|
+
const decorator = unique((ts13.getDecorators(node) ?? []).filter((item) => ts13.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
|
|
26365
|
+
const argument = ts13.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
|
|
26366
|
+
if (!argument || !ts13.isObjectLiteralExpression(argument))
|
|
26352
26367
|
throw new Error(`@${name} requires a static object`);
|
|
26353
26368
|
return argument;
|
|
26354
26369
|
}
|
|
26355
26370
|
function moduleObjects(source) {
|
|
26356
26371
|
const result = [];
|
|
26357
26372
|
for (const statement of source.statements) {
|
|
26358
|
-
if (
|
|
26373
|
+
if (ts13.isClassDeclaration(statement) && (ts13.getDecorators(statement) ?? []).some((item) => ts13.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
|
|
26359
26374
|
result.push(decoratorObject(statement, "Module"));
|
|
26360
26375
|
}
|
|
26361
|
-
if (
|
|
26376
|
+
if (ts13.isVariableStatement(statement)) {
|
|
26362
26377
|
for (const declaration of statement.declarationList.declarations) {
|
|
26363
26378
|
const call = declaration.initializer;
|
|
26364
|
-
if (call &&
|
|
26379
|
+
if (call && ts13.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts13.isObjectLiteralExpression(call.arguments[0])) {
|
|
26365
26380
|
result.push(call.arguments[0]);
|
|
26366
26381
|
}
|
|
26367
26382
|
}
|
|
@@ -26375,19 +26390,19 @@ function importSymbol(source, path, symbol) {
|
|
|
26375
26390
|
const target = resolve14(dirname8(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
26376
26391
|
if (current === target)
|
|
26377
26392
|
return source.text;
|
|
26378
|
-
const matches = source.statements.filter((item) =>
|
|
26393
|
+
const matches = source.statements.filter((item) => ts13.isImportDeclaration(item) && ts13.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
|
|
26379
26394
|
if (matches.length > 1)
|
|
26380
26395
|
throw new Error(`Ambiguous imports from '${path}'`);
|
|
26381
26396
|
const match = matches[0];
|
|
26382
|
-
if (match &&
|
|
26397
|
+
if (match && ts13.isImportDeclaration(match) && match.importClause?.namedBindings && ts13.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
|
|
26383
26398
|
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
26384
26399
|
return source.text;
|
|
26385
26400
|
const bindings = match.importClause.namedBindings;
|
|
26386
|
-
const updated =
|
|
26401
|
+
const updated = ts13.factory.updateNamedImports(bindings, [
|
|
26387
26402
|
...bindings.elements,
|
|
26388
|
-
|
|
26403
|
+
ts13.factory.createImportSpecifier(false, undefined, ts13.factory.createIdentifier(symbol))
|
|
26389
26404
|
]);
|
|
26390
|
-
return source.text.slice(0, bindings.getStart(source)) +
|
|
26405
|
+
return source.text.slice(0, bindings.getStart(source)) + ts13.createPrinter().printNode(ts13.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
|
|
26391
26406
|
}
|
|
26392
26407
|
if (match)
|
|
26393
26408
|
throw new Error(`Import from '${path}' is not a named value import`);
|
|
@@ -26909,7 +26924,7 @@ var init_release_evidence_cli = __esm(() => {
|
|
|
26909
26924
|
import { createHash as createHash12 } from "node:crypto";
|
|
26910
26925
|
import { mkdir as mkdir5, readFile as readFile13 } from "node:fs/promises";
|
|
26911
26926
|
import { dirname as dirname11, relative as relative12, resolve as resolve24 } from "node:path";
|
|
26912
|
-
import * as
|
|
26927
|
+
import * as ts18 from "@typescript/typescript6";
|
|
26913
26928
|
function hash5(value) {
|
|
26914
26929
|
return createHash12("sha256").update(value).digest("hex");
|
|
26915
26930
|
}
|
|
@@ -26949,20 +26964,20 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
26949
26964
|
const rootDir = resolve24(options.rootDir), outDir = resolve24(options.outDir);
|
|
26950
26965
|
const postgrestTypes = resolve24(rootDir, options.postgrestTypes), drizzleSchema = resolve24(rootDir, options.drizzleSchema);
|
|
26951
26966
|
const snapshot = await readFile13(postgrestTypes, "utf8");
|
|
26952
|
-
const syntax =
|
|
26953
|
-
const database = syntax.statements.find((node) => (
|
|
26967
|
+
const syntax = ts18.createSourceFile(postgrestTypes, snapshot, ts18.ScriptTarget.Latest, true);
|
|
26968
|
+
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));
|
|
26954
26969
|
if (!database)
|
|
26955
26970
|
throw new Error("PostgREST snapshot must export Database from the official type generator");
|
|
26956
|
-
const program =
|
|
26971
|
+
const program = ts18.createProgram([postgrestTypes], {
|
|
26957
26972
|
strict: true,
|
|
26958
26973
|
noEmit: true,
|
|
26959
26974
|
skipLibCheck: true,
|
|
26960
26975
|
types: [],
|
|
26961
|
-
target:
|
|
26962
|
-
module:
|
|
26963
|
-
moduleResolution:
|
|
26976
|
+
target: ts18.ScriptTarget.ES2022,
|
|
26977
|
+
module: ts18.ModuleKind.ESNext,
|
|
26978
|
+
moduleResolution: ts18.ModuleResolutionKind.Bundler
|
|
26964
26979
|
});
|
|
26965
|
-
if (
|
|
26980
|
+
if (ts18.getPreEmitDiagnostics(program).length)
|
|
26966
26981
|
throw new Error("PostgREST snapshot has TypeScript errors");
|
|
26967
26982
|
const artifacts = await renderGraphql({
|
|
26968
26983
|
rootDir,
|
|
@@ -26980,11 +26995,11 @@ async function generateDatabaseContracts(options, check = false) {
|
|
|
26980
26995
|
};
|
|
26981
26996
|
await addInput(postgrestTypes);
|
|
26982
26997
|
await addInput(drizzleSchema);
|
|
26983
|
-
const drizzleProgram =
|
|
26998
|
+
const drizzleProgram = ts18.createProgram([drizzleSchema], {
|
|
26984
26999
|
noEmit: true,
|
|
26985
|
-
moduleResolution:
|
|
26986
|
-
module:
|
|
26987
|
-
target:
|
|
27000
|
+
moduleResolution: ts18.ModuleResolutionKind.Bundler,
|
|
27001
|
+
module: ts18.ModuleKind.ESNext,
|
|
27002
|
+
target: ts18.ScriptTarget.ES2022,
|
|
26988
27003
|
types: [],
|
|
26989
27004
|
skipLibCheck: true
|
|
26990
27005
|
});
|
|
@@ -27431,7 +27446,6 @@ function readProjectConfig(rootDir) {
|
|
|
27431
27446
|
skipLibCheck: true
|
|
27432
27447
|
},
|
|
27433
27448
|
errors: [],
|
|
27434
|
-
projectReferences: undefined,
|
|
27435
27449
|
configFingerprint: "defaults"
|
|
27436
27450
|
};
|
|
27437
27451
|
}
|
|
@@ -27453,7 +27467,7 @@ function readProjectConfig(rootDir) {
|
|
|
27453
27467
|
return {
|
|
27454
27468
|
options: parsed.options,
|
|
27455
27469
|
errors: parsed.errors,
|
|
27456
|
-
projectReferences: parsed.projectReferences,
|
|
27470
|
+
...parsed.projectReferences === undefined ? {} : { projectReferences: parsed.projectReferences },
|
|
27457
27471
|
configFingerprint: JSON.stringify([...configReads])
|
|
27458
27472
|
};
|
|
27459
27473
|
}
|
|
@@ -30661,7 +30675,7 @@ import { join as join4 } from "node:path";
|
|
|
30661
30675
|
// src/type-safety.ts
|
|
30662
30676
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
30663
30677
|
import { dirname as dirname3, join as join3, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
|
|
30664
|
-
import * as
|
|
30678
|
+
import * as ts10 from "@typescript/typescript6";
|
|
30665
30679
|
|
|
30666
30680
|
// src/sql-safety.ts
|
|
30667
30681
|
import * as ts8 from "@typescript/typescript6";
|
|
@@ -30704,6 +30718,198 @@ function scanDrizzleSql(sourceFile, checker, file, strict) {
|
|
|
30704
30718
|
return diagnostics;
|
|
30705
30719
|
}
|
|
30706
30720
|
|
|
30721
|
+
// src/source-semantics.ts
|
|
30722
|
+
import * as ts9 from "@typescript/typescript6";
|
|
30723
|
+
var SOURCE_SEMANTIC_DIAGNOSTIC_CODES = {
|
|
30724
|
+
"source-unsafe-any": { errorCode: "SC6009", docsUrl: "https://supacloud.dev/errors/SC6009" },
|
|
30725
|
+
"source-floating-promise": { errorCode: "SC6010", docsUrl: "https://supacloud.dev/errors/SC6010" },
|
|
30726
|
+
"source-non-exhaustive-switch": { errorCode: "SC6011", docsUrl: "https://supacloud.dev/errors/SC6011" }
|
|
30727
|
+
};
|
|
30728
|
+
function scanSourceSemantics(source, checker, file, rootDir) {
|
|
30729
|
+
const diagnostics = [];
|
|
30730
|
+
const report = (code, node, message) => {
|
|
30731
|
+
diagnostics.push({
|
|
30732
|
+
severity: "error",
|
|
30733
|
+
code,
|
|
30734
|
+
...SOURCE_SEMANTIC_DIAGNOSTIC_CODES[code],
|
|
30735
|
+
file,
|
|
30736
|
+
message,
|
|
30737
|
+
line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1
|
|
30738
|
+
});
|
|
30739
|
+
};
|
|
30740
|
+
const unsafe = (value, target) => {
|
|
30741
|
+
if (isUnknownBoundary(target, checker) || containsAny(target, checker, new Set, rootDir))
|
|
30742
|
+
return;
|
|
30743
|
+
if (containsAny(checker.getTypeAtLocation(value), checker, new Set, rootDir)) {
|
|
30744
|
+
report("source-unsafe-any", value, "An any-containing value cannot enter a concrete type. Quarantine it as unknown and decode it before use.");
|
|
30745
|
+
}
|
|
30746
|
+
};
|
|
30747
|
+
const declared = (node) => {
|
|
30748
|
+
let hasAnyKeyword = false;
|
|
30749
|
+
const visitType = (child) => {
|
|
30750
|
+
if (child.kind === ts9.SyntaxKind.AnyKeyword)
|
|
30751
|
+
hasAnyKeyword = true;
|
|
30752
|
+
ts9.forEachChild(child, visitType);
|
|
30753
|
+
};
|
|
30754
|
+
visitType(node);
|
|
30755
|
+
if (!hasAnyKeyword && containsAny(checker.getTypeAtLocation(node), checker, new Set, rootDir)) {
|
|
30756
|
+
report("source-unsafe-any", node, "Declared application types must not hide any through aliases or generic arguments.");
|
|
30757
|
+
}
|
|
30758
|
+
};
|
|
30759
|
+
const visit = (node) => {
|
|
30760
|
+
if (ts9.isTypeAliasDeclaration(node))
|
|
30761
|
+
declared(node.type);
|
|
30762
|
+
if ((ts9.isVariableDeclaration(node) || ts9.isParameter(node) || ts9.isPropertyDeclaration(node) || ts9.isPropertySignature(node)) && node.type)
|
|
30763
|
+
declared(node.type);
|
|
30764
|
+
if (ts9.isVariableDeclaration(node) && node.initializer) {
|
|
30765
|
+
const type = checker.getTypeAtLocation(node.name);
|
|
30766
|
+
if (node.type)
|
|
30767
|
+
unsafe(node.initializer, type);
|
|
30768
|
+
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)) {
|
|
30769
|
+
report("source-unsafe-any", node.name, "Inferred values must not contain any, including nested and generic result types.");
|
|
30770
|
+
}
|
|
30771
|
+
}
|
|
30772
|
+
if (ts9.isPropertyDeclaration(node) && !node.type && node.initializer && containsAny(checker.getTypeAtLocation(node.name), checker, new Set, rootDir)) {
|
|
30773
|
+
report("source-unsafe-any", node.name, "Inferred class fields must not propagate any. Decode the value or quarantine it as unknown.");
|
|
30774
|
+
}
|
|
30775
|
+
if ((ts9.isFunctionDeclaration(node) || ts9.isMethodDeclaration(node) || ts9.isArrowFunction(node) || ts9.isFunctionExpression(node)) && !node.type && node.body) {
|
|
30776
|
+
const signature = checker.getSignatureFromDeclaration(node);
|
|
30777
|
+
if (signature && containsAny(checker.getReturnTypeOfSignature(signature), checker, new Set, rootDir)) {
|
|
30778
|
+
report("source-unsafe-any", node.name ?? node, "Inferred function results must not propagate any. Return unknown at the boundary or a decoded concrete result.");
|
|
30779
|
+
}
|
|
30780
|
+
}
|
|
30781
|
+
if (ts9.isFunctionLike(node) && node.type)
|
|
30782
|
+
declared(node.type);
|
|
30783
|
+
if (ts9.isBinaryExpression(node) && node.operatorToken.kind === ts9.SyntaxKind.EqualsToken) {
|
|
30784
|
+
unsafe(node.right, checker.getTypeAtLocation(node.left));
|
|
30785
|
+
}
|
|
30786
|
+
if (ts9.isAsExpression(node) || ts9.isTypeAssertionExpression(node)) {
|
|
30787
|
+
unsafe(node.expression, checker.getTypeAtLocation(node));
|
|
30788
|
+
}
|
|
30789
|
+
if (ts9.isReturnStatement(node) && node.expression) {
|
|
30790
|
+
let owner = node.parent;
|
|
30791
|
+
while (owner && !ts9.isFunctionLike(owner))
|
|
30792
|
+
owner = owner.parent;
|
|
30793
|
+
if (owner && ts9.isFunctionLike(owner) && owner.type) {
|
|
30794
|
+
const signature = checker.getSignatureFromDeclaration(owner);
|
|
30795
|
+
if (signature)
|
|
30796
|
+
unsafe(node.expression, checker.getReturnTypeOfSignature(signature));
|
|
30797
|
+
}
|
|
30798
|
+
}
|
|
30799
|
+
if (ts9.isCallExpression(node)) {
|
|
30800
|
+
const signature = checker.getResolvedSignature(node);
|
|
30801
|
+
const parameters = signature?.getParameters() ?? [];
|
|
30802
|
+
node.arguments.forEach((argument, index) => {
|
|
30803
|
+
const parameter = parameters[index] ?? parameters.at(-1);
|
|
30804
|
+
if (!parameter)
|
|
30805
|
+
return;
|
|
30806
|
+
const type = checker.getTypeOfSymbolAtLocation(parameter, node);
|
|
30807
|
+
const declaration = parameter.valueDeclaration;
|
|
30808
|
+
const rest = declaration && ts9.isParameter(declaration) && declaration.dotDotDotToken;
|
|
30809
|
+
const target = rest ? checker.getIndexTypeOfType(type, ts9.IndexKind.Number) ?? type : type;
|
|
30810
|
+
unsafe(argument, target);
|
|
30811
|
+
});
|
|
30812
|
+
}
|
|
30813
|
+
if (ts9.isExpressionStatement(node)) {
|
|
30814
|
+
const expression = unwrap(node.expression);
|
|
30815
|
+
if (isPromise(checker.getTypeAtLocation(expression), checker, expression) && !handlesRejection(expression, checker)) {
|
|
30816
|
+
report("source-floating-promise", node, "Promise work must be awaited, returned, or have a callable rejection handler. void does not establish cancellation ownership.");
|
|
30817
|
+
}
|
|
30818
|
+
}
|
|
30819
|
+
if (ts9.isSwitchStatement(node)) {
|
|
30820
|
+
const type = checker.getTypeAtLocation(node.expression);
|
|
30821
|
+
const members = type.isUnion() ? type.types : [type];
|
|
30822
|
+
if (members.every(isFiniteLiteral)) {
|
|
30823
|
+
const cases = node.caseBlock.clauses.filter(ts9.isCaseClause);
|
|
30824
|
+
const missing = members.filter((member) => !cases.some((clause) => sameLiteral(member, checker.getTypeAtLocation(clause.expression))));
|
|
30825
|
+
if (missing.length > 0) {
|
|
30826
|
+
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.`);
|
|
30827
|
+
}
|
|
30828
|
+
}
|
|
30829
|
+
}
|
|
30830
|
+
ts9.forEachChild(node, visit);
|
|
30831
|
+
};
|
|
30832
|
+
visit(source);
|
|
30833
|
+
return diagnostics;
|
|
30834
|
+
}
|
|
30835
|
+
function containsAny(type, checker, seen, rootDir) {
|
|
30836
|
+
if (type.flags & ts9.TypeFlags.Any)
|
|
30837
|
+
return true;
|
|
30838
|
+
if (seen.has(type))
|
|
30839
|
+
return false;
|
|
30840
|
+
seen.add(type);
|
|
30841
|
+
if (type.isUnionOrIntersection())
|
|
30842
|
+
return type.types.some((part) => containsAny(part, checker, seen, rootDir));
|
|
30843
|
+
const declarations = type.getSymbol()?.declarations ?? [];
|
|
30844
|
+
if (declarations.some((declaration) => ts9.isClassDeclaration(declaration) && (declaration.getSourceFile().isDeclarationFile || declaration.getSourceFile().fileName.replaceAll("\\", "/").includes("/node_modules/"))))
|
|
30845
|
+
return false;
|
|
30846
|
+
const arguments_ = isTypeReference2(type) ? checker.getTypeArguments(type) : type.aliasTypeArguments ?? [];
|
|
30847
|
+
if (arguments_.some((argument) => containsAny(argument, checker, seen, rootDir)))
|
|
30848
|
+
return true;
|
|
30849
|
+
if (checker.getSignaturesOfType(type, ts9.SignatureKind.Call).some((signature) => {
|
|
30850
|
+
const declaration = signature.getDeclaration();
|
|
30851
|
+
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)));
|
|
30852
|
+
}))
|
|
30853
|
+
return true;
|
|
30854
|
+
return checker.getPropertiesOfType(type).some((property) => {
|
|
30855
|
+
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
30856
|
+
return declaration !== undefined && isWithinRoot(declaration.getSourceFile().fileName, rootDir) && containsAny(checker.getTypeOfSymbolAtLocation(property, declaration), checker, seen, rootDir);
|
|
30857
|
+
});
|
|
30858
|
+
}
|
|
30859
|
+
function isWithinRoot(file, rootDir) {
|
|
30860
|
+
const normalizedFile = file.replaceAll("\\", "/");
|
|
30861
|
+
const normalizedRoot = rootDir.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
30862
|
+
return normalizedFile === normalizedRoot || normalizedFile.startsWith(`${normalizedRoot}/`);
|
|
30863
|
+
}
|
|
30864
|
+
function isUnknownBoundary(type, checker) {
|
|
30865
|
+
if (type.flags & (ts9.TypeFlags.Unknown | ts9.TypeFlags.Void))
|
|
30866
|
+
return true;
|
|
30867
|
+
const promised = promiseArgument(type, checker);
|
|
30868
|
+
return promised !== undefined && Boolean(promised.flags & ts9.TypeFlags.Unknown);
|
|
30869
|
+
}
|
|
30870
|
+
function unwrap(expression) {
|
|
30871
|
+
while (ts9.isParenthesizedExpression(expression) || ts9.isVoidExpression(expression))
|
|
30872
|
+
expression = expression.expression;
|
|
30873
|
+
return expression;
|
|
30874
|
+
}
|
|
30875
|
+
function isPromise(type, checker, node) {
|
|
30876
|
+
return type.isUnion() ? type.types.some((part) => isPromise(part, checker, node)) : promiseArgument(type, checker) !== undefined;
|
|
30877
|
+
}
|
|
30878
|
+
function handlesRejection(expression, checker) {
|
|
30879
|
+
if (!ts9.isCallExpression(expression) || !ts9.isPropertyAccessExpression(expression.expression))
|
|
30880
|
+
return false;
|
|
30881
|
+
const { name, expression: receiver } = expression.expression;
|
|
30882
|
+
if (!isPromise(checker.getTypeAtLocation(receiver), checker, receiver))
|
|
30883
|
+
return false;
|
|
30884
|
+
const handler = name.text === "catch" ? expression.arguments[0] : name.text === "then" ? expression.arguments[1] : undefined;
|
|
30885
|
+
return handler !== undefined && checker.getTypeAtLocation(handler).getCallSignatures().length > 0;
|
|
30886
|
+
}
|
|
30887
|
+
function isFiniteLiteral(type) {
|
|
30888
|
+
return Boolean(type.flags & (ts9.TypeFlags.StringLiteral | ts9.TypeFlags.NumberLiteral | ts9.TypeFlags.BigIntLiteral | ts9.TypeFlags.BooleanLiteral | ts9.TypeFlags.Null | ts9.TypeFlags.Undefined));
|
|
30889
|
+
}
|
|
30890
|
+
function sameLiteral(left, right) {
|
|
30891
|
+
if (left.flags !== right.flags)
|
|
30892
|
+
return false;
|
|
30893
|
+
if (left.isStringLiteral() && right.isStringLiteral())
|
|
30894
|
+
return left.value === right.value;
|
|
30895
|
+
if (left.isNumberLiteral() && right.isNumberLiteral())
|
|
30896
|
+
return left.value === right.value;
|
|
30897
|
+
return left === right;
|
|
30898
|
+
}
|
|
30899
|
+
function isTypeReference2(type) {
|
|
30900
|
+
return Boolean(type.flags & ts9.TypeFlags.Object) && "objectFlags" in type && typeof type.objectFlags === "number" && Boolean(type.objectFlags & ts9.ObjectFlags.Reference) && "target" in type;
|
|
30901
|
+
}
|
|
30902
|
+
function promiseArgument(type, checker) {
|
|
30903
|
+
if (type.flags & (ts9.TypeFlags.Any | ts9.TypeFlags.Unknown | ts9.TypeFlags.Never))
|
|
30904
|
+
return;
|
|
30905
|
+
const then = checker.getPropertyOfType(type, "then");
|
|
30906
|
+
const declaration = then?.valueDeclaration ?? then?.declarations?.[0];
|
|
30907
|
+
if (!then || !declaration || checker.getTypeOfSymbolAtLocation(then, declaration).getCallSignatures().length === 0)
|
|
30908
|
+
return;
|
|
30909
|
+
const awaited = checker.getAwaitedType(type);
|
|
30910
|
+
return awaited !== type ? awaited : undefined;
|
|
30911
|
+
}
|
|
30912
|
+
|
|
30707
30913
|
// src/type-safety.ts
|
|
30708
30914
|
var DEFAULT_EXCLUDES = [
|
|
30709
30915
|
"**/*.test.ts",
|
|
@@ -30718,6 +30924,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
30718
30924
|
];
|
|
30719
30925
|
var TYPE_SAFETY_DIAGNOSTIC_CODES = {
|
|
30720
30926
|
...SQL_SAFETY_DIAGNOSTIC_CODES,
|
|
30927
|
+
...SOURCE_SEMANTIC_DIAGNOSTIC_CODES,
|
|
30721
30928
|
"generated-any": { errorCode: "SC6001", docsUrl: "https://supacloud.dev/errors/SC6001" },
|
|
30722
30929
|
"source-any": { errorCode: "SC6002", docsUrl: "https://supacloud.dev/errors/SC6002" },
|
|
30723
30930
|
"source-type-assertion": { errorCode: "SC6003", docsUrl: "https://supacloud.dev/errors/SC6003" },
|
|
@@ -30730,7 +30937,7 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
30730
30937
|
for (const [file, content] of Object.entries(artifacts)) {
|
|
30731
30938
|
if (content === undefined)
|
|
30732
30939
|
continue;
|
|
30733
|
-
const sourceFile =
|
|
30940
|
+
const sourceFile = ts10.createSourceFile(file, content, ts10.ScriptTarget.Latest, true, ts10.ScriptKind.TS);
|
|
30734
30941
|
for (const node of descendantsOfKind2(sourceFile, isAnyKeyword)) {
|
|
30735
30942
|
diagnostics.push(makeDiagnostic("generated-any", `生成产物 ${file} 包含 any;严格生成模式要求使用 unknown、具体接口或泛型约束。`, sourceFile, node, strict));
|
|
30736
30943
|
}
|
|
@@ -30739,36 +30946,58 @@ function scanGeneratedArtifacts(artifacts, strict = true) {
|
|
|
30739
30946
|
}
|
|
30740
30947
|
function scanProductionSource(options) {
|
|
30741
30948
|
const rootDir = resolve3(options.rootDir);
|
|
30742
|
-
const configPath =
|
|
30949
|
+
const configPath = ts10.findConfigFile(rootDir, ts10.sys.fileExists) ?? join3(rootDir, "tsconfig.json");
|
|
30743
30950
|
const projectConfig = existsSync2(configPath) ? readProjectConfig2(configPath) : {
|
|
30744
30951
|
options: {
|
|
30745
30952
|
strict: true,
|
|
30953
|
+
experimentalDecorators: true,
|
|
30746
30954
|
skipLibCheck: true,
|
|
30747
|
-
target:
|
|
30748
|
-
module:
|
|
30749
|
-
moduleResolution:
|
|
30955
|
+
target: ts10.ScriptTarget.ES2022,
|
|
30956
|
+
module: ts10.ModuleKind.ESNext,
|
|
30957
|
+
moduleResolution: ts10.ModuleResolutionKind.Bundler
|
|
30750
30958
|
},
|
|
30751
30959
|
errors: []
|
|
30752
30960
|
};
|
|
30753
30961
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
30754
|
-
const rootNames =
|
|
30755
|
-
const compilerOptions = {
|
|
30756
|
-
|
|
30962
|
+
const rootNames = ts10.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist"], include).filter((file) => isProductionSourcePath(rootDir, file, [...DEFAULT_EXCLUDES, ...options.exclude ?? []]));
|
|
30963
|
+
const compilerOptions = {
|
|
30964
|
+
...projectConfig.options,
|
|
30965
|
+
noCheck: false,
|
|
30966
|
+
strict: true,
|
|
30967
|
+
noImplicitAny: true,
|
|
30968
|
+
strictNullChecks: true,
|
|
30969
|
+
strictFunctionTypes: true,
|
|
30970
|
+
strictBindCallApply: true,
|
|
30971
|
+
strictPropertyInitialization: true,
|
|
30972
|
+
strictBuiltinIteratorReturn: true,
|
|
30973
|
+
noImplicitThis: true,
|
|
30974
|
+
useUnknownInCatchVariables: true,
|
|
30975
|
+
alwaysStrict: true,
|
|
30976
|
+
noUncheckedIndexedAccess: true,
|
|
30977
|
+
exactOptionalPropertyTypes: true,
|
|
30978
|
+
noImplicitOverride: true,
|
|
30979
|
+
noPropertyAccessFromIndexSignature: true,
|
|
30980
|
+
noFallthroughCasesInSwitch: true,
|
|
30981
|
+
forceConsistentCasingInFileNames: true,
|
|
30982
|
+
noEmit: true
|
|
30983
|
+
};
|
|
30984
|
+
const host = ts10.createCompilerHost(compilerOptions);
|
|
30757
30985
|
host.getCurrentDirectory = () => dirname3(configPath);
|
|
30758
|
-
const program =
|
|
30986
|
+
const program = ts10.createProgram(rootNames, compilerOptions, host);
|
|
30759
30987
|
const outDir = options.outDir ? normalizeRelative(rootDir, options.outDir) : undefined;
|
|
30760
30988
|
const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
|
|
30761
30989
|
const sourceFiles = program.getSourceFiles().filter((sourceFile) => isProductionSource(rootDir, sourceFile, excludes, outDir));
|
|
30762
30990
|
const diagnostics = [...projectConfig.errors, ...program.getOptionsDiagnostics()].map((diagnostic) => ({
|
|
30763
30991
|
severity: "error",
|
|
30764
30992
|
code: "source-config",
|
|
30765
|
-
message:
|
|
30993
|
+
message: ts10.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
30766
30994
|
`),
|
|
30767
30995
|
file: diagnostic.file ? normalizeRelative(rootDir, diagnostic.file.fileName) : normalizeRelative(rootDir, configPath),
|
|
30768
30996
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
30769
30997
|
errorCode: `TS${diagnostic.code}`
|
|
30770
30998
|
}));
|
|
30771
30999
|
const checker = program.getTypeChecker();
|
|
31000
|
+
const moduleResolutionCodes = new Set([2307, 2688, 2792]);
|
|
30772
31001
|
for (const diagnostic of [
|
|
30773
31002
|
...program.getGlobalDiagnostics(),
|
|
30774
31003
|
...sourceFiles.flatMap((sourceFile) => [
|
|
@@ -30778,8 +31007,8 @@ function scanProductionSource(options) {
|
|
|
30778
31007
|
]) {
|
|
30779
31008
|
diagnostics.push({
|
|
30780
31009
|
severity: "error",
|
|
30781
|
-
code: "source-typescript",
|
|
30782
|
-
message:
|
|
31010
|
+
code: moduleResolutionCodes.has(diagnostic.code) ? "source-config" : "source-typescript",
|
|
31011
|
+
message: ts10.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
30783
31012
|
`),
|
|
30784
31013
|
...diagnostic.file ? { file: normalizeRelative(rootDir, diagnostic.file.fileName) } : {},
|
|
30785
31014
|
...diagnostic.file && diagnostic.start !== undefined ? { line: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line + 1 } : {},
|
|
@@ -30788,10 +31017,11 @@ function scanProductionSource(options) {
|
|
|
30788
31017
|
}
|
|
30789
31018
|
for (const sourceFile of sourceFiles) {
|
|
30790
31019
|
scanSourceFile(sourceFile, checker, rootDir, diagnostics, options.strict ?? false);
|
|
31020
|
+
diagnostics.push(...scanSourceSemantics(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), rootDir));
|
|
30791
31021
|
diagnostics.push(...scanDrizzleSql(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), options.strict ?? false));
|
|
30792
|
-
const scanner =
|
|
30793
|
-
for (let kind = scanner.scan();kind !==
|
|
30794
|
-
if ((kind ===
|
|
31022
|
+
const scanner = ts10.createScanner(ts10.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
|
|
31023
|
+
for (let kind = scanner.scan();kind !== ts10.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
|
|
31024
|
+
if ((kind === ts10.SyntaxKind.SingleLineCommentTrivia || kind === ts10.SyntaxKind.MultiLineCommentTrivia) && /@ts-(?:ignore|nocheck|expect-error)\b/.test(scanner.getTokenText())) {
|
|
30795
31025
|
diagnostics.push({
|
|
30796
31026
|
severity: "error",
|
|
30797
31027
|
code: "source-type-suppression",
|
|
@@ -30811,22 +31041,22 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
30811
31041
|
diagnostics.push(makeDiagnostic("source-any", "生产源码使用了显式 any;请改用 unknown、具体接口或泛型约束。", sourceFile, node, strict, rootDir));
|
|
30812
31042
|
}
|
|
30813
31043
|
for (const node of descendants(sourceFile)) {
|
|
30814
|
-
if (
|
|
30815
|
-
if (
|
|
31044
|
+
if (ts10.isAsExpression(node)) {
|
|
31045
|
+
if (ts10.isAsExpression(node.parent) || ts10.isTypeAssertionExpression(node.parent))
|
|
30816
31046
|
continue;
|
|
30817
31047
|
const assertedType = node.type.getText(sourceFile);
|
|
30818
31048
|
if (assertedType === "const")
|
|
30819
31049
|
continue;
|
|
30820
31050
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
30821
|
-
} else if (
|
|
30822
|
-
if (
|
|
31051
|
+
} else if (ts10.isTypeAssertionExpression(node)) {
|
|
31052
|
+
if (ts10.isAsExpression(node.parent) || ts10.isTypeAssertionExpression(node.parent))
|
|
30823
31053
|
continue;
|
|
30824
31054
|
diagnostics.push(makeDiagnostic("source-type-assertion", `生产源码包含类型断言 ${node.getText(sourceFile)};请优先使用类型守卫、satisfies 或显式边界解析。`, sourceFile, node, strict, rootDir));
|
|
30825
|
-
} else if (
|
|
31055
|
+
} else if (ts10.isNonNullExpression(node)) {
|
|
30826
31056
|
diagnostics.push(makeDiagnostic("source-non-null-assertion", `生产源码包含非空断言 ${node.getText(sourceFile)};请显式处理 null/undefined。`, sourceFile, node, strict, rootDir));
|
|
30827
31057
|
}
|
|
30828
31058
|
}
|
|
30829
|
-
for (const declaration of descendantsOfKind2(sourceFile,
|
|
31059
|
+
for (const declaration of descendantsOfKind2(sourceFile, ts10.isVariableDeclaration)) {
|
|
30830
31060
|
const initializer = declaration.initializer;
|
|
30831
31061
|
if (!initializer || declaration.type)
|
|
30832
31062
|
continue;
|
|
@@ -30842,11 +31072,11 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
30842
31072
|
if (isLetDeclaration(declaration) && isLiteralSyntax(initializer) && !isLiteralType(declarationType)) {
|
|
30843
31073
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `变量 ${declaration.name.getText(sourceFile)} 的字面量类型从 ${checker.typeToString(initializerType, initializer)} 隐式宽化为 ${checker.typeToString(declarationType, declaration)};请补充类型或使用 const。`, sourceFile, declaration, strict, rootDir));
|
|
30844
31074
|
}
|
|
30845
|
-
if (
|
|
31075
|
+
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))) {
|
|
30846
31076
|
diagnostics.push(makeDiagnostic("source-implicit-widening", `常量对象 ${declaration.name.getText(sourceFile)} 的字面量属性会隐式宽化;请补充对象类型或使用 as const。`, sourceFile, declaration, strict, rootDir));
|
|
30847
31077
|
}
|
|
30848
31078
|
}
|
|
30849
|
-
for (const parameter of descendantsOfKind2(sourceFile,
|
|
31079
|
+
for (const parameter of descendantsOfKind2(sourceFile, ts10.isParameter)) {
|
|
30850
31080
|
if (parameter.type)
|
|
30851
31081
|
continue;
|
|
30852
31082
|
for (const name of bindingNames(parameter.name)) {
|
|
@@ -30857,10 +31087,10 @@ function scanSourceFile(sourceFile, checker, rootDir, diagnostics, strict) {
|
|
|
30857
31087
|
}
|
|
30858
31088
|
}
|
|
30859
31089
|
function readProjectConfig2(configPath) {
|
|
30860
|
-
const config =
|
|
31090
|
+
const config = ts10.readConfigFile(configPath, (file) => readFileSync2(file, "utf8"));
|
|
30861
31091
|
if (config.error)
|
|
30862
31092
|
return { options: {}, errors: [config.error] };
|
|
30863
|
-
const parsed =
|
|
31093
|
+
const parsed = ts10.parseJsonConfigFileContent(config.config, ts10.sys, dirname3(configPath));
|
|
30864
31094
|
return { options: parsed.options, errors: parsed.errors };
|
|
30865
31095
|
}
|
|
30866
31096
|
function isProductionSource(rootDir, sourceFile, excludes, outDir) {
|
|
@@ -30880,42 +31110,42 @@ function globMatches(value, pattern) {
|
|
|
30880
31110
|
return new RegExp(`^${escaped}$`).test(value);
|
|
30881
31111
|
}
|
|
30882
31112
|
function bindingNames(name) {
|
|
30883
|
-
if (
|
|
31113
|
+
if (ts10.isIdentifier(name))
|
|
30884
31114
|
return [name];
|
|
30885
|
-
return name.elements.flatMap((element) =>
|
|
31115
|
+
return name.elements.flatMap((element) => ts10.isBindingElement(element) ? bindingNames(element.name) : []);
|
|
30886
31116
|
}
|
|
30887
31117
|
function isLiteralExpression(node) {
|
|
30888
31118
|
if (!node)
|
|
30889
31119
|
return false;
|
|
30890
31120
|
return [
|
|
30891
|
-
|
|
30892
|
-
|
|
30893
|
-
|
|
30894
|
-
|
|
31121
|
+
ts10.SyntaxKind.StringLiteral,
|
|
31122
|
+
ts10.SyntaxKind.NumericLiteral,
|
|
31123
|
+
ts10.SyntaxKind.TrueKeyword,
|
|
31124
|
+
ts10.SyntaxKind.FalseKeyword
|
|
30895
31125
|
].includes(node.kind);
|
|
30896
31126
|
}
|
|
30897
31127
|
function isLiteralSyntax(node) {
|
|
30898
|
-
return
|
|
31128
|
+
return ts10.isStringLiteral(node) || ts10.isNumericLiteral(node) || node.kind === ts10.SyntaxKind.TrueKeyword || node.kind === ts10.SyntaxKind.FalseKeyword;
|
|
30899
31129
|
}
|
|
30900
31130
|
function isLiteralType(type) {
|
|
30901
|
-
return (type.flags & (
|
|
31131
|
+
return (type.flags & (ts10.TypeFlags.StringLiteral | ts10.TypeFlags.NumberLiteral | ts10.TypeFlags.BooleanLiteral | ts10.TypeFlags.BigIntLiteral)) !== 0;
|
|
30902
31132
|
}
|
|
30903
31133
|
function isAnyType(type) {
|
|
30904
|
-
return (type.flags &
|
|
31134
|
+
return (type.flags & ts10.TypeFlags.Any) !== 0;
|
|
30905
31135
|
}
|
|
30906
31136
|
function isLetDeclaration(declaration) {
|
|
30907
|
-
return
|
|
31137
|
+
return ts10.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts10.NodeFlags.Let) !== 0;
|
|
30908
31138
|
}
|
|
30909
31139
|
function isConstDeclaration(declaration) {
|
|
30910
|
-
return
|
|
31140
|
+
return ts10.isVariableDeclarationList(declaration.parent) && (declaration.parent.flags & ts10.NodeFlags.Const) !== 0;
|
|
30911
31141
|
}
|
|
30912
31142
|
function descendants(root) {
|
|
30913
31143
|
const result = [];
|
|
30914
31144
|
const visit = (node) => {
|
|
30915
31145
|
result.push(node);
|
|
30916
|
-
|
|
31146
|
+
ts10.forEachChild(node, visit);
|
|
30917
31147
|
};
|
|
30918
|
-
|
|
31148
|
+
ts10.forEachChild(root, visit);
|
|
30919
31149
|
return result;
|
|
30920
31150
|
}
|
|
30921
31151
|
function descendantsOfKind2(root, predicate) {
|
|
@@ -30923,9 +31153,9 @@ function descendantsOfKind2(root, predicate) {
|
|
|
30923
31153
|
const visit = (node) => {
|
|
30924
31154
|
if (predicate(node))
|
|
30925
31155
|
result.push(node);
|
|
30926
|
-
|
|
31156
|
+
ts10.forEachChild(node, visit);
|
|
30927
31157
|
};
|
|
30928
|
-
|
|
31158
|
+
ts10.forEachChild(root, visit);
|
|
30929
31159
|
return result;
|
|
30930
31160
|
}
|
|
30931
31161
|
function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir) {
|
|
@@ -30933,7 +31163,7 @@ function makeDiagnostic(code, message, fileOrSourceFile, node, strict, rootDir)
|
|
|
30933
31163
|
const file = typeof fileOrSourceFile === "string" ? fileOrSourceFile : rootDir ? normalizeRelative(rootDir, fileOrSourceFile.fileName) : fileOrSourceFile.fileName;
|
|
30934
31164
|
const meta = TYPE_SAFETY_DIAGNOSTIC_CODES[code];
|
|
30935
31165
|
return {
|
|
30936
|
-
severity: strict ? "error" : "warn",
|
|
31166
|
+
severity: strict || code === "source-any" || code === "generated-any" ? "error" : "warn",
|
|
30937
31167
|
code,
|
|
30938
31168
|
message,
|
|
30939
31169
|
file,
|
|
@@ -30946,7 +31176,7 @@ function normalizeRelative(rootDir, filePath) {
|
|
|
30946
31176
|
return relative3(rootDir, filePath).split(sep3).join("/").replace(/^\.\//, "");
|
|
30947
31177
|
}
|
|
30948
31178
|
function isAnyKeyword(node) {
|
|
30949
|
-
return node.kind ===
|
|
31179
|
+
return node.kind === ts10.SyntaxKind.AnyKeyword;
|
|
30950
31180
|
}
|
|
30951
31181
|
|
|
30952
31182
|
// src/compile.ts
|
|
@@ -31107,11 +31337,12 @@ async function compileProject(options) {
|
|
|
31107
31337
|
}, options.strict ?? false));
|
|
31108
31338
|
}
|
|
31109
31339
|
const hasErrors = diagnostics.some((diagnostic) => diagnostic.severity === "error");
|
|
31340
|
+
const hasTypeErrors = diagnostics.some(({ severity, code }) => severity === "error" && (code.startsWith("source-") || code === "generated-any"));
|
|
31110
31341
|
const generatedOptions = {
|
|
31111
31342
|
...options,
|
|
31112
31343
|
...options.cache ? { artifactHashes: options.cache.generatedHashes } : {}
|
|
31113
31344
|
};
|
|
31114
|
-
const written = !hasErrors || options.writeOnError === true ? await writeRenderedApplication(rendered, generatedOptions) : [];
|
|
31345
|
+
const written = !hasErrors || options.writeOnError === true && !hasTypeErrors ? await writeRenderedApplication(rendered, generatedOptions) : [];
|
|
31115
31346
|
if (!hasErrors) {
|
|
31116
31347
|
for (const [filename, content] of Object.entries(graphql.files)) {
|
|
31117
31348
|
const path = join4(options.outDir, filename);
|
|
@@ -31208,8 +31439,8 @@ async function checkProject(options) {
|
|
|
31208
31439
|
}
|
|
31209
31440
|
function resolveTypeSafety(options) {
|
|
31210
31441
|
return {
|
|
31211
|
-
noAnyInGenerated:
|
|
31212
|
-
scanProductionSource:
|
|
31442
|
+
noAnyInGenerated: true,
|
|
31443
|
+
scanProductionSource: true,
|
|
31213
31444
|
...options.typeSafety?.exclude ? { exclude: options.typeSafety.exclude } : {}
|
|
31214
31445
|
};
|
|
31215
31446
|
}
|
|
@@ -31494,19 +31725,7 @@ function createIncrementalCompiler() {
|
|
|
31494
31725
|
const snapshot = !options.graphql && changedPaths && previousSnapshot && previousSnapshot.optionsKey === optionsKey ? await updateSnapshot(previousSnapshot, options, changedPaths) : await createSnapshot(options);
|
|
31495
31726
|
const changedFiles = changedPaths && previousSnapshot ? diffFiles(previousSnapshot.files, snapshot.files) : diffFiles(previousSnapshot?.files, snapshot.files);
|
|
31496
31727
|
const activeCache = options.cache ?? cache;
|
|
31497
|
-
const cacheHit = Boolean(previousSnapshot && previousSnapshot.optionsKey === snapshot.optionsKey && previousCache === activeCache && changedFiles.length === 0)
|
|
31498
|
-
if (cacheHit && previousResult) {
|
|
31499
|
-
return {
|
|
31500
|
-
...previousResult,
|
|
31501
|
-
stats: {
|
|
31502
|
-
cacheHit: true,
|
|
31503
|
-
changedFiles: [],
|
|
31504
|
-
affectedModules: [],
|
|
31505
|
-
reusedModules: previousResult.graph.modules.map((m) => m.name),
|
|
31506
|
-
reanalyzedModules: []
|
|
31507
|
-
}
|
|
31508
|
-
};
|
|
31509
|
-
}
|
|
31728
|
+
const cacheHit = Boolean(previousSnapshot && previousSnapshot.optionsKey === snapshot.optionsKey && previousCache === activeCache && changedFiles.length === 0);
|
|
31510
31729
|
if (!activeCache.dependencyGraph && previousResult) {
|
|
31511
31730
|
activeCache.dependencyGraph = new ModuleDependencyGraph(previousResult.graph.modules);
|
|
31512
31731
|
}
|
|
@@ -31522,7 +31741,7 @@ function createIncrementalCompiler() {
|
|
|
31522
31741
|
activeCache.dependencyGraph = new ModuleDependencyGraph(result.graph.modules);
|
|
31523
31742
|
}
|
|
31524
31743
|
const stats = {
|
|
31525
|
-
cacheHit:
|
|
31744
|
+
cacheHit: cacheHit && !result.diagnostics.some(({ severity }) => severity === "error"),
|
|
31526
31745
|
changedFiles,
|
|
31527
31746
|
affectedModules,
|
|
31528
31747
|
reusedModules,
|
|
@@ -32076,10 +32295,10 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
|
|
|
32076
32295
|
...resolved.detectOrphanModules === undefined ? {} : { detectOrphanModules: resolved.detectOrphanModules },
|
|
32077
32296
|
effect: resolved.effect === undefined ? { ...DEFAULT_SUPACLOUD_CONFIG.effect } : { ...DEFAULT_SUPACLOUD_CONFIG.effect, ...resolved.effect },
|
|
32078
32297
|
treeShakeUnusedProviders: resolved.treeShakeUnusedProviders ?? DEFAULT_SUPACLOUD_CONFIG.treeShakeUnusedProviders,
|
|
32079
|
-
graphql
|
|
32298
|
+
...resolved.graphql === undefined || resolved.graphql === false ? {} : { graphql: {
|
|
32080
32299
|
...resolved.graphql,
|
|
32081
32300
|
schema: resolve13(cwd, resolved.graphql.schema)
|
|
32082
|
-
}
|
|
32301
|
+
} }
|
|
32083
32302
|
};
|
|
32084
32303
|
}
|
|
32085
32304
|
async function loadSupacloudConfig(cwd = process.cwd()) {
|
|
@@ -32407,7 +32626,7 @@ function formatDeliveryPlan(result) {
|
|
|
32407
32626
|
import { mkdir as mkdir3, mkdtemp, readFile as readFile7, realpath as realpath4, rename as rename4, rm as rm2 } from "node:fs/promises";
|
|
32408
32627
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
32409
32628
|
import { dirname as dirname9, join as join10, relative as relative10, resolve as resolve17, sep as sep10 } from "node:path";
|
|
32410
|
-
import * as
|
|
32629
|
+
import * as ts16 from "@typescript/typescript6";
|
|
32411
32630
|
|
|
32412
32631
|
// src/delivery-build-schema.ts
|
|
32413
32632
|
init_delivery_build_schema();
|
|
@@ -32449,22 +32668,22 @@ init_delivery_files2();
|
|
|
32449
32668
|
import { isBuiltin } from "node:module";
|
|
32450
32669
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
32451
32670
|
import { join as join9, resolve as resolve15 } from "node:path";
|
|
32452
|
-
import * as
|
|
32671
|
+
import * as ts15 from "@typescript/typescript6";
|
|
32453
32672
|
|
|
32454
32673
|
// src/delivery-imports.ts
|
|
32455
|
-
import * as
|
|
32674
|
+
import * as ts14 from "@typescript/typescript6";
|
|
32456
32675
|
function staticDeliveryImports(path, contents) {
|
|
32457
32676
|
if (!/\.[cm]?[jt]sx?$/.test(path))
|
|
32458
32677
|
return contents;
|
|
32459
|
-
const source =
|
|
32678
|
+
const source = ts14.createSourceFile(path, new TextDecoder().decode(contents), ts14.ScriptTarget.Latest, true);
|
|
32460
32679
|
const computed = [];
|
|
32461
32680
|
function scan(node) {
|
|
32462
|
-
if (
|
|
32681
|
+
if (ts14.isCallExpression(node) && (node.expression.kind === ts14.SyntaxKind.ImportKeyword || ts14.isIdentifier(node.expression) && node.expression.text === "require")) {
|
|
32463
32682
|
const argument = node.arguments[0];
|
|
32464
|
-
if (!argument || !
|
|
32683
|
+
if (!argument || !ts14.isStringLiteral(argument) && !ts14.isNoSubstitutionTemplateLiteral(argument))
|
|
32465
32684
|
computed.push(node);
|
|
32466
32685
|
}
|
|
32467
|
-
|
|
32686
|
+
ts14.forEachChild(node, scan);
|
|
32468
32687
|
}
|
|
32469
32688
|
scan(source);
|
|
32470
32689
|
if (computed.length === 0)
|
|
@@ -32472,36 +32691,36 @@ function staticDeliveryImports(path, contents) {
|
|
|
32472
32691
|
const reject = () => {
|
|
32473
32692
|
throw new Error("Computed module loading is not supported in independent delivery bundles.");
|
|
32474
32693
|
};
|
|
32475
|
-
if (!
|
|
32694
|
+
if (!ts14.isExternalModule(source))
|
|
32476
32695
|
return reject();
|
|
32477
|
-
const host =
|
|
32696
|
+
const host = ts14.createCompilerHost({ noLib: true, noResolve: true, allowJs: true });
|
|
32478
32697
|
host.getSourceFile = (name) => name === path ? source : undefined;
|
|
32479
|
-
const checker =
|
|
32698
|
+
const checker = ts14.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, host).getTypeChecker();
|
|
32480
32699
|
const replacements = new Map;
|
|
32481
32700
|
const removed = new Set;
|
|
32482
32701
|
for (const call of computed) {
|
|
32483
32702
|
let visit = function(node) {
|
|
32484
|
-
const referenced =
|
|
32485
|
-
if (
|
|
32703
|
+
const referenced = ts14.isIdentifier(node) ? ts14.isShorthandPropertyAssignment(node.parent) ? checker.getShorthandAssignmentValueSymbol(node.parent) : ts14.isExportSpecifier(node.parent) ? checker.getExportSpecifierLocalTargetSymbol(node.parent) : checker.getSymbolAtLocation(node) : undefined;
|
|
32704
|
+
if (ts14.isIdentifier(node) && node !== declarationName && referenced === symbol) {
|
|
32486
32705
|
const use = node.parent;
|
|
32487
|
-
if (!
|
|
32706
|
+
if (!ts14.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
|
|
32488
32707
|
return reject();
|
|
32489
32708
|
const value = use.arguments[0];
|
|
32490
|
-
if (!value || !
|
|
32709
|
+
if (!value || !ts14.isStringLiteral(value) && !ts14.isNoSubstitutionTemplateLiteral(value))
|
|
32491
32710
|
return reject();
|
|
32492
32711
|
references++;
|
|
32493
|
-
replacements.set(use,
|
|
32712
|
+
replacements.set(use, ts14.factory.createCallExpression(call.expression, undefined, [value]));
|
|
32494
32713
|
}
|
|
32495
|
-
|
|
32714
|
+
ts14.forEachChild(node, visit);
|
|
32496
32715
|
};
|
|
32497
32716
|
const statement = call.parent;
|
|
32498
32717
|
const block = statement.parent;
|
|
32499
32718
|
const declaration = block.parent;
|
|
32500
|
-
if (call.expression.kind !==
|
|
32719
|
+
if (call.expression.kind !== ts14.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts14.isReturnStatement(statement) || !ts14.isBlock(block) || block.statements.length !== 1 || !ts14.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
|
|
32501
32720
|
return reject();
|
|
32502
32721
|
const parameter = declaration.parameters[0];
|
|
32503
32722
|
const argument = call.arguments[0];
|
|
32504
|
-
if (!parameter || !
|
|
32723
|
+
if (!parameter || !ts14.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts14.isIdentifier(argument) || checker.getSymbolAtLocation(argument) !== checker.getSymbolAtLocation(parameter.name))
|
|
32505
32724
|
return reject();
|
|
32506
32725
|
const symbol = checker.getSymbolAtLocation(declaration.name);
|
|
32507
32726
|
if (!symbol || symbol.declarations?.length !== 1)
|
|
@@ -32513,22 +32732,22 @@ function staticDeliveryImports(path, contents) {
|
|
|
32513
32732
|
return reject();
|
|
32514
32733
|
removed.add(declaration);
|
|
32515
32734
|
}
|
|
32516
|
-
const transformed =
|
|
32735
|
+
const transformed = ts14.transform(source, [(context) => {
|
|
32517
32736
|
const visit = (node) => {
|
|
32518
|
-
if (
|
|
32737
|
+
if (ts14.isFunctionDeclaration(node) && removed.has(node))
|
|
32519
32738
|
return;
|
|
32520
|
-
const replacement =
|
|
32739
|
+
const replacement = ts14.isCallExpression(node) ? replacements.get(node) : undefined;
|
|
32521
32740
|
if (replacement)
|
|
32522
32741
|
return replacement;
|
|
32523
|
-
return
|
|
32742
|
+
return ts14.visitEachChild(node, visit, context);
|
|
32524
32743
|
};
|
|
32525
|
-
return (node) =>
|
|
32744
|
+
return (node) => ts14.visitNode(node, visit, ts14.isSourceFile) ?? node;
|
|
32526
32745
|
}]);
|
|
32527
32746
|
try {
|
|
32528
32747
|
const transformedSource = transformed.transformed[0];
|
|
32529
32748
|
if (!transformedSource)
|
|
32530
32749
|
return reject();
|
|
32531
|
-
return new TextEncoder().encode(
|
|
32750
|
+
return new TextEncoder().encode(ts14.createPrinter().printFile(transformedSource));
|
|
32532
32751
|
} finally {
|
|
32533
32752
|
transformed.dispose();
|
|
32534
32753
|
}
|
|
@@ -32676,16 +32895,16 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
32676
32895
|
const bytes = new Uint8Array(await output.arrayBuffer());
|
|
32677
32896
|
if (/\.[cm]?js$/.test(path)) {
|
|
32678
32897
|
let check = function(node) {
|
|
32679
|
-
const specifier =
|
|
32680
|
-
if (specifier &&
|
|
32898
|
+
const specifier = ts15.isImportDeclaration(node) || ts15.isExportDeclaration(node) ? node.moduleSpecifier : ts15.isCallExpression(node) && (node.expression.kind === ts15.SyntaxKind.ImportKeyword || ts15.isIdentifier(node.expression) && /^(?:__)?require$/.test(node.expression.text) || ts15.isPropertyAccessExpression(node.expression) && node.expression.name.text === "require" && ts15.isMetaProperty(node.expression.expression) && node.expression.expression.keywordToken === ts15.SyntaxKind.ImportKeyword) ? node.arguments[0] : undefined;
|
|
32899
|
+
if (specifier && ts15.isStringLiteralLike(specifier)) {
|
|
32681
32900
|
if (!isBuiltin(specifier.text) && specifier.text !== "bun" && !specifier.text.startsWith("bun:")) {
|
|
32682
32901
|
throw new Error("Independent bundles cannot retain external package imports.");
|
|
32683
32902
|
}
|
|
32684
32903
|
runtimeImports.add(specifier.text);
|
|
32685
32904
|
}
|
|
32686
|
-
|
|
32905
|
+
ts15.forEachChild(node, check);
|
|
32687
32906
|
};
|
|
32688
|
-
const source =
|
|
32907
|
+
const source = ts15.createSourceFile(path, new TextDecoder().decode(bytes), ts15.ScriptTarget.Latest, true);
|
|
32689
32908
|
check(source);
|
|
32690
32909
|
}
|
|
32691
32910
|
files.set(`bundle/${path}`, bytes);
|
|
@@ -32704,16 +32923,16 @@ function renderDeliveryRuntimeIdentity() {
|
|
|
32704
32923
|
return `
|
|
32705
32924
|
function deliveryRuntimeIdentity(kind: "http" | "worker") {
|
|
32706
32925
|
const env = deliveryProcess.env;
|
|
32707
|
-
if (env
|
|
32926
|
+
if (env["SUPACLOUD_ACTIVATION_ID"] === undefined) return null;
|
|
32708
32927
|
const identity = {
|
|
32709
32928
|
schema: "supacloud.application-runtime.v1",
|
|
32710
|
-
project_ref: env
|
|
32711
|
-
application_id: env
|
|
32712
|
-
environment_id: env
|
|
32713
|
-
release_id: env
|
|
32714
|
-
activation_id: env
|
|
32715
|
-
target: env
|
|
32716
|
-
object_id: env
|
|
32929
|
+
project_ref: env["SUPACLOUD_PROJECT_REF"],
|
|
32930
|
+
application_id: env["SUPACLOUD_APPLICATION_ID"],
|
|
32931
|
+
environment_id: env["SUPACLOUD_ENVIRONMENT_ID"],
|
|
32932
|
+
release_id: env["SUPACLOUD_RELEASE_ID"],
|
|
32933
|
+
activation_id: env["SUPACLOUD_ACTIVATION_ID"],
|
|
32934
|
+
target: env["SUPACLOUD_TARGET"],
|
|
32935
|
+
object_id: env["SUPACLOUD_OBJECT_ID"],
|
|
32717
32936
|
kind, pid: deliveryProcess.pid,
|
|
32718
32937
|
};
|
|
32719
32938
|
const matches = (value: string | undefined, pattern: RegExp) => typeof value === "string" && pattern.test(value);
|
|
@@ -32746,8 +32965,8 @@ interface DeliveryHttpHost {
|
|
|
32746
32965
|
|
|
32747
32966
|
async function startDeliveryHttp(signal: AbortSignal, shutdownTimeout: number, startDeadline: () => void) {
|
|
32748
32967
|
const identity = deliveryRuntimeIdentity("http");
|
|
32749
|
-
const port = Number(deliveryProcess.env
|
|
32750
|
-
const hostname = deliveryProcess.env
|
|
32968
|
+
const port = Number(deliveryProcess.env["PORT"] ?? "3000");
|
|
32969
|
+
const hostname = deliveryProcess.env["HOST"] ?? "127.0.0.1";
|
|
32751
32970
|
if (!Number.isInteger(port) || port < 0 || port > 65535 || hostname.length === 0) {
|
|
32752
32971
|
throw new Error("Invalid delivery HTTP listener configuration.");
|
|
32753
32972
|
}
|
|
@@ -32815,7 +33034,7 @@ async function startDeliveryHttp(signal: AbortSignal, shutdownTimeout: number, s
|
|
|
32815
33034
|
|
|
32816
33035
|
{
|
|
32817
33036
|
const lifecycle = new AbortController();
|
|
32818
|
-
const shutdownTimeout = Number(deliveryProcess.env
|
|
33037
|
+
const shutdownTimeout = Number(deliveryProcess.env["SHUTDOWN_TIMEOUT_MS"] ?? "10000");
|
|
32819
33038
|
let running: Awaited<ReturnType<typeof startDeliveryHttp>>;
|
|
32820
33039
|
let deadline: ReturnType<typeof setTimeout> | undefined;
|
|
32821
33040
|
const finish = (failed: boolean) => {
|
|
@@ -32883,7 +33102,7 @@ interface DeliveryWorkerHost {
|
|
|
32883
33102
|
|
|
32884
33103
|
{
|
|
32885
33104
|
const lifecycle = new AbortController();
|
|
32886
|
-
const shutdownTimeout = Number(deliveryProcess.env
|
|
33105
|
+
const shutdownTimeout = Number(deliveryProcess.env["SHUTDOWN_TIMEOUT_MS"] ?? "10000");
|
|
32887
33106
|
let host: DeliveryWorkerHost | undefined;
|
|
32888
33107
|
let running = false;
|
|
32889
33108
|
let runtimeFailed = false;
|
|
@@ -32951,7 +33170,7 @@ interface DeliveryWorkerHost {
|
|
|
32951
33170
|
const candidate = await createHost(createCompiledModules(), { signal: lifecycle.signal });
|
|
32952
33171
|
if (!candidate || typeof candidate.close !== "function") throw new Error("Invalid delivery worker host.");
|
|
32953
33172
|
host = candidate;
|
|
32954
|
-
const execution = deliveryProcess.env
|
|
33173
|
+
const execution = deliveryProcess.env["SUPACLOUD_WORKER_EXECUTION"];
|
|
32955
33174
|
if (execution) {
|
|
32956
33175
|
const expected: unknown = JSON.parse(Buffer.from(execution, "base64").toString("utf8"));
|
|
32957
33176
|
if (!deliveryPolicyEqual(host.execution, expected) || typeof host.health !== "function" || !host.failure) {
|
|
@@ -33055,7 +33274,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
33055
33274
|
const settings = parseDeliveryOptions(delivery);
|
|
33056
33275
|
if (typeof Bun === "undefined")
|
|
33057
33276
|
throw new Error("Independent delivery builds require Bun.");
|
|
33058
|
-
const configPath =
|
|
33277
|
+
const configPath = ts16.findConfigFile(resolve17(options.rootDir), ts16.sys.fileExists);
|
|
33059
33278
|
if (!configPath)
|
|
33060
33279
|
throw new Error("Independent delivery builds require a project tsconfig.json.");
|
|
33061
33280
|
const lexicalProject = dirname9(configPath);
|
|
@@ -33071,8 +33290,8 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
33071
33290
|
if (inside(generatedRoot, sourceRoot))
|
|
33072
33291
|
throw new Error("Output must not contain the application source root.");
|
|
33073
33292
|
const configInputs = new Map;
|
|
33074
|
-
const parsedConfig =
|
|
33075
|
-
...
|
|
33293
|
+
const parsedConfig = ts16.getParsedCommandLineOfConfigFile(await realpath4(configPath), {}, {
|
|
33294
|
+
...ts16.sys,
|
|
33076
33295
|
readFile(path) {
|
|
33077
33296
|
const contents = readFileSync3(path, "utf8");
|
|
33078
33297
|
configInputs.set(resolve17(path), digest(contents));
|
|
@@ -33192,7 +33411,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
33192
33411
|
for (const [name, contents] of Object.entries(generated))
|
|
33193
33412
|
await writeArtifact(stage, `generated/${name}`, contents);
|
|
33194
33413
|
{
|
|
33195
|
-
const program =
|
|
33414
|
+
const program = ts16.createProgram({
|
|
33196
33415
|
rootNames: [
|
|
33197
33416
|
...parsedConfig.fileNames.filter((path) => !inside(generatedRoot, path)),
|
|
33198
33417
|
...Object.keys(generated).map((name) => join10(stage, "generated", name))
|
|
@@ -33200,12 +33419,12 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
33200
33419
|
options: { ...parsedConfig.options, rootDir: project },
|
|
33201
33420
|
...parsedConfig.projectReferences ? { projectReferences: parsedConfig.projectReferences } : {}
|
|
33202
33421
|
});
|
|
33203
|
-
const diagnostics =
|
|
33204
|
-
if (diagnostics.some((item) => item.category ===
|
|
33205
|
-
return failed(diagnostics.filter((item) => item.category ===
|
|
33422
|
+
const diagnostics = ts16.getPreEmitDiagnostics(program);
|
|
33423
|
+
if (diagnostics.some((item) => item.category === ts16.DiagnosticCategory.Error)) {
|
|
33424
|
+
return failed(diagnostics.filter((item) => item.category === ts16.DiagnosticCategory.Error).map((item) => ({
|
|
33206
33425
|
severity: "error",
|
|
33207
33426
|
code: "delivery-generated-type-error",
|
|
33208
|
-
message:
|
|
33427
|
+
message: ts16.flattenDiagnosticMessageText(item.messageText, `
|
|
33209
33428
|
`),
|
|
33210
33429
|
...item.file ? { file: item.file.fileName } : {}
|
|
33211
33430
|
})));
|
|
@@ -33351,7 +33570,7 @@ async function buildDeliveryProject(options, delivery) {
|
|
|
33351
33570
|
// src/migrations.ts
|
|
33352
33571
|
import { rename as rename5, readFile as readFile9, writeFile as writeFile4, rm as rm3 } from "node:fs/promises";
|
|
33353
33572
|
import { relative as relative11, resolve as resolve19 } from "node:path";
|
|
33354
|
-
import * as
|
|
33573
|
+
import * as ts17 from "@typescript/typescript6";
|
|
33355
33574
|
|
|
33356
33575
|
// src/migration-policy.ts
|
|
33357
33576
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
@@ -33359,7 +33578,7 @@ import { readFileSync as readFileSync4 } from "node:fs";
|
|
|
33359
33578
|
import { resolve as resolve18 } from "node:path";
|
|
33360
33579
|
|
|
33361
33580
|
// src/migration-app-version.ts
|
|
33362
|
-
var MIGRATION_APP_VERSION = "0.
|
|
33581
|
+
var MIGRATION_APP_VERSION = "0.25.0";
|
|
33363
33582
|
|
|
33364
33583
|
// src/migration-elysia-version.ts
|
|
33365
33584
|
var MIGRATION_ELYSIA_VERSION = "0.29.0";
|
|
@@ -33403,29 +33622,29 @@ async function checkMigrationDependencies(rootDir) {
|
|
|
33403
33622
|
// src/migrations.ts
|
|
33404
33623
|
var ROUTE_DECORATORS2 = new Set(["Get", "Post", "Put", "Patch", "Delete", "Head", "Options"]);
|
|
33405
33624
|
var MIGRATION_COMPILER_OPTIONS = {
|
|
33406
|
-
target:
|
|
33407
|
-
module:
|
|
33408
|
-
moduleResolution:
|
|
33625
|
+
target: ts17.ScriptTarget.ES2022,
|
|
33626
|
+
module: ts17.ModuleKind.ESNext,
|
|
33627
|
+
moduleResolution: ts17.ModuleResolutionKind.Bundler,
|
|
33409
33628
|
noEmit: true,
|
|
33410
33629
|
skipLibCheck: true
|
|
33411
33630
|
};
|
|
33412
33631
|
function migrationCompilerOptions(rootDir) {
|
|
33413
33632
|
if (!rootDir)
|
|
33414
33633
|
return MIGRATION_COMPILER_OPTIONS;
|
|
33415
|
-
const configPath =
|
|
33634
|
+
const configPath = ts17.findConfigFile(rootDir, ts17.sys.fileExists);
|
|
33416
33635
|
if (!configPath)
|
|
33417
33636
|
return MIGRATION_COMPILER_OPTIONS;
|
|
33418
33637
|
const configHost = {
|
|
33419
|
-
...
|
|
33638
|
+
...ts17.sys,
|
|
33420
33639
|
onUnRecoverableConfigFileDiagnostic: (_diagnostic) => {}
|
|
33421
33640
|
};
|
|
33422
|
-
const parsed =
|
|
33641
|
+
const parsed = ts17.getParsedCommandLineOfConfigFile(configPath, {}, configHost);
|
|
33423
33642
|
if (!parsed || parsed.errors.length > 0)
|
|
33424
33643
|
return MIGRATION_COMPILER_OPTIONS;
|
|
33425
33644
|
return { ...parsed.options, noEmit: true, skipLibCheck: true };
|
|
33426
33645
|
}
|
|
33427
33646
|
function propertyName2(property) {
|
|
33428
|
-
if (
|
|
33647
|
+
if (ts17.isIdentifier(property) || ts17.isStringLiteral(property) || ts17.isNumericLiteral(property))
|
|
33429
33648
|
return property.text;
|
|
33430
33649
|
return;
|
|
33431
33650
|
}
|
|
@@ -33435,7 +33654,7 @@ function lineOf2(sourceFile, node) {
|
|
|
33435
33654
|
function resolveSymbol(symbol, checker) {
|
|
33436
33655
|
if (!symbol)
|
|
33437
33656
|
return;
|
|
33438
|
-
for (let guard = 0;guard < 4 && (symbol.flags &
|
|
33657
|
+
for (let guard = 0;guard < 4 && (symbol.flags & ts17.SymbolFlags.Alias) !== 0; guard += 1) {
|
|
33439
33658
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
33440
33659
|
if (aliased === symbol)
|
|
33441
33660
|
break;
|
|
@@ -33444,12 +33663,12 @@ function resolveSymbol(symbol, checker) {
|
|
|
33444
33663
|
return symbol;
|
|
33445
33664
|
}
|
|
33446
33665
|
function symbolForExpression(expression, checker) {
|
|
33447
|
-
const location =
|
|
33666
|
+
const location = ts17.isIdentifier(expression) ? expression : ts17.isPropertyAccessExpression(expression) ? expression.name : ts17.isElementAccessExpression(expression) && expression.argumentExpression && ts17.isStringLiteral(expression.argumentExpression) ? expression : undefined;
|
|
33448
33667
|
return location ? resolveSymbol(checker.getSymbolAtLocation(location), checker) : undefined;
|
|
33449
33668
|
}
|
|
33450
33669
|
function unwrapExpression(expression) {
|
|
33451
33670
|
let current = expression;
|
|
33452
|
-
while (
|
|
33671
|
+
while (ts17.isAsExpression(current) || ts17.isSatisfiesExpression(current) || ts17.isParenthesizedExpression(current) || ts17.isTypeAssertionExpression(current)) {
|
|
33453
33672
|
current = current.expression;
|
|
33454
33673
|
}
|
|
33455
33674
|
return current;
|
|
@@ -33464,7 +33683,7 @@ function isRouteDecoratorCall(node, checker) {
|
|
|
33464
33683
|
if (node.arguments.length < 2)
|
|
33465
33684
|
return false;
|
|
33466
33685
|
const name = node.expression.getText(node.getSourceFile());
|
|
33467
|
-
if (
|
|
33686
|
+
if (ts17.isIdentifier(node.expression) && ROUTE_DECORATORS2.has(node.expression.text))
|
|
33468
33687
|
return true;
|
|
33469
33688
|
if (ROUTE_DECORATORS2.has(name))
|
|
33470
33689
|
return true;
|
|
@@ -33478,14 +33697,14 @@ function resolveStaticObjectLiteral2(input, checker, seen = new Set) {
|
|
|
33478
33697
|
if (seen.has(expression))
|
|
33479
33698
|
return;
|
|
33480
33699
|
seen.add(expression);
|
|
33481
|
-
if (
|
|
33700
|
+
if (ts17.isObjectLiteralExpression(expression))
|
|
33482
33701
|
return expression;
|
|
33483
|
-
if (
|
|
33702
|
+
if (ts17.isCallExpression(expression) && isDefineRouteContractCall(expression, checker)) {
|
|
33484
33703
|
return resolveStaticObjectLiteral2(expression.arguments[0], checker, seen);
|
|
33485
33704
|
}
|
|
33486
33705
|
const symbol = symbolForExpression(expression, checker);
|
|
33487
33706
|
for (const declaration of symbol?.declarations ?? []) {
|
|
33488
|
-
if (
|
|
33707
|
+
if (ts17.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
33489
33708
|
const resolved = resolveStaticObjectLiteral2(declaration.initializer, checker, seen);
|
|
33490
33709
|
if (resolved)
|
|
33491
33710
|
return resolved;
|
|
@@ -33499,7 +33718,7 @@ function displayFile(rootDir, fileName) {
|
|
|
33499
33718
|
}
|
|
33500
33719
|
function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
33501
33720
|
const compilerOptions = migrationCompilerOptions(rootDir);
|
|
33502
|
-
const host =
|
|
33721
|
+
const host = ts17.createCompilerHost(compilerOptions);
|
|
33503
33722
|
const getSourceFile = host.getSourceFile.bind(host);
|
|
33504
33723
|
const fileExists = host.fileExists.bind(host);
|
|
33505
33724
|
const readFile = host.readFile.bind(host);
|
|
@@ -33508,16 +33727,16 @@ function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
|
|
|
33508
33727
|
host.readFile = (fileName) => sourceOverrides.get(resolve19(fileName)) ?? readFile(fileName);
|
|
33509
33728
|
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
33510
33729
|
const source = sourceOverrides.get(resolve19(fileName));
|
|
33511
|
-
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) :
|
|
33730
|
+
return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts17.createSourceFile(fileName, source, languageVersion, true);
|
|
33512
33731
|
};
|
|
33513
33732
|
host.getCurrentDirectory = () => rootDir ?? currentDirectory();
|
|
33514
|
-
return
|
|
33733
|
+
return ts17.createProgram(fileNames, compilerOptions, host);
|
|
33515
33734
|
}
|
|
33516
33735
|
function routeResponseProperties(object) {
|
|
33517
|
-
const responseProperties = object.properties.filter((property) =>
|
|
33736
|
+
const responseProperties = object.properties.filter((property) => ts17.isPropertyAssignment(property) && propertyName2(property.name) === "response");
|
|
33518
33737
|
return {
|
|
33519
33738
|
response: responseProperties[0],
|
|
33520
|
-
hasResponses: object.properties.some((property) => (
|
|
33739
|
+
hasResponses: object.properties.some((property) => (ts17.isPropertyAssignment(property) || ts17.isShorthandPropertyAssignment(property)) && propertyName2(property.name) === "responses"),
|
|
33521
33740
|
duplicateResponse: responseProperties.length > 1
|
|
33522
33741
|
};
|
|
33523
33742
|
}
|
|
@@ -33537,7 +33756,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
33537
33756
|
if (!includedFiles.has(sourcePath))
|
|
33538
33757
|
continue;
|
|
33539
33758
|
const visit = (node) => {
|
|
33540
|
-
if (
|
|
33759
|
+
if (ts17.isCallExpression(node) && isRouteDecoratorCall(node, checker)) {
|
|
33541
33760
|
const options = node.arguments[1];
|
|
33542
33761
|
const object = options && resolveStaticObjectLiteral2(options, checker);
|
|
33543
33762
|
if (object) {
|
|
@@ -33557,7 +33776,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
|
|
|
33557
33776
|
}
|
|
33558
33777
|
}
|
|
33559
33778
|
}
|
|
33560
|
-
|
|
33779
|
+
ts17.forEachChild(node, visit);
|
|
33561
33780
|
};
|
|
33562
33781
|
visit(sourceFile);
|
|
33563
33782
|
}
|
|
@@ -33724,7 +33943,7 @@ async function migrateProject(options) {
|
|
|
33724
33943
|
}
|
|
33725
33944
|
}
|
|
33726
33945
|
const include = options.include ?? ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
|
|
33727
|
-
const files =
|
|
33946
|
+
const files = ts17.sys.readDirectory(rootDir, [".ts", ".tsx", ".mts", ".cts"], ["node_modules", "dist", "generated"], include).sort();
|
|
33728
33947
|
const results = [];
|
|
33729
33948
|
const issues = [];
|
|
33730
33949
|
const pendingWrites = new Map;
|
|
@@ -33868,30 +34087,30 @@ function resolveSchema(value, document, seen = new Set) {
|
|
|
33868
34087
|
const schema = recordValue(value);
|
|
33869
34088
|
if (!schema)
|
|
33870
34089
|
return;
|
|
33871
|
-
const ref = stringValue(schema
|
|
34090
|
+
const ref = stringValue(schema["$ref"]);
|
|
33872
34091
|
if (!ref || !ref.startsWith("#/components/schemas/"))
|
|
33873
34092
|
return schema;
|
|
33874
34093
|
if (seen.has(ref))
|
|
33875
34094
|
return schema;
|
|
33876
34095
|
const name = decodeJsonPointerPart(ref.slice("#/components/schemas/".length));
|
|
33877
|
-
const components = recordValue(document
|
|
33878
|
-
const schemas = recordValue(components?.schemas);
|
|
34096
|
+
const components = recordValue(document["components"]);
|
|
34097
|
+
const schemas = recordValue(components?.["schemas"]);
|
|
33879
34098
|
const target = schemas?.[name];
|
|
33880
34099
|
if (target === undefined)
|
|
33881
34100
|
return schema;
|
|
33882
34101
|
return resolveSchema(target, document, new Set([...seen, ref]));
|
|
33883
34102
|
}
|
|
33884
34103
|
function schemaEnum(value) {
|
|
33885
|
-
return Array.isArray(value?.enum) ? value
|
|
34104
|
+
return Array.isArray(value?.["enum"]) ? value["enum"] : undefined;
|
|
33886
34105
|
}
|
|
33887
34106
|
function schemaProperties(value) {
|
|
33888
|
-
return recordValue(value?.properties);
|
|
34107
|
+
return recordValue(value?.["properties"]);
|
|
33889
34108
|
}
|
|
33890
34109
|
function schemaRequired(value) {
|
|
33891
|
-
return new Set(arrayValue(value?.required).filter((item) => typeof item === "string"));
|
|
34110
|
+
return new Set(arrayValue(value?.["required"]).filter((item) => typeof item === "string"));
|
|
33892
34111
|
}
|
|
33893
34112
|
function schemaType(value) {
|
|
33894
|
-
return value?.type;
|
|
34113
|
+
return value?.["type"];
|
|
33895
34114
|
}
|
|
33896
34115
|
function addChange(changes, change) {
|
|
33897
34116
|
if (changes.some((item) => item.kind === change.kind && item.code === change.code && item.path === change.path && item.message === change.message))
|
|
@@ -33935,7 +34154,7 @@ function compareSchema(baseValue, currentValue, baseDocument, currentDocument, p
|
|
|
33935
34154
|
if (baseProperties && currentProperties) {
|
|
33936
34155
|
for (const name of sortedKeys2(baseProperties)) {
|
|
33937
34156
|
if (currentProperties[name] === undefined) {
|
|
33938
|
-
const inputRemovalIsBreaking = baseSchema
|
|
34157
|
+
const inputRemovalIsBreaking = baseSchema["additionalProperties"] === false;
|
|
33939
34158
|
if (direction === "output" || inputRemovalIsBreaking) {
|
|
33940
34159
|
addChange(changes, {
|
|
33941
34160
|
kind: "breaking",
|
|
@@ -33962,7 +34181,7 @@ function compareSchema(baseValue, currentValue, baseDocument, currentDocument, p
|
|
|
33962
34181
|
});
|
|
33963
34182
|
}
|
|
33964
34183
|
}
|
|
33965
|
-
if (baseSchema
|
|
34184
|
+
if (baseSchema["additionalProperties"] !== false && currentSchema["additionalProperties"] === false) {
|
|
33966
34185
|
addChange(changes, {
|
|
33967
34186
|
kind: "breaking",
|
|
33968
34187
|
code: "request-additional-properties-rejected",
|
|
@@ -33985,13 +34204,13 @@ function compareSchema(baseValue, currentValue, baseDocument, currentDocument, p
|
|
|
33985
34204
|
}
|
|
33986
34205
|
function parameterKey(value) {
|
|
33987
34206
|
const parameter = recordValue(value);
|
|
33988
|
-
const name = stringValue(parameter?.name);
|
|
33989
|
-
const location = stringValue(parameter?.in);
|
|
34207
|
+
const name = stringValue(parameter?.["name"]);
|
|
34208
|
+
const location = stringValue(parameter?.["in"]);
|
|
33990
34209
|
return name && location ? `${location}:${name}` : undefined;
|
|
33991
34210
|
}
|
|
33992
34211
|
function operationParameters(pathItem, operation) {
|
|
33993
34212
|
const result = new Map;
|
|
33994
|
-
for (const source of [pathItem
|
|
34213
|
+
for (const source of [pathItem["parameters"], operation["parameters"]]) {
|
|
33995
34214
|
for (const item of arrayValue(source)) {
|
|
33996
34215
|
const parameter = recordValue(item);
|
|
33997
34216
|
const key = parameterKey(parameter);
|
|
@@ -34002,7 +34221,7 @@ function operationParameters(pathItem, operation) {
|
|
|
34002
34221
|
return result;
|
|
34003
34222
|
}
|
|
34004
34223
|
function parameterSchema(value) {
|
|
34005
|
-
return value
|
|
34224
|
+
return value["schema"];
|
|
34006
34225
|
}
|
|
34007
34226
|
function compareParameters(basePathItem, currentPathItem, baseOperation, currentOperation, baseDocument, currentDocument, path, changes) {
|
|
34008
34227
|
const baseParameters = operationParameters(basePathItem, baseOperation);
|
|
@@ -34019,7 +34238,7 @@ function compareParameters(basePathItem, currentPathItem, baseOperation, current
|
|
|
34019
34238
|
});
|
|
34020
34239
|
continue;
|
|
34021
34240
|
}
|
|
34022
|
-
if (currentParameter
|
|
34241
|
+
if (currentParameter["required"] === true && baseParameter["required"] !== true) {
|
|
34023
34242
|
addChange(changes, {
|
|
34024
34243
|
kind: "breaking",
|
|
34025
34244
|
code: "parameter-required",
|
|
@@ -34038,16 +34257,16 @@ function compareParameters(basePathItem, currentPathItem, baseOperation, current
|
|
|
34038
34257
|
if (!parameter)
|
|
34039
34258
|
continue;
|
|
34040
34259
|
addChange(changes, {
|
|
34041
|
-
kind: parameter
|
|
34042
|
-
code: parameter
|
|
34260
|
+
kind: parameter["required"] === true ? "breaking" : "non-breaking",
|
|
34261
|
+
code: parameter["required"] === true ? "parameter-required" : "parameter-added",
|
|
34043
34262
|
path: `${path}.parameters.${key}`,
|
|
34044
|
-
message: parameter
|
|
34263
|
+
message: parameter["required"] === true ? "A new required parameter was added." : "An optional parameter was added."
|
|
34045
34264
|
});
|
|
34046
34265
|
}
|
|
34047
34266
|
}
|
|
34048
34267
|
function compareRequestBody(baseOperation, currentOperation, baseDocument, currentDocument, path, changes) {
|
|
34049
|
-
const baseBody = recordValue(baseOperation
|
|
34050
|
-
const currentBody = recordValue(currentOperation
|
|
34268
|
+
const baseBody = recordValue(baseOperation["requestBody"]);
|
|
34269
|
+
const currentBody = recordValue(currentOperation["requestBody"]);
|
|
34051
34270
|
if (!baseBody || !currentBody) {
|
|
34052
34271
|
if (baseBody && !currentBody) {
|
|
34053
34272
|
addChange(changes, {
|
|
@@ -34056,7 +34275,7 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
34056
34275
|
path: `${path}.requestBody`,
|
|
34057
34276
|
message: "A request body from the previous contract was removed."
|
|
34058
34277
|
});
|
|
34059
|
-
} else if (!baseBody && currentBody?.required === true) {
|
|
34278
|
+
} else if (!baseBody && currentBody?.["required"] === true) {
|
|
34060
34279
|
addChange(changes, {
|
|
34061
34280
|
kind: "breaking",
|
|
34062
34281
|
code: "request-body-required",
|
|
@@ -34073,7 +34292,7 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
34073
34292
|
}
|
|
34074
34293
|
return;
|
|
34075
34294
|
}
|
|
34076
|
-
if (currentBody
|
|
34295
|
+
if (currentBody["required"] === true && baseBody["required"] !== true) {
|
|
34077
34296
|
addChange(changes, {
|
|
34078
34297
|
kind: "breaking",
|
|
34079
34298
|
code: "request-body-required",
|
|
@@ -34081,8 +34300,8 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
34081
34300
|
message: "An optional request body became required."
|
|
34082
34301
|
});
|
|
34083
34302
|
}
|
|
34084
|
-
const baseContent = recordValue(baseBody
|
|
34085
|
-
const currentContent = recordValue(currentBody
|
|
34303
|
+
const baseContent = recordValue(baseBody["content"]);
|
|
34304
|
+
const currentContent = recordValue(currentBody["content"]);
|
|
34086
34305
|
for (const mediaType of sortedKeys2(baseContent)) {
|
|
34087
34306
|
const baseMedia = recordValue(baseContent?.[mediaType]);
|
|
34088
34307
|
const currentMedia = recordValue(currentContent?.[mediaType]);
|
|
@@ -34095,14 +34314,14 @@ function compareRequestBody(baseOperation, currentOperation, baseDocument, curre
|
|
|
34095
34314
|
});
|
|
34096
34315
|
continue;
|
|
34097
34316
|
}
|
|
34098
|
-
if (baseMedia
|
|
34099
|
-
compareSchema(baseMedia
|
|
34317
|
+
if (baseMedia["schema"] !== undefined && currentMedia["schema"] !== undefined) {
|
|
34318
|
+
compareSchema(baseMedia["schema"], currentMedia["schema"], baseDocument, currentDocument, `${path}.requestBody.content.${mediaType}.schema`, "input", changes);
|
|
34100
34319
|
}
|
|
34101
34320
|
}
|
|
34102
34321
|
}
|
|
34103
34322
|
function compareResponses(baseOperation, currentOperation, baseDocument, currentDocument, path, changes) {
|
|
34104
|
-
const baseResponses = recordValue(baseOperation
|
|
34105
|
-
const currentResponses = recordValue(currentOperation
|
|
34323
|
+
const baseResponses = recordValue(baseOperation["responses"]);
|
|
34324
|
+
const currentResponses = recordValue(currentOperation["responses"]);
|
|
34106
34325
|
for (const status of sortedKeys2(baseResponses)) {
|
|
34107
34326
|
const baseResponse = recordValue(baseResponses?.[status]);
|
|
34108
34327
|
const currentResponse = recordValue(currentResponses?.[status]);
|
|
@@ -34115,8 +34334,8 @@ function compareResponses(baseOperation, currentOperation, baseDocument, current
|
|
|
34115
34334
|
});
|
|
34116
34335
|
continue;
|
|
34117
34336
|
}
|
|
34118
|
-
const baseContent = recordValue(baseResponse
|
|
34119
|
-
const currentContent = recordValue(currentResponse
|
|
34337
|
+
const baseContent = recordValue(baseResponse["content"]);
|
|
34338
|
+
const currentContent = recordValue(currentResponse["content"]);
|
|
34120
34339
|
for (const mediaType of sortedKeys2(baseContent)) {
|
|
34121
34340
|
const baseMedia = recordValue(baseContent?.[mediaType]);
|
|
34122
34341
|
const currentMedia = recordValue(currentContent?.[mediaType]);
|
|
@@ -34129,8 +34348,8 @@ function compareResponses(baseOperation, currentOperation, baseDocument, current
|
|
|
34129
34348
|
});
|
|
34130
34349
|
continue;
|
|
34131
34350
|
}
|
|
34132
|
-
if (baseMedia
|
|
34133
|
-
compareSchema(baseMedia
|
|
34351
|
+
if (baseMedia["schema"] !== undefined && currentMedia["schema"] !== undefined) {
|
|
34352
|
+
compareSchema(baseMedia["schema"], currentMedia["schema"], baseDocument, currentDocument, `${path}.responses.${status}.content.${mediaType}.schema`, "output", changes);
|
|
34134
34353
|
}
|
|
34135
34354
|
}
|
|
34136
34355
|
}
|
|
@@ -34149,8 +34368,8 @@ function compareOperation(basePathItem, currentPathItem, baseOperation, currentO
|
|
|
34149
34368
|
compareParameters(basePathItem, currentPathItem, baseOperation, currentOperation, baseDocument, currentDocument, path, changes);
|
|
34150
34369
|
compareRequestBody(baseOperation, currentOperation, baseDocument, currentDocument, path, changes);
|
|
34151
34370
|
compareResponses(baseOperation, currentOperation, baseDocument, currentDocument, path, changes);
|
|
34152
|
-
const baseSecurity = baseOperation
|
|
34153
|
-
const currentSecurity = currentOperation
|
|
34371
|
+
const baseSecurity = baseOperation["security"];
|
|
34372
|
+
const currentSecurity = currentOperation["security"];
|
|
34154
34373
|
if (Array.isArray(currentSecurity) && currentSecurity.length > 0 && (!Array.isArray(baseSecurity) || baseSecurity.length === 0)) {
|
|
34155
34374
|
addChange(changes, {
|
|
34156
34375
|
kind: "breaking",
|
|
@@ -34161,8 +34380,8 @@ function compareOperation(basePathItem, currentPathItem, baseOperation, currentO
|
|
|
34161
34380
|
}
|
|
34162
34381
|
}
|
|
34163
34382
|
function compareComponents(baseDocument, currentDocument, changes) {
|
|
34164
|
-
const baseComponents = recordValue(baseDocument
|
|
34165
|
-
const currentComponents = recordValue(currentDocument
|
|
34383
|
+
const baseComponents = recordValue(baseDocument["components"]);
|
|
34384
|
+
const currentComponents = recordValue(currentDocument["components"]);
|
|
34166
34385
|
for (const group of COMPONENT_GROUPS) {
|
|
34167
34386
|
const baseGroup = recordValue(baseComponents?.[group]);
|
|
34168
34387
|
const currentGroup = recordValue(currentComponents?.[group]);
|
|
@@ -34189,10 +34408,10 @@ function compareComponents(baseDocument, currentDocument, changes) {
|
|
|
34189
34408
|
}
|
|
34190
34409
|
}
|
|
34191
34410
|
function parseOpenApiDocument(value) {
|
|
34192
|
-
if (!isRecord(value) || typeof value
|
|
34411
|
+
if (!isRecord(value) || typeof value["openapi"] !== "string" || !/^3\.[0-9]+(?:\.[0-9]+)?$/.test(value["openapi"]) || !isRecord(value["info"]) || !isRecord(value["paths"])) {
|
|
34193
34412
|
throw new OpenApiDocumentError;
|
|
34194
34413
|
}
|
|
34195
|
-
return { ...value, openapi: value
|
|
34414
|
+
return { ...value, openapi: value["openapi"], info: value["info"], paths: value["paths"] };
|
|
34196
34415
|
}
|
|
34197
34416
|
function serializeOpenApiJson(document, space = 2) {
|
|
34198
34417
|
const parsed = parseOpenApiDocument(document);
|
|
@@ -34241,7 +34460,7 @@ async function loadGeneratedOpenApiDocument(modulePath) {
|
|
|
34241
34460
|
const loaded = await import(moduleUrl.href);
|
|
34242
34461
|
if (!isRecord(loaded))
|
|
34243
34462
|
throw new OpenApiDocumentError;
|
|
34244
|
-
return parseOpenApiDocument(loaded
|
|
34463
|
+
return parseOpenApiDocument(loaded["OPENAPI_DOCUMENT"]);
|
|
34245
34464
|
} catch (error) {
|
|
34246
34465
|
if (error instanceof OpenApiDocumentError)
|
|
34247
34466
|
throw error;
|
|
@@ -34401,16 +34620,19 @@ async function assessMigration(options) {
|
|
|
34401
34620
|
};
|
|
34402
34621
|
try {
|
|
34403
34622
|
const parsed = JSON.parse(await readFile11(contractsManifestPath, "utf8"));
|
|
34404
|
-
if (!isRecord2(parsed) || parsed
|
|
34623
|
+
if (!isRecord2(parsed) || parsed["version"] !== 1)
|
|
34405
34624
|
throw new Error("invalid manifest");
|
|
34625
|
+
const commands = arrayLength(parsed["commands"]);
|
|
34626
|
+
const routes = arrayLength(parsed["routes"]);
|
|
34627
|
+
const permissions = arrayLength(parsed["permissions"]);
|
|
34406
34628
|
contractsManifest = {
|
|
34407
34629
|
path: contractsManifestPath,
|
|
34408
34630
|
present: true,
|
|
34409
34631
|
sha256: await sha2562(contractsManifestPath),
|
|
34410
34632
|
version: 1,
|
|
34411
|
-
...
|
|
34412
|
-
...
|
|
34413
|
-
...
|
|
34633
|
+
...commands === undefined ? {} : { commands },
|
|
34634
|
+
...routes === undefined ? {} : { routes },
|
|
34635
|
+
...permissions === undefined ? {} : { permissions }
|
|
34414
34636
|
};
|
|
34415
34637
|
} catch {
|
|
34416
34638
|
findings.push({
|
|
@@ -34641,15 +34863,20 @@ function checkGraphqlCompatibility(schema, documents, policy = {}) {
|
|
|
34641
34863
|
try {
|
|
34642
34864
|
parsed = parse9(document.source);
|
|
34643
34865
|
} catch (error) {
|
|
34644
|
-
diagnostics.push({
|
|
34866
|
+
diagnostics.push({
|
|
34867
|
+
severity: "error",
|
|
34868
|
+
code: "graphql-document-invalid",
|
|
34869
|
+
message: error instanceof Error ? error.message : String(error),
|
|
34870
|
+
...document.path === undefined ? {} : { file: document.path }
|
|
34871
|
+
});
|
|
34645
34872
|
continue;
|
|
34646
34873
|
}
|
|
34647
34874
|
diagnostics.push(...validate2(schema, parsed).map((error) => ({
|
|
34648
34875
|
severity: "error",
|
|
34649
34876
|
code: "graphql-validation",
|
|
34650
34877
|
message: error.message,
|
|
34651
|
-
file: document.path,
|
|
34652
|
-
line: error.locations
|
|
34878
|
+
...document.path === undefined ? {} : { file: document.path },
|
|
34879
|
+
...error.locations?.[0]?.line === undefined ? {} : { line: error.locations[0].line }
|
|
34653
34880
|
})));
|
|
34654
34881
|
const fragmentDefinitions = new Map(parsed.definitions.filter((definition) => definition.kind === Kind2.FRAGMENT_DEFINITION).map((definition) => [definition.name.value, definition]));
|
|
34655
34882
|
for (const definition of parsed.definitions) {
|
|
@@ -34657,7 +34884,10 @@ function checkGraphqlCompatibility(schema, documents, policy = {}) {
|
|
|
34657
34884
|
continue;
|
|
34658
34885
|
const result = operationReport(schema, definition, fragmentDefinitions, policy);
|
|
34659
34886
|
operations.push(result.report);
|
|
34660
|
-
diagnostics.push(...result.diagnostics.map((item) => ({
|
|
34887
|
+
diagnostics.push(...result.diagnostics.map((item) => ({
|
|
34888
|
+
...item,
|
|
34889
|
+
...document.path === undefined ? {} : { file: document.path }
|
|
34890
|
+
})));
|
|
34661
34891
|
}
|
|
34662
34892
|
}
|
|
34663
34893
|
return { ok: diagnostics.every((item) => item.severity !== "error"), features: graphqlFeatureMatrix(schema), operations, diagnostics };
|