Skip to content

Commit abbea7e

Browse files
authored
feat: add --main-export flag to ct dev command (#1885)
Add --main-export flag to ct dev command to specify which named export from the entry file should be used as the recipe definition. This brings ct dev into parity with ct charm new. Changes: - Add --main-export option to dev command CLI interface - Add mainExport field to ProcessOptions interface - Set program.mainExport before processing in lib/dev.ts - Use specified export name when accessing module exports - Add test fixture with both default and named exports - Add tests for default export behavior and named export behavior The Engine already supports mainExport via RuntimeProgram, so this change only wires up the CLI flag to the existing infrastructure.
1 parent 538ee3b commit abbea7e

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

packages/cli/commands/dev.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export const dev = new Command()
3333
"--show-transformed",
3434
"Show only the transformed TypeScript source code without executing the recipe.",
3535
)
36+
.option(
37+
"--main-export <export:string>",
38+
'Named export from entry for recipe definition. Defaults to "default".',
39+
)
3640
.arguments("<main:string>")
3741
.action(async (options, main) => {
3842
const { main: exports } = await process({
@@ -42,11 +46,15 @@ export const dev = new Command()
4246
output: options.output,
4347
filename: options.filename,
4448
showTransformed: options.showTransformed,
49+
mainExport: options.mainExport,
4550
});
4651
// If --show-transformed is used, the transformed source is already printed to stdout
4752
// and we don't want to print the JSON output
4853
if (!options.showTransformed && exports) {
49-
const mainExport = "default" in exports ? exports.default : exports;
54+
// Select the export to render. If no --main-export specified, use "default".
55+
// This mirrors the logic in Engine.run() which uses program.mainExport ?? "default"
56+
const exportName = options.mainExport ?? "default";
57+
const mainExport = exportName in exports ? exports[exportName] : exports;
5058
try {
5159
// Stringify before rendering, as the exported
5260
// recipe is a function with extra properties via Object.assign
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Test file with named export instead of default export
2+
import { h, recipe, schema } from "commontools";
3+
4+
const model = schema({
5+
type: "object",
6+
properties: {
7+
message: { type: "string", default: "from named export" },
8+
},
9+
default: { message: "from named export" },
10+
});
11+
12+
export const myNamedRecipe = recipe(model, model, (cell) => {
13+
return {
14+
message: cell.message,
15+
};
16+
});
17+
18+
export default recipe(model, model, (cell) => {
19+
return {
20+
message: "from default export",
21+
};
22+
});

packages/cli/lib/dev.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface ProcessOptions {
2121
output?: string;
2222
filename?: string;
2323
showTransformed?: boolean;
24+
mainExport?: string;
2425
}
2526

2627
export async function process(
@@ -35,6 +36,9 @@ export async function process(
3536
const program = await engine.resolve(
3637
new FileSystemProgramResolver(options.main),
3738
);
39+
if (options.mainExport) {
40+
program.mainExport = options.mainExport;
41+
}
3842
const getTransformedProgram = options.showTransformed
3943
? renderTransformed
4044
: undefined;

packages/cli/test/dev.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,27 @@ describe("cli dev", () => {
2828
const rendered = bytesToLines(await Deno.readFile(temp));
2929
expect(rendered[rendered.length - 1]).toEqual("//# sourceURL=test-file.js");
3030
});
31+
32+
it("Uses default export when no --main-export specified", async () => {
33+
const { code, stdout, stderr } = await ct(
34+
"dev fixtures/named-export.tsx",
35+
);
36+
checkStderr(stderr);
37+
const output = JSON.parse(stdout.join("\n"));
38+
expect(output.result.message).toBe("from default export");
39+
expect(code).toBe(0);
40+
});
41+
42+
it("Uses specified named export with --main-export", async () => {
43+
const { code, stdout, stderr } = await ct(
44+
"dev fixtures/named-export.tsx --main-export myNamedRecipe",
45+
);
46+
checkStderr(stderr);
47+
const output = JSON.parse(stdout.join("\n"));
48+
// Named export uses cell reference, so check the argument schema
49+
expect(output.argumentSchema.default.message).toBe("from named export");
50+
// Also verify mainExport was set correctly in program
51+
expect(output.program.mainExport).toBe("myNamedRecipe");
52+
expect(code).toBe(0);
53+
});
3154
});

0 commit comments

Comments
 (0)