33 mkdirSync ,
44 readFileSync ,
55 readdirSync ,
6+ rmSync ,
67 writeFileSync ,
78} from 'node:fs'
89import { dirname , extname , join , relative , resolve } from 'node:path'
@@ -11,6 +12,7 @@ import { fileURLToPath } from 'node:url'
1112const packageDir = resolve ( dirname ( fileURLToPath ( import . meta. url ) ) , '..' )
1213const frameworksDir = resolve ( packageDir , 'src/frameworks' )
1314const outputFile = resolve ( packageDir , 'src/generated/create-manifest.ts' )
15+ const workerOutputDir = resolve ( packageDir , 'src/generated/worker' )
1416
1517const binaryExtensions = new Set ( [ '.png' , '.jpg' , '.jpeg' , '.gif' , '.svg' , '.ico' ] )
1618const templateRenderers = new Map ( )
@@ -250,8 +252,8 @@ function compileTemplate(template) {
250252 return lines . join ( '\n' )
251253}
252254
253- function createTemplateRendererSource ( ) {
254- const entries = Array . from ( templateRenderers . entries ( ) ) . sort ( ( [ a ] , [ b ] ) =>
255+ function createTemplateRendererSource ( renderers = templateRenderers ) {
256+ const entries = Array . from ( renderers . entries ( ) ) . sort ( ( [ a ] , [ b ] ) =>
255257 a . localeCompare ( b ) ,
256258 )
257259
@@ -331,7 +333,7 @@ type TemplateRenderContext = {
331333 getPackageManagerExecuteScript: (...args: Array<any>) => string
332334 relativePath: (...args: Array<any>) => string
333335 integrationImportContent: (...args: Array<any>) => string
334- integrationImportCode: (...args: Array<any>) => string
336+ integrationImportCode: (...args: Array<any>) => string | undefined
335337 renderTemplate: (content: string) => string
336338 ignoreFile: () => never
337339}
@@ -376,6 +378,10 @@ const templateRenderers: Record<string, TemplateRenderer> = {
376378${ mapEntries }
377379}
378380
381+ export function hasManifestTemplate(template: string) {
382+ return getManifestTemplateKey(template) in templateRenderers
383+ }
384+
379385export function renderManifestTemplate(
380386 template: string,
381387 context: TemplateRenderContext,
@@ -390,6 +396,162 @@ export function renderManifestTemplate(
390396`
391397}
392398
399+ function createTemplateRenderersForFrameworkBase ( framework ) {
400+ const renderers = new Map ( )
401+
402+ for ( const [ file , contents ] of Object . entries ( framework . base ) ) {
403+ if ( file . endsWith ( '.ejs' ) ) {
404+ renderers . set ( getTemplateKey ( contents ) , compileTemplate ( contents ) )
405+ }
406+ }
407+
408+ return renderers
409+ }
410+
411+ function createTemplateRenderersForAddOn ( addOn ) {
412+ const renderers = new Map ( )
413+
414+ for ( const [ file , contents ] of Object . entries ( addOn . files ) ) {
415+ if ( file . endsWith ( '.ejs' ) ) {
416+ renderers . set ( getTemplateKey ( contents ) , compileTemplate ( contents ) )
417+ }
418+ }
419+
420+ if ( addOn . packageTemplate ) {
421+ renderers . set (
422+ getTemplateKey ( addOn . packageTemplate ) ,
423+ compileTemplate ( addOn . packageTemplate ) ,
424+ )
425+ }
426+
427+ if ( addOn . readmeIsEjs && addOn . readme ) {
428+ renderers . set ( getTemplateKey ( addOn . readme ) , compileTemplate ( addOn . readme ) )
429+ }
430+
431+ return renderers
432+ }
433+
434+ function stripAddOnForCatalog ( addOn ) {
435+ const {
436+ files : _files ,
437+ deletedFiles : _deletedFiles ,
438+ packageTemplate : _packageTemplate ,
439+ readme : _readme ,
440+ readmeIsEjs : _readmeIsEjs ,
441+ ...metadata
442+ } = addOn
443+
444+ return metadata
445+ }
446+
447+ function stripFrameworkForCatalog ( framework ) {
448+ const { base : _base , addOns, ...metadata } = framework
449+
450+ return {
451+ ...metadata ,
452+ addOns : addOns . map ( stripAddOnForCatalog ) ,
453+ }
454+ }
455+
456+ function toModuleSegment ( value ) {
457+ return value . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 _ - ] + / g, '-' )
458+ }
459+
460+ function writeGeneratedModule ( file , source ) {
461+ mkdirSync ( dirname ( file ) , { recursive : true } )
462+ writeFileSync (
463+ file ,
464+ `// Generated by scripts/generate-manifest.mjs. Do not edit by hand.\n${ source } ` ,
465+ )
466+ }
467+
468+ function writeWorkerManifest ( manifest ) {
469+ rmSync ( workerOutputDir , { recursive : true , force : true } )
470+
471+ writeGeneratedModule (
472+ join ( workerOutputDir , 'catalog.ts' ) ,
473+ `export const manifestCatalog = ${ JSON . stringify (
474+ {
475+ frameworks : manifest . map ( stripFrameworkForCatalog ) ,
476+ } ,
477+ null ,
478+ 2 ,
479+ ) } \n`,
480+ )
481+
482+ const frameworkLoaders = [ ]
483+ const addOnLoaders = [ ]
484+
485+ for ( const framework of manifest ) {
486+ const frameworkSegment = toModuleSegment ( framework . id )
487+ const frameworkModule = `./frameworks/${ frameworkSegment } .js`
488+ frameworkLoaders . push ( [ framework . id , frameworkModule ] )
489+
490+ writeGeneratedModule (
491+ join ( workerOutputDir , 'frameworks' , `${ frameworkSegment } .ts` ) ,
492+ `${ createTemplateRendererSource (
493+ createTemplateRenderersForFrameworkBase ( framework ) ,
494+ ) } \n\nexport const framework = ${ JSON . stringify (
495+ {
496+ id : framework . id ,
497+ base : framework . base ,
498+ } ,
499+ null ,
500+ 2 ,
501+ ) } \n`,
502+ )
503+
504+ for ( const addOn of framework . addOns ) {
505+ const addOnSegment = toModuleSegment ( addOn . id )
506+ const addOnModule = `./frameworks/${ frameworkSegment } /add-ons/${ addOnSegment } .js`
507+ addOnLoaders . push ( [ framework . id , addOn . id , addOnModule ] )
508+
509+ writeGeneratedModule (
510+ join (
511+ workerOutputDir ,
512+ 'frameworks' ,
513+ frameworkSegment ,
514+ 'add-ons' ,
515+ `${ addOnSegment } .ts` ,
516+ ) ,
517+ `${ createTemplateRendererSource (
518+ createTemplateRenderersForAddOn ( addOn ) ,
519+ ) } \n\nexport const addOn = ${ JSON . stringify ( addOn , null , 2 ) } \n`,
520+ )
521+ }
522+ }
523+
524+ const frameworkLoaderSource = frameworkLoaders
525+ . map (
526+ ( [ frameworkId , modulePath ] ) =>
527+ ` ${ JSON . stringify ( frameworkId ) } : () => import(${ JSON . stringify (
528+ modulePath ,
529+ ) } ),`,
530+ )
531+ . join ( '\n' )
532+
533+ const addOnLoaderGroups = manifest
534+ . map ( ( framework ) => {
535+ const entries = addOnLoaders
536+ . filter ( ( [ frameworkId ] ) => frameworkId === framework . id )
537+ . map (
538+ ( [ , addOnId , modulePath ] ) =>
539+ ` ${ JSON . stringify ( addOnId ) } : () => import(${ JSON . stringify (
540+ modulePath ,
541+ ) } ),`,
542+ )
543+ . join ( '\n' )
544+
545+ return ` ${ JSON . stringify ( framework . id ) } : {\n${ entries } \n },`
546+ } )
547+ . join ( '\n' )
548+
549+ writeGeneratedModule (
550+ join ( workerOutputDir , 'bundled-loader.ts' ) ,
551+ `const frameworkLoaders = {\n${ frameworkLoaderSource } \n}\n\nconst addOnLoaders = {\n${ addOnLoaderGroups } \n}\n\nexport function createBundledWorkerManifestLoader() {\n return {\n async loadCatalog() {\n const module = await import('./catalog.js')\n return module.manifestCatalog\n },\n async loadFramework(frameworkId: string) {\n const load = frameworkLoaders[frameworkId as keyof typeof frameworkLoaders]\n if (!load) {\n throw new Error(\`Framework \${frameworkId} not found in bundled worker manifest\`)\n }\n const module = await load()\n return {\n ...module.framework,\n renderManifestTemplate: module.renderManifestTemplate,\n hasManifestTemplate: module.hasManifestTemplate,\n }\n },\n async loadAddOn(frameworkId: string, addOnId: string) {\n const frameworkAddOnLoaders = addOnLoaders[frameworkId as keyof typeof addOnLoaders]\n const load = frameworkAddOnLoaders?.[addOnId as keyof typeof frameworkAddOnLoaders]\n if (!load) {\n throw new Error(\`Add-on \${addOnId} not found in bundled worker manifest for framework \${frameworkId}\`)\n }\n const module = await load()\n return {\n ...module.addOn,\n renderManifestTemplate: module.renderManifestTemplate,\n hasManifestTemplate: module.hasManifestTemplate,\n }\n },\n }\n}\n` ,
552+ )
553+ }
554+
393555const manifest = [ createFramework ( 'react' ) , createFramework ( 'solid' ) ]
394556
395557mkdirSync ( dirname ( outputFile ) , { recursive : true } )
@@ -405,3 +567,5 @@ writeFileSync(
405567 2 ,
406568 ) } \n`,
407569)
570+
571+ writeWorkerManifest ( manifest )
0 commit comments