11import path from "node:path" ;
22import { existsSync } from "node:fs" ;
3- import { readFile , readdir , writeFile } from "node:fs/promises" ;
3+ import { mkdir , readFile , readdir , writeFile } from "node:fs/promises" ;
44import { fileURLToPath } from "node:url" ;
5+ import { parse } from "jsonc-parser" ;
56
67const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
78
@@ -123,6 +124,10 @@ export default function (
123124 name : "Create a new shared library" ,
124125 value : "shared" ,
125126 } ,
127+ {
128+ name : "Setup VSCode testing settings" ,
129+ value : "vscode-testing" ,
130+ } ,
126131 ] ,
127132 } ,
128133 {
@@ -387,6 +392,8 @@ export default function (
387392 templateFiles : "templates/shared" ,
388393 } ,
389394 ] ;
395+ } else if ( data . type === "vscode-testing" ) {
396+ return [ initVscodeTesting ] ;
390397 }
391398 return [ ] ;
392399 } ,
@@ -396,3 +403,125 @@ export default function (
396403function getObjectPartialInPackageJson ( object ) {
397404 return JSON . stringify ( object , null , 4 ) . replace ( / \} \s * $ / , " }" ) ;
398405}
406+
407+ async function initVscodeTesting ( ) {
408+ const folders = await getWorkspaceFolders ( ) ;
409+ if ( folders . length === 0 ) {
410+ return "No workspace folders found, are you sure this is a monorepo?" ;
411+ }
412+
413+ const vscodeDir = path . join ( rootDir , ".vscode" ) ;
414+ if ( ! existsSync ( vscodeDir ) ) {
415+ await mkdir ( vscodeDir ) ;
416+ }
417+
418+ const settingsJson = path . join ( vscodeDir , "settings.json" ) ;
419+ let settings = { } ;
420+ if ( existsSync ( settingsJson ) ) {
421+ // settings = JSON.parse(await readFile(settingsJson, "utf-8"));
422+ const errors = [ ] ;
423+ settings = parse ( await readFile ( settingsJson , "utf-8" ) , errors , {
424+ allowTrailingComma : true ,
425+ } ) ;
426+ if ( errors . length > 0 ) {
427+ return `Failed to parse existing .vscode/settings.json: ${ errors
428+ . map ( ( e ) => `at offset ${ e . offset } (${ e . error } )` )
429+ . join ( ", " ) } `;
430+ }
431+ }
432+ Object . assign ( settings , {
433+ "jest.runMode" : "on-demand" ,
434+ "jest.jestCommandLine" : "npx test-next" ,
435+ "jest.useJest30" : true ,
436+ "jest.nodeEnv" : {
437+ NODE_ENV : "test" ,
438+ } ,
439+ "jest.virtualFolders" : folders . map ( ( folder ) => ( {
440+ name : folder ,
441+ rootPath : folder ,
442+ } ) ) ,
443+ } ) ;
444+ await writeFile ( settingsJson , JSON . stringify ( settings , null , 2 ) + "\n" ) ;
445+
446+ const launchJson = path . join ( vscodeDir , "launch.json" ) ;
447+ let launchConfig = { } ;
448+ if ( existsSync ( launchJson ) ) {
449+ const errors = [ ] ;
450+ launchConfig = parse ( await readFile ( launchJson , "utf-8" ) , errors , {
451+ allowTrailingComma : true ,
452+ } ) ;
453+ if ( errors . length > 0 ) {
454+ return `Failed to parse existing .vscode/launch.json: ${ errors
455+ . map ( ( e ) => `at offset ${ e . offset } (${ e . error } )` )
456+ . join ( ", " ) } `;
457+ }
458+ }
459+ const configs = folders . map ( ( folder ) => ( {
460+ type : "node" ,
461+ name : `vscode-jest-tests.v2.${ folder } ` ,
462+ request : "launch" ,
463+ args : [
464+ "--runInBand" ,
465+ "--watchAll=false" ,
466+ "--testNamePattern" ,
467+ "${jest.testNamePattern}" ,
468+ "--runTestsByPath" ,
469+ "${jest.testFile}" ,
470+ ] ,
471+ cwd : `${ rootDir } /${ folder } ` ,
472+ console : "integratedTerminal" ,
473+ internalConsoleOptions : "neverOpen" ,
474+ program : `${ rootDir } /node_modules/.bin/test-next` ,
475+ env : {
476+ NODE_ENV : "test" ,
477+ } ,
478+ } ) ) ;
479+ launchConfig . configurations = [
480+ ...( launchConfig . configurations ?. filter (
481+ ( config ) => ! config . name ?. startsWith ( "vscode-jest-tests." )
482+ ) ?? [ ] ) ,
483+ ...configs ,
484+ ] ;
485+ await writeFile ( launchJson , JSON . stringify ( launchConfig , null , 2 ) + "\n" ) ;
486+
487+ return 'Updated VSCode testing settings in ".vscode/settings.json" and ".vscode/launch.json".' ;
488+ }
489+
490+ async function getWorkspaceFolders ( ) {
491+ const { workspaces } = packageJson ;
492+ /** @type {string[] } */
493+ const folders = (
494+ await Promise . all (
495+ workspaces . map ( async ( pattern ) => {
496+ const result = [ ] ;
497+ if ( pattern . endsWith ( "/*" ) ) {
498+ const folder = pattern . slice ( 0 , - 2 ) ;
499+ const dir = path . join ( rootDir , folder ) ;
500+ const dirs = await readdir ( dir , {
501+ withFileTypes : true ,
502+ } ) ;
503+ for ( const d of dirs ) {
504+ const pkgJsonPath = path . join ( dir , d . name , "package.json" ) ;
505+ if ( d . isDirectory ( ) && existsSync ( pkgJsonPath ) ) {
506+ const pkg = JSON . parse ( await readFile ( pkgJsonPath , "utf-8" ) ) ;
507+ if ( pkg . scripts ?. test ) {
508+ result . push ( path . join ( folder , d . name ) ) ;
509+ }
510+ }
511+ }
512+ } else {
513+ const dir = path . join ( rootDir , pattern ) ;
514+ const pkgJsonPath = path . join ( dir , "package.json" ) ;
515+ if ( existsSync ( pkgJsonPath ) ) {
516+ const pkg = JSON . parse ( await readFile ( pkgJsonPath , "utf-8" ) ) ;
517+ if ( pkg . scripts ?. test ) {
518+ result . push ( pattern ) ;
519+ }
520+ }
521+ }
522+ return result ;
523+ } )
524+ )
525+ ) . flat ( ) ;
526+ return folders ;
527+ }
0 commit comments