Mark first-party generated files with .gen; preserve third-party conventions

This commit is contained in:
Timothy J. Aveni
2026-09-15 17:32:53 -07:00
parent 1afc9feb94
commit e557a057d8
8 changed files with 21 additions and 16 deletions
+1
View File
@@ -1,3 +1,4 @@
nixExprPath: yarn-project.gen.nix
enableScripts: true enableScripts: true
generateDefaultNix: false generateDefaultNix: false
+1 -1
View File
@@ -119,7 +119,7 @@ fragment, so fragments do not become independent repositories or identities.
Executable package metadata remains protobuf text format: Executable package metadata remains protobuf text format:
```sh ```sh
quixos-descriptor-check path/to/descriptor.quixos-package.txtpb quixos-descriptor-check path/to/descriptor.quixos-package.gen.txtpb
``` ```
Descriptors identify exact package revisions and exported runtime symbols. Descriptors identify exact package revisions and exported runtime symbols.
+2 -2
View File
@@ -18,7 +18,7 @@
let let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs { inherit system; };
nodejs = pkgs.nodejs_24; nodejs = pkgs.nodejs_24;
quixos-protocol = (pkgs.callPackage ./yarn-project.nix { inherit nodejs; }) { quixos-protocol = (pkgs.callPackage ./yarn-project.gen.nix { inherit nodejs; }) {
src = pkgs.lib.cleanSource ./.; src = pkgs.lib.cleanSource ./.;
overrideAttrs = old: { overrideAttrs = old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [
@@ -127,7 +127,7 @@
in in
{ {
packages.default = quixos-protocol; packages.default = quixos-protocol;
packages.inspector = (pkgs.callPackage ./yarn-project.nix { inherit nodejs; }) { packages.inspector = (pkgs.callPackage ./yarn-project.gen.nix { inherit nodejs; }) {
src = pkgs.lib.fileset.toSource { src = pkgs.lib.fileset.toSource {
root = ./.; root = ./.;
fileset = pkgs.lib.fileset.unions [ fileset = pkgs.lib.fileset.unions [
+1 -1
View File
@@ -12,7 +12,7 @@ const main = async () => {
const generated = generateTypeScriptBindings(JSON.parse(await readFile(schema, "utf8")), revision, config); const generated = generateTypeScriptBindings(JSON.parse(await readFile(schema, "utf8")), revision, config);
await writeFile(output, generated); await writeFile(output, generated);
if (config.messages?.["org.quixos.web-studio.ReactProps"]) { if (config.messages?.["org.quixos.web-studio.ReactProps"]) {
await writeFile(path.join(path.dirname(output), "web-studio-react-runtime.d.ts"), reactPlatformTypes); await writeFile(path.join(path.dirname(output), "web-studio-react-runtime.gen.d.ts"), reactPlatformTypes);
} }
}; };
main().catch((error: unknown) => { main().catch((error: unknown) => {
+8 -8
View File
@@ -146,13 +146,13 @@ export const scaffoldRecipe = async (
); );
create( create(
"src/impl/sourceGet.ts", "src/impl/sourceGet.ts",
`import componentSource from "../component.js?browser-source";\nimport type {Implementation} from "../gen/qx.js";\nexport const handler: Implementation["sourceGet"] = () => componentSource;\n`, `import componentSource from "../component.js?browser-source";\nimport type {Implementation} from "../gen/qx.gen.js";\nexport const handler: Implementation["sourceGet"] = () => componentSource;\n`,
); );
create( create(
"src/browser-assets.d.ts", "src/browser-assets.d.ts",
`declare module "*?browser-source" { const source: string; export default source; }\ndeclare module "*.css" {}\n`, `declare module "*?browser-source" { const source: string; export default source; }\ndeclare module "*.css" {}\n`,
); );
create("src/gen/web-studio-react-runtime.d.ts", reactPlatformTypes); create("src/gen/web-studio-react-runtime.gen.d.ts", reactPlatformTypes);
} }
create(".gitignore", "node_modules/\ndist/\n.quixos/\nresult\n.yarn/install-state.gz\n"); create(".gitignore", "node_modules/\ndist/\n.quixos/\nresult\n.yarn/install-state.gz\n");
create( create(
@@ -177,7 +177,7 @@ export const scaffoldRecipe = async (
"quixos.check.json", "quixos.check.json",
json({ json({
backend: "typescript", backend: "typescript",
bindingOutput: "src/gen/qx.ts", bindingOutput: "src/gen/qx.gen.ts",
...(react ...(react
? { ? {
options: { options: {
@@ -204,7 +204,7 @@ export const scaffoldRecipe = async (
inherit inputs nixpkgs flake-utils; packageRoot = ./.; inherit inputs nixpkgs flake-utils; packageRoot = ./.;
bundle = { entry = ${JSON.stringify(react ? "src/server.ts" : "dist/server.js")}; ${react ? "browserSources = true;" : ""} }; bundle = { entry = ${JSON.stringify(react ? "src/server.ts" : "dist/server.js")}; ${react ? "browserSources = true;" : ""} };
migrationEntrypoint = "dist/migrate.js"; migrationEntrypoint = "dist/migrate.js";
installServer = { libexecName = ${JSON.stringify(name.toLowerCase())}; descriptorPath = "descriptor.quixos-package.txtpb"; }; installServer = { libexecName = ${JSON.stringify(name.toLowerCase())}; descriptorPath = "descriptor.quixos-package.gen.txtpb"; };
}; };
}\n`, }\n`,
); );
@@ -282,7 +282,7 @@ export const scaffoldRecipe = async (
const implementation = const implementation =
command === "migration" command === "migration"
? `import type {MigrationContext} from "@quixos/camino-package-runtime";\nexport const handler = async (_context: MigrationContext): Promise<void> => { throw new Error(${JSON.stringify(`Implement migration ${name}`)}); };\n` ? `import type {MigrationContext} from "@quixos/camino-package-runtime";\nexport const handler = async (_context: MigrationContext): Promise<void> => { throw new Error(${JSON.stringify(`Implement migration ${name}`)}); };\n`
: `import type {Implementation} from "../gen/qx.js";\nexport const handler: Implementation[${JSON.stringify(name)}] = ${derived ? '{kind: "derived", get: ' : ""}async (_context) => { throw new Error(${JSON.stringify(`Implement ${name}`)}); }${derived ? "}" : ""};\n`; : `import type {Implementation} from "../gen/qx.gen.js";\nexport const handler: Implementation[${JSON.stringify(name)}] = ${derived ? '{kind: "derived", get: ' : ""}async (_context) => { throw new Error(${JSON.stringify(`Implement ${name}`)}); }${derived ? "}" : ""};\n`;
create(file, implementation); create(file, implementation);
packageModel.exports.push({ name, id: spec.id, file, ...(command === "migration" ? { migration: true } : {}) }); packageModel.exports.push({ name, id: spec.id, file, ...(command === "migration" ? { migration: true } : {}) });
if (command === "migration") { if (command === "migration") {
@@ -333,7 +333,7 @@ export const scaffoldRecipe = async (
} else { } else {
create( create(
"src/server.ts", "src/server.ts",
`import {servePackageRuntime} from "@quixos/camino-package-runtime";\nimport {createRuntime} from "./gen/qx.js";\n` + `import {servePackageRuntime} from "@quixos/camino-package-runtime";\nimport {createRuntime} from "./gen/qx.gen.js";\n` +
packageModel.exports packageModel.exports
.filter((entry) => !entry.migration) .filter((entry) => !entry.migration)
.map( .map(
@@ -364,7 +364,7 @@ export const scaffoldRecipe = async (
); );
} }
generated( generated(
"descriptor.quixos-package.txtpb", "descriptor.quixos-package.gen.txtpb",
`# Generated by qx-scaffold-v1\npackage_id: ${JSON.stringify(packageModel.id)}\npackage_revision_id: ${JSON.stringify(packageModel.revision)}\nruntime_protocol_version: "quixos-capabilities-v1"\n` + `# Generated by qx-scaffold-v1\npackage_id: ${JSON.stringify(packageModel.id)}\npackage_revision_id: ${JSON.stringify(packageModel.revision)}\nruntime_protocol_version: "quixos-capabilities-v1"\n` +
packageModel.exports packageModel.exports
.map( .map(
@@ -403,7 +403,7 @@ export const scaffoldRecipe = async (
} }
// A composed React recipe supplies its own modules and complete server. // A composed React recipe supplies its own modules and complete server.
if (reactRecipe(spec)) { if (reactRecipe(spec)) {
for (const file of ["src/component.tsx", "src/impl/sourceGet.ts", "descriptor.quixos-package.txtpb"]) for (const file of ["src/component.tsx", "src/impl/sourceGet.ts", "descriptor.quixos-package.gen.txtpb"])
if (!(file in spec.initialFiles)) { if (!(file in spec.initialFiles)) {
const index = files.findIndex((entry) => entry.file === prefix + file); const index = files.findIndex((entry) => entry.file === prefix + file);
if (index >= 0) files.splice(index, 1); if (index >= 0) files.splice(index, 1);
+3 -2
View File
@@ -437,6 +437,7 @@ const main = async () => {
for (const [executable, args] of [ for (const [executable, args] of [
["corepack", ["yarn", "plugin", "import", toolchain.nixifyPluginUrl]], ["corepack", ["yarn", "plugin", "import", toolchain.nixifyPluginUrl]],
["corepack", ["yarn", "config", "set", "generateDefaultNix", "false"]], ["corepack", ["yarn", "config", "set", "generateDefaultNix", "false"]],
["corepack", ["yarn", "config", "set", "nixExprPath", "yarn-project.gen.nix"]],
["corepack", ["yarn", "config", "set", "individualNixPackaging", "true"]], ["corepack", ["yarn", "config", "set", "individualNixPackaging", "true"]],
["corepack", ["yarn", "install"]], ["corepack", ["yarn", "install"]],
] as const) { ] as const) {
@@ -447,10 +448,10 @@ const main = async () => {
); );
} }
try { try {
await readFile(path.join(cwd, "yarn-project.nix")); await readFile(path.join(cwd, "yarn-project.gen.nix"));
} catch { } catch {
throw new Error( throw new Error(
"Nixify did not generate yarn-project.nix. It skips repositories under the OS temporary directory; use an ordinary workspace checkout and retry installation.", "Nixify did not generate yarn-project.gen.nix. It skips repositories under the OS temporary directory; use an ordinary workspace checkout and retry installation.",
); );
} }
await snapshotCommit(cwd); await snapshotCommit(cwd);
+5 -2
View File
@@ -28,7 +28,10 @@ test("React preset applies its browser build script and shared-platform imports"
await applyStructure(await planStructure(root, request)); await applyStructure(await planStructure(root, request));
assert.match(await fs.readFile(path.join(root, "src/impl/sourceGet.ts"), "utf8"), /component.js\?browser-source/); assert.match(await fs.readFile(path.join(root, "src/impl/sourceGet.ts"), "utf8"), /component.js\?browser-source/);
assert.match(await fs.readFile(path.join(root, "flake.nix"), "utf8"), /browserSources = true/); assert.match(await fs.readFile(path.join(root, "flake.nix"), "utf8"), /browserSources = true/);
assert.equal(await fs.readFile(path.join(root, "src/gen/web-studio-react-runtime.d.ts"), "utf8"), reactPlatformTypes); assert.equal(
await fs.readFile(path.join(root, "src/gen/web-studio-react-runtime.gen.d.ts"), "utf8"),
reactPlatformTypes,
);
assert.match(await fs.readFile(path.join(root, "src/browser-assets.d.ts"), "utf8"), /declare module "\*\.css"/); assert.match(await fs.readFile(path.join(root, "src/browser-assets.d.ts"), "utf8"), /declare module "\*\.css"/);
assert.equal( assert.equal(
JSON.parse(await fs.readFile(path.join(root, "quixos.check.json"), "utf8")).options.messages[ JSON.parse(await fs.readFile(path.join(root, "quixos.check.json"), "utf8")).options.messages[
@@ -62,7 +65,7 @@ test("imperative scaffolds preserve authored wiring; migration sealing is explic
await apply("function", { ...base, name: "play", id: "export:play" }); await apply("function", { ...base, name: "play", id: "export:play" });
const filename = path.join(root, base.directory, "src/impl/play.ts"); const filename = path.join(root, base.directory, "src/impl/play.ts");
const edited = const edited =
'import type {Implementation} from "../gen/qx.js";\nexport const handler: Implementation["play"] = async () => null;\n'; 'import type {Implementation} from "../gen/qx.gen.js";\nexport const handler: Implementation["play"] = async () => null;\n';
await fs.writeFile(filename, edited); await fs.writeFile(filename, edited);
const old = { version: 1 }, const old = { version: 1 },
next = { version: 2 }, next = { version: 2 },