88import { expect , test , describe } from "bun:test" ;
99import { withTestBackend } from "./test_backend.ts" ;
1010import { addWorkspace } from "../workspace.ts" ;
11- import { writeFile } from "node:fs/promises" ;
11+ import { mkdir , readFile , stat , writeFile } from "node:fs/promises" ;
1212import {
1313 createLocalScript ,
1414 createLocalFlow ,
@@ -19,7 +19,12 @@ import {
1919/**
2020 * Helper to set up a workspace with wmill.yaml
2121 */
22- async function setupWorkspace ( backend : any , tempDir : string , workspaceName : string ) {
22+ async function setupWorkspace (
23+ backend : any ,
24+ tempDir : string ,
25+ workspaceName : string ,
26+ nonDottedPaths = false
27+ ) {
2328 const testWorkspace = {
2429 remote : backend . baseUrl ,
2530 workspaceId : backend . workspace ,
@@ -29,11 +34,88 @@ async function setupWorkspace(backend: any, tempDir: string, workspaceName: stri
2934 await addWorkspace ( testWorkspace , { force : true , configDir : backend . testConfigDir } ) ;
3035
3136 await writeFile ( `${ tempDir } /wmill.yaml` , `defaultTs: bun
32- includes:
37+ ${ nonDottedPaths ? "nonDottedPaths: true\n" : "" } includes:
3338 - "**"
3439excludes: []` , "utf-8" ) ;
3540}
3641
42+ async function createLocalNonDottedFlow ( tempDir : string , name : string ) {
43+ const flowDir = `${ tempDir } /f/test/${ name } __flow` ;
44+ await mkdir ( flowDir , { recursive : true } ) ;
45+
46+ await writeFile (
47+ `${ flowDir } /a.ts` ,
48+ `export async function main() {\n return "Hello from flow ${ name } ";\n}` ,
49+ "utf-8"
50+ ) ;
51+
52+ await writeFile (
53+ `${ flowDir } /flow.yaml` ,
54+ `summary: "${ name } flow"
55+ description: "A flow for testing"
56+ value:
57+ modules:
58+ - id: a
59+ value:
60+ type: rawscript
61+ content: "!inline a.ts"
62+ language: bun
63+ input_transforms: {}
64+ schema:
65+ $schema: "https://json-schema.org/draft/2020-12/schema"
66+ type: object
67+ properties: {}
68+ required: []
69+ ` ,
70+ "utf-8"
71+ ) ;
72+ }
73+
74+ async function createLocalNonDottedApp ( tempDir : string , name : string ) {
75+ const appDir = `${ tempDir } /f/test/${ name } __app` ;
76+ await mkdir ( appDir , { recursive : true } ) ;
77+
78+ await writeFile (
79+ `${ appDir } /app.yaml` ,
80+ `summary: "${ name } app"
81+ value:
82+ type: app
83+ grid:
84+ - id: button1
85+ data:
86+ type: buttoncomponent
87+ componentInput:
88+ type: runnable
89+ runnable:
90+ type: runnableByName
91+ inlineScript:
92+ content: |
93+ export async function main() {
94+ return "hello from app";
95+ }
96+ language: bun
97+ hiddenInlineScripts: []
98+ css: {}
99+ norefreshbar: false
100+ policy:
101+ on_behalf_of: null
102+ on_behalf_of_email: null
103+ triggerables: {}
104+ execution_mode: viewer
105+ ` ,
106+ "utf-8"
107+ ) ;
108+ }
109+
110+ async function fileExists ( filePath : string ) : Promise < boolean > {
111+ try {
112+ await stat ( filePath ) ;
113+ return true ;
114+ } catch {
115+ return false ;
116+ }
117+ }
118+
37119// =============================================================================
38120// Main test: processes scripts, flows, and apps together
39121// =============================================================================
@@ -156,6 +238,87 @@ describe("generate-metadata flags", () => {
156238 } ) ;
157239 } ) ;
158240
241+ test ( "--lock-only preserves non-dotted flow filenames" , async ( ) => {
242+ await withTestBackend ( async ( backend , tempDir ) => {
243+ await setupWorkspace ( backend , tempDir , "lock_only_non_dotted_test" , true ) ;
244+
245+ await createLocalNonDottedFlow ( tempDir , "my_flow" ) ;
246+
247+ const result = await backend . runCLICommand (
248+ [ "generate-metadata" , "--yes" , "--lock-only" ] ,
249+ tempDir ,
250+ "lock_only_non_dotted_test"
251+ ) ;
252+
253+ expect ( result . code ) . toEqual ( 0 ) ;
254+
255+ const flowDir = `${ tempDir } /f/test/my_flow__flow` ;
256+ const flowYaml = await readFile ( `${ flowDir } /flow.yaml` , "utf-8" ) ;
257+
258+ expect ( flowYaml ) . toContain ( "!inline a.ts" ) ;
259+ expect ( flowYaml ) . toContain ( "!inline a.lock" ) ;
260+ expect ( flowYaml ) . not . toContain ( ".inline_script." ) ;
261+ expect ( await fileExists ( `${ flowDir } /a.lock` ) ) . toEqual ( true ) ;
262+ expect ( await fileExists ( `${ flowDir } /a.inline_script.ts` ) ) . toEqual ( false ) ;
263+ expect ( await fileExists ( `${ flowDir } /a.inline_script.lock` ) ) . toEqual ( false ) ;
264+ } ) ;
265+ } ) ;
266+
267+ test ( "generate-metadata preserves non-dotted flow inline script filenames" , async ( ) => {
268+ await withTestBackend ( async ( backend , tempDir ) => {
269+ await setupWorkspace ( backend , tempDir , "full_gen_non_dotted_flow_test" , true ) ;
270+
271+ await createLocalNonDottedFlow ( tempDir , "my_flow" ) ;
272+
273+ const result = await backend . runCLICommand (
274+ [ "generate-metadata" , "--yes" ] ,
275+ tempDir ,
276+ "full_gen_non_dotted_flow_test"
277+ ) ;
278+
279+ expect ( result . code ) . toEqual ( 0 ) ;
280+
281+ const flowDir = `${ tempDir } /f/test/my_flow__flow` ;
282+ const flowYaml = await readFile ( `${ flowDir } /flow.yaml` , "utf-8" ) ;
283+
284+ // Inline script references should use non-dotted naming
285+ expect ( flowYaml ) . toContain ( "!inline a.ts" ) ;
286+ expect ( flowYaml ) . toContain ( "!inline a.lock" ) ;
287+ expect ( flowYaml ) . not . toContain ( ".inline_script." ) ;
288+ expect ( await fileExists ( `${ flowDir } /a.ts` ) ) . toEqual ( true ) ;
289+ expect ( await fileExists ( `${ flowDir } /a.lock` ) ) . toEqual ( true ) ;
290+ expect ( await fileExists ( `${ flowDir } /a.inline_script.ts` ) ) . toEqual ( false ) ;
291+ expect ( await fileExists ( `${ flowDir } /a.inline_script.lock` ) ) . toEqual ( false ) ;
292+ } ) ;
293+ } ) ;
294+
295+ test ( "generate-metadata uses non-dotted app inline script filenames" , async ( ) => {
296+ await withTestBackend ( async ( backend , tempDir ) => {
297+ await setupWorkspace ( backend , tempDir , "non_dotted_app_gen_test" , true ) ;
298+
299+ await createLocalNonDottedApp ( tempDir , "my_app" ) ;
300+
301+ const result = await backend . runCLICommand (
302+ [ "generate-metadata" , "--yes" ] ,
303+ tempDir ,
304+ "non_dotted_app_gen_test"
305+ ) ;
306+
307+ expect ( result . code ) . toEqual ( 0 ) ;
308+
309+ const appDir = `${ tempDir } /f/test/my_app__app` ;
310+ const appYaml = await readFile ( `${ appDir } /app.yaml` , "utf-8" ) ;
311+
312+ // Inline script references should use non-dotted naming
313+ expect ( appYaml ) . not . toContain ( ".inline_script." ) ;
314+ // Verify no dotted inline script files were created
315+ const { readdir : readdirAsync } = await import ( "node:fs/promises" ) ;
316+ const files = await readdirAsync ( appDir ) ;
317+ const dottedFiles = files . filter ( ( f : string ) => f . includes ( ".inline_script." ) ) ;
318+ expect ( dottedFiles . length ) . toEqual ( 0 ) ;
319+ } ) ;
320+ } ) ;
321+
159322 test ( "--schema-only only processes scripts (skips flows and apps)" , async ( ) => {
160323 await withTestBackend ( async ( backend , tempDir ) => {
161324 await setupWorkspace ( backend , tempDir , "schema_only_test" ) ;
0 commit comments