UNPKG

16.5 kBSource Map (JSON)View Raw
1{"version":3,"file":"AkteApp.cjs","sources":["../../src/AkteApp.ts"],"sourcesContent":["import { dirname, join, resolve } from \"node:path\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\n\nimport { type MatchedRoute, type RadixRouter, createRouter } from \"radix3\";\n\nimport type { AkteFiles } from \"./AkteFiles\";\nimport type { Awaitable, GlobalDataFn } from \"./types\";\nimport { NotFoundError } from \"./errors\";\nimport { runCLI } from \"./runCLI\";\nimport { akteWelcome } from \"./akteWelcome\";\n\nimport { __PRODUCTION__ } from \"./lib/__PRODUCTION__\";\nimport { createDebugger } from \"./lib/createDebugger\";\nimport { pathToRouterPath } from \"./lib/pathToRouterPath\";\nimport { isCLI } from \"./lib/isCLI\";\n\n/* eslint-disable @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports */\n\nimport type { defineAkteFile } from \"./defineAkteFile\";\nimport type { defineAkteFiles } from \"./defineAkteFiles\";\n\n/* eslint-enable @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports */\n\n/** Akte app configuration object. */\nexport type Config<TGlobalData> = {\n\t/**\n\t * Akte files this config is responsible for.\n\t *\n\t * Create them with {@link defineAkteFile} and {@link defineAkteFiles}.\n\t */\n\tfiles: AkteFiles<TGlobalData>[];\n\n\t/** Configuration related to Akte build process. */\n\tbuild?: {\n\t\t/**\n\t\t * Output directory for Akte build command.\n\t\t *\n\t\t * @remarks\n\t\t * This directory is overriden by the Akte Vite plugin when running Akte\n\t\t * through Vite.\n\t\t * @defaultValue `\"dist\"` for Akte build command, `\".akte\"` for Akte Vite plugin.\n\t\t */\n\t\toutDir?: string;\n\t};\n\t// Most global data will eventually be objects we use this\n\t// assumption to make mandatory or not the `globalData` method\n} & (TGlobalData extends Record<string | number | symbol, unknown>\n\t? {\n\t\t\t/**\n\t\t\t * Global data retrieval function.\n\t\t\t *\n\t\t\t * The return value of this function is then shared with each Akte file.\n\t\t\t */\n\t\t\tglobalData: GlobalDataFn<TGlobalData>;\n\t }\n\t: {\n\t\t\t/**\n\t\t\t * Global data retrieval function.\n\t\t\t *\n\t\t\t * The return value of this function is then shared with each Akte file.\n\t\t\t */\n\t\t\tglobalData?: GlobalDataFn<TGlobalData>;\n\t });\n\nconst debug = createDebugger(\"akte:app\");\nconst debugWrite = createDebugger(\"akte:app:write\");\nconst debugRender = createDebugger(\"akte:app:render\");\nconst debugRouter = createDebugger(\"akte:app:router\");\nconst debugCache = createDebugger(\"akte:app:cache\");\n\n/** An Akte app, ready to be interacted with. */\nexport class AkteApp<TGlobalData = unknown> {\n\tprotected config: Config<TGlobalData>;\n\n\t/**\n\t * Readonly array of {@link AkteFiles} registered within the app.\n\t *\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tget files(): AkteFiles<TGlobalData>[] {\n\t\treturn this.config.files;\n\t}\n\n\tconstructor(config: Config<TGlobalData>) {\n\t\tif (!__PRODUCTION__) {\n\t\t\tif (config.files.length === 0 && akteWelcome) {\n\t\t\t\tconfig.files.push(akteWelcome);\n\t\t\t}\n\t\t}\n\n\t\tthis.config = config;\n\n\t\tdebug(\"defined with %o files\", this.config.files.length);\n\n\t\tif (isCLI) {\n\t\t\trunCLI(this as AkteApp);\n\t\t}\n\t}\n\n\t/**\n\t * Looks up the Akte file responsible for rendering the path.\n\t *\n\t * @param path - Path to lookup, e.g. \"/foo\"\n\t * @returns A match featuring the path, the path parameters if any, and the\n\t * Akte file.\n\t * @throws {@link NotFoundError} When no Akte file is found for handling\n\t * looked up path.\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tlookup(path: string): MatchedRoute<{\n\t\tfile: AkteFiles<TGlobalData>;\n\t}> & { path: string } {\n\t\tconst pathWithExtension = pathToRouterPath(path);\n\t\tdebugRouter(\"looking up %o (%o)\", path, pathWithExtension);\n\n\t\tconst maybeMatch = this.getRouter().lookup(pathWithExtension);\n\n\t\tif (!maybeMatch || !maybeMatch.file) {\n\t\t\tdebugRouter(\"not found %o\", path);\n\t\t\tthrow new NotFoundError(path);\n\t\t}\n\n\t\treturn {\n\t\t\t...maybeMatch,\n\t\t\tpath,\n\t\t};\n\t}\n\n\t/**\n\t * Renders a match from {@link lookup}.\n\t *\n\t * @param match - Match to render.\n\t * @returns Rendered file.\n\t * @throws {@link NotFoundError} When the Akte file could not render the match\n\t * (404), with an optional `cause` attached to it for uncaught errors (500)\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tasync render(\n\t\tmatch: MatchedRoute<{\n\t\t\tfile: AkteFiles<TGlobalData>;\n\t\t}> & { path: string; globalData?: TGlobalData; data?: unknown },\n\t): Promise<string> {\n\t\tdebugRender(\"rendering %o...\", match.path);\n\n\t\tconst params: Record<string, string> = match.params || {};\n\t\tconst globalData = match.globalData || (await this.getGlobalData());\n\n\t\ttry {\n\t\t\tconst content = await match.file.render({\n\t\t\t\tpath: match.path,\n\t\t\t\tparams,\n\t\t\t\tglobalData,\n\t\t\t\tdata: match.data,\n\t\t\t});\n\n\t\t\tdebugRender(\"rendered %o\", match.path);\n\n\t\t\treturn content;\n\t\t} catch (error) {\n\t\t\tif (error instanceof NotFoundError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tdebugRender(\"could not render %o\", match.path);\n\n\t\t\tthrow new NotFoundError(match.path, { cause: error });\n\t\t}\n\t}\n\n\t/**\n\t * Renders all Akte files.\n\t *\n\t * @returns Rendered files map.\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tasync renderAll(): Promise<Record<string, string>> {\n\t\tdebugRender(\"rendering all files...\");\n\n\t\tconst globalData = await this.getGlobalData();\n\n\t\tconst renderAll = async (\n\t\t\takteFiles: AkteFiles<TGlobalData>,\n\t\t): Promise<Record<string, string>> => {\n\t\t\ttry {\n\t\t\t\tconst files = await akteFiles.renderAll({ globalData });\n\n\t\t\t\treturn files;\n\t\t\t} catch (error) {\n\t\t\t\tdebug.error(\"Akte → Failed to build %o\\n\", akteFiles.path);\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t};\n\n\t\tconst promises: Promise<Record<string, string>>[] = [];\n\t\tfor (const akteFiles of this.config.files) {\n\t\t\tpromises.push(renderAll(akteFiles));\n\t\t}\n\n\t\tconst rawFilesArray = await Promise.all(promises);\n\n\t\tconst files: Record<string, string> = {};\n\t\tfor (const rawFiles of rawFilesArray) {\n\t\t\tfor (const path in rawFiles) {\n\t\t\t\tif (path in files) {\n\t\t\t\t\tdebug.warn(\n\t\t\t\t\t\t\" Multiple files built %o, only the first one is preserved\",\n\t\t\t\t\t\tpath,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfiles[path] = rawFiles[path];\n\t\t\t}\n\t\t}\n\n\t\tconst rendered = Object.keys(files).length;\n\t\tdebugRender(\n\t\t\t`done, %o ${rendered > 1 ? \"files\" : \"file\"} rendered`,\n\t\t\trendered,\n\t\t);\n\n\t\treturn files;\n\t}\n\n\t/**\n\t * Writes a map of rendered Akte files to the specified `outDir`, or the app\n\t * specified one (defaults to `\"dist\"`).\n\t *\n\t * @param args - A map of rendered Akte files, and an optional `outDir`\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tasync writeAll(args: {\n\t\toutDir?: string;\n\t\tfiles: Record<string, string>;\n\t}): Promise<void> {\n\t\tdebugWrite(\"writing all files...\");\n\t\tconst outDir = args.outDir ?? this.config.build?.outDir ?? \"dist\";\n\t\tconst outDirPath = resolve(outDir);\n\n\t\tconst controller = new AbortController();\n\n\t\tconst write = async (path: string, content: string): Promise<void> => {\n\t\t\tconst filePath = join(outDirPath, path);\n\t\t\tconst fileDir = dirname(filePath);\n\n\t\t\ttry {\n\t\t\t\tawait mkdir(fileDir, { recursive: true });\n\t\t\t\tawait writeFile(filePath, content, {\n\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (controller.signal.aborted) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.abort();\n\n\t\t\t\tdebug.error(\"Akte → Failed to write %o\\n\", path);\n\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tdebugWrite(\"%o\", path);\n\t\t\tdebugWrite.log(\" %o\", path);\n\t\t};\n\n\t\tconst promises: Promise<void>[] = [];\n\t\tfor (const path in args.files) {\n\t\t\tpromises.push(write(path, args.files[path]));\n\t\t}\n\n\t\tawait Promise.all(promises);\n\n\t\tdebugWrite(\n\t\t\t`done, %o ${promises.length > 1 ? \"files\" : \"file\"} written`,\n\t\t\tpromises.length,\n\t\t);\n\t}\n\n\t/**\n\t * Build (renders and write) all Akte files to the specified `outDir`, or the\n\t * app specified one (defaults to `\"dist\"`).\n\t *\n\t * @param args - An optional `outDir`\n\t * @returns Built files array.\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tasync buildAll(args?: { outDir?: string }): Promise<string[]> {\n\t\tconst files = await this.renderAll();\n\t\tawait this.writeAll({ ...args, files });\n\n\t\treturn Object.keys(files);\n\t}\n\n\t/**\n\t * Akte caches all `globalData`, `data`, `bulkData` calls for performance.\n\t * This method can be used to clear the cache.\n\t *\n\t * @param alsoClearFileCache - Also clear cache on all registered Akte files.\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tclearCache(alsoClearFileCache = false): void {\n\t\tdebugCache(\"clearing...\");\n\n\t\tthis._globalDataCache = undefined;\n\t\tthis._router = undefined;\n\n\t\tif (alsoClearFileCache) {\n\t\t\tfor (const file of this.config.files) {\n\t\t\t\tfile.clearCache();\n\t\t\t}\n\t\t}\n\n\t\tdebugCache(\"cleared\");\n\t}\n\n\t/**\n\t * Readonly cache of the app's definition `globalData` method.\n\t *\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tget globalDataCache(): Awaitable<TGlobalData> | undefined {\n\t\treturn this._globalDataCache;\n\t}\n\n\tprivate _globalDataCache: Awaitable<TGlobalData> | undefined;\n\n\t/**\n\t * Retrieves data from the app's definition `globalData` method.\n\t *\n\t * @param context - Context to get global data with.\n\t * @returns Retrieved global data.\n\t * @remark Returned global data may come from cache.\n\t * @experimental Programmatic API might still change not following SemVer.\n\t */\n\tgetGlobalData(): Awaitable<TGlobalData> {\n\t\tif (!this._globalDataCache) {\n\t\t\tdebugCache(\"retrieving global data...\");\n\t\t\tconst globalDataPromise =\n\t\t\t\tthis.config.globalData?.() ?? (undefined as TGlobalData);\n\n\t\t\tif (globalDataPromise instanceof Promise) {\n\t\t\t\tglobalDataPromise.then(() => {\n\t\t\t\t\tdebugCache(\"retrieved global data\");\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tdebugCache(\"retrieved global data\");\n\t\t\t}\n\n\t\t\tthis._globalDataCache = globalDataPromise;\n\t\t} else {\n\t\t\tdebugCache(\"using cached global data\");\n\t\t}\n\n\t\treturn this._globalDataCache;\n\t}\n\n\tprivate _router:\n\t\t| RadixRouter<{\n\t\t\t\tfile: AkteFiles<TGlobalData>;\n\t\t }>\n\t\t| undefined;\n\n\tprotected getRouter(): RadixRouter<{\n\t\tfile: AkteFiles<TGlobalData>;\n\t}> {\n\t\tif (!this._router) {\n\t\t\tdebugCache(\"creating router...\");\n\t\t\tconst router = createRouter<{ file: AkteFiles<TGlobalData> }>();\n\n\t\t\tfor (const file of this.config.files) {\n\t\t\t\tconst path = pathToRouterPath(file.path);\n\t\t\t\trouter.insert(pathToRouterPath(file.path), { file });\n\t\t\t\tdebugRouter(\"registered %o\", path);\n\t\t\t\tif (file.path.endsWith(\"/**\")) {\n\t\t\t\t\tconst catchAllPath = pathToRouterPath(\n\t\t\t\t\t\tfile.path.replace(/\\/\\*\\*$/, \"\"),\n\t\t\t\t\t);\n\t\t\t\t\trouter.insert(catchAllPath, {\n\t\t\t\t\t\tfile,\n\t\t\t\t\t});\n\t\t\t\t\tdebugRouter(\"registered %o\", catchAllPath);\n\t\t\t\t\tdebugCache(pathToRouterPath(file.path.replace(/\\/\\*\\*$/, \"\")));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._router = router;\n\t\t\tdebugCache(\"created router\");\n\t\t} else {\n\t\t\tdebugCache(\"using cached router\");\n\t\t}\n\n\t\treturn this._router;\n\t}\n}\n"],"names":["createDebugger","__PRODUCTION__","akteWelcome","isCLI","runCLI","path","pathToRouterPath","NotFoundError","files","resolve","join","dirname","mkdir","writeFile","createRouter"],"mappings":"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"}
\No newline at end of file