Merge remote-tracking branch 'origin/main' into explore-git-sync-improvements

This commit is contained in:
hugocasa
2026-07-06 21:45:27 +02:00
81 changed files with 3211 additions and 513 deletions
+1 -1
View File
@@ -10,4 +10,4 @@ export const WM_FORK_PREFIX = "wm-fork";
// (e.g. utils.ts) can read it without importing main.ts and creating a circular
// dependency (main → workspace → utils → main) that triggers a TDZ.
// Re-exported from main.ts for backwards compatibility.
export const VERSION = "1.749.0";
export const VERSION = "1.751.0";
+7 -3
View File
@@ -1,5 +1,9 @@
import { Schema, SchemaProperty } from "../../bootstrap/common.ts";
function quotePropName(name: string): string {
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
}
export function compileResourceTypeToTsType(schema: Schema) {
function rec(x: { [name: string]: SchemaProperty }, root = false) {
let res = "{\n";
@@ -10,15 +14,15 @@ export function compileResourceTypeToTsType(schema: Schema) {
let i = 0;
for (let [name, prop] of entries) {
if (prop.type == "object") {
res += ` ${name}: ${rec(prop.properties ?? {})}`;
res += ` ${quotePropName(name)}: ${rec(prop.properties ?? {})}`;
} else if (prop.type == "array") {
res += ` ${name}: ${prop?.items?.type ?? "any"}[]`;
res += ` ${quotePropName(name)}: ${prop?.items?.type ?? "any"}[]`;
} else {
let typ = prop?.type ?? "any";
if (typ == "integer") {
typ = "number";
}
res += ` ${name}: ${typ}`;
res += ` ${quotePropName(name)}: ${typ}`;
}
i++;
if (i < entries.length) {
+68
View File
@@ -0,0 +1,68 @@
import { expect, test } from "bun:test";
import { compileResourceTypeToTsType } from "../src/utils/resource_types.ts";
import type { Schema } from "../bootstrap/common.ts";
// =============================================================================
// Resource-type namespace generation (WIN-2132)
//
// `compileResourceTypeToTsType` renders a JSON Schema into the body of a
// TypeScript type used in the generated `rt.d.ts` (RT namespace). JSON Schema
// property names are unconstrained, so a name with a colon, hyphen, or space
// is legal in the schema but not a valid bare TS identifier. Emitting it raw
// produced syntactically invalid output that broke `tsc`. These tests pin that
// such names are quoted while plain identifiers stay bare.
// =============================================================================
function schema(properties: Schema["properties"]): Schema {
return {
$schema: undefined,
type: "object",
properties,
required: [],
};
}
test("plain identifiers are emitted without quotes", () => {
const out = compileResourceTypeToTsType(
schema({
host: { type: "string" },
_port: { type: "integer" },
$ref: { type: "boolean" },
})
);
expect(out).toContain(" host: string");
expect(out).toContain(" _port: number");
expect(out).toContain(" $ref: boolean");
expect(out).not.toContain('"host"');
});
test("non-identifier property names are double-quoted", () => {
const out = compileResourceTypeToTsType(
schema({
"content-type": { type: "string" },
"x:api:key": { type: "string" },
"with space": { type: "integer" },
"3leading": { type: "boolean" },
})
);
expect(out).toContain(' "content-type": string');
expect(out).toContain(' "x:api:key": string');
expect(out).toContain(' "with space": number');
expect(out).toContain(' "3leading": boolean');
});
test("nested object and array property names are quoted too", () => {
const out = compileResourceTypeToTsType(
schema({
"nested-obj": {
type: "object",
properties: { "inner-key": { type: "string" } },
},
"arr-field": { type: "array", items: { type: "string" } },
})
);
expect(out).toContain('"nested-obj": {');
expect(out).toContain('"inner-key": string');
expect(out).toContain('"arr-field": string[]');
});