diff --git a/packages/kanel/src/hooks/generateIndexFile.ts b/packages/kanel/src/hooks/generateIndexFile.ts index 2cc54df3..8d926c23 100644 --- a/packages/kanel/src/hooks/generateIndexFile.ts +++ b/packages/kanel/src/hooks/generateIndexFile.ts @@ -25,6 +25,11 @@ type ExportsItem = { exportAsType: boolean; }; +type SchemaExports = { + items: Record; + path: string; +}; + function stringifyExportItem(item: ExportsItem): string { const prefix = item.exportAsType ? "type " : ""; return `${prefix}${item.wasExportedAs === "default" ? "default as " : ""}${ @@ -32,12 +37,37 @@ function stringifyExportItem(item: ExportsItem): string { }`; } +function getSchemaFromPath(path: string, outputPath: string): string { + const relpath = relative(outputPath, path); + const relparts = relpath.split("/"); + + // Make sure path is part of a schema path + if (relparts.length === 2) { + return relparts[0]; + } + + return null; +} + export const makeGenerateIndexFile: ( config: GenerateIndexFileConfig, ) => PreRenderHook = (config) => (outputAcc, instantiatedConfig) => { const allExports: Record = {}; + const schemaExports: Record = {}; + const { outputPath } = instantiatedConfig; for (const path of Object.keys(outputAcc)) { + const schema = getSchemaFromPath(path, outputPath); + + if (schema && !schemaExports[schema]) { + schemaExports[schema] = { + path: join(outputPath, schema), + items: { [path]: [] }, + }; + } else if (schema) { + schemaExports[schema].items[path] = []; + } + const file = outputAcc[path]; allExports[path] = []; for (const declaration of file.declarations) { @@ -50,23 +80,76 @@ export const makeGenerateIndexFile: ( } const { name, exportAs, declarationType } = declaration; - allExports[path].push({ + const declarationItem = { name, wasExportedAs: exportAs, exportAsType: ["typeDeclaration", "interface"].includes( declarationType, ), - }); + }; + + // Add to the global index + allExports[path].push(declarationItem); + + // Add to the schema index + if (schema) { + schemaExports[schema].items[path].push(declarationItem); + } } } + const schemaIndexFiles: Record = {}; + for (const schema of Object.keys(schemaExports)) { + const schemaPath = schemaExports[schema].path; + const schemaLines = Object.keys(schemaExports[schema].items).map( + (itemPath) => { + const schemaDeclExports = schemaExports[schema].items[itemPath]; + if (schemaDeclExports.length === 0) { + return ""; + } + + let relativePath = relative(schemaPath, itemPath); + // Fix Windows-style paths in import line + if (sep === "\\") { + relativePath = relativePath.replaceAll("\\", "/"); + } + + const line = `export { ${schemaDeclExports + .map(stringifyExportItem) + .join(", ")} } from './${relativePath}';`; + + return line; + }, + ); + + const schemaIndexFile: FileContents = { + declarations: [ + { + declarationType: "generic", + lines: schemaLines, + }, + ], + }; + + const schemaIndexPath = join(schemaPath, "index"); + schemaIndexFiles[schemaIndexPath] = schemaIndexFile; + } + + // Return now if using schema-indexes to avoid a conflicting global index + if (Object.values(schemaIndexFiles).length > 0) { + return { + ...outputAcc, + ...schemaIndexFiles, + }; + } + const lines = Object.keys(allExports).map((path) => { const exports = allExports[path]; if (exports.length === 0) { return ""; } - let relativePath = relative(instantiatedConfig.outputPath, path); + let relativePath = relative(outputPath, path); // Fix Windows-style paths in import line if (sep === "\\") { relativePath = relativePath.replaceAll("\\", "/"); @@ -88,7 +171,7 @@ export const makeGenerateIndexFile: ( ], }; - const path = join(instantiatedConfig.outputPath, "index"); + const path = join(outputPath, "index"); return { ...outputAcc,