@pakk/core
Version:
The core library of pakk, that can manage your package.json for library development.
1 lines • 110 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/internal/defaults.const.ts","../src/package-json/package-json-kind.enum.ts","../src/package-json/package-json-export-target.enum.ts","../src/package-json/package-json-npm-hooks.const.ts","../src/plugins/export/helpers/strip-file-extension.function.ts","../src/plugins/export/helpers/create-export-map-from-paths.function.ts","../src/plugins/export/helpers/enter-path.function.ts","../src/plugins/bin/auto-bin.class.options.ts","../src/plugins/bin/helpers/normalize-package-name.function.ts","../src/plugins/bin/auto-bin.class.ts","../src/plugins/copy-license/auto-copy-license.class.ts","../src/plugins/directive/auto-directive.class.ts","../src/plugins/export/auto-export.class.options.ts","../src/plugins/export-static/auto-export-static.class.options.ts","../src/plugins/export-static/auto-export-static.class.ts","../src/plugins/export/auto-export.class.ts","../src/plugins/export/helpers/bundle-file-name.function.ts","../src/plugins/metadata/auto-metadata.class.options.ts","../src/plugins/metadata/auto-metadata.class.ts","../src/plugins/peer/auto-peer.class.ts","../src/plugins/remove-workspace-directive/auto-remove-workspace-directive.class.ts","../src/plugins/sort-package-json/auto-sort-package-json.class.options.ts","../src/plugins/sort-package-json/auto-sort-package-json.class.ts","../src/internal/find-current-and-root-workspace-package.function.ts","../src/internal/pakk.class.options.ts","../src/internal/pakk.class.ts"],"sourcesContent":["import type { InternalModuleFormat } from 'rollup';\nimport type { LibraryFormats } from 'vite';\n\n/**\n * Where a bundler will place the built artifact, it is assumed that the\n * distributed packageJson file will be directly in this directory.\n */\nexport const DEFAULT_OUT_DIR = 'dist';\n\n/**\n * Where the source files are located in within a package\n */\nexport const DEFAULT_SRC_DIR = 'src';\n/**\n * Where bin entry points are located within the SRC directory\n */\nexport const DEFAULT_BIN_DIR = 'bin';\n/**\n * By default every valid entry is a bin in the bin directory\n */\nexport const DEFAULT_BIN_GLOB = '*';\n/**\n * Where to place automatic shims for bins, this is relative to the package\n * directory and should be outside of SRC as these files are excluded from\n * lints/typechecks etc.\n *\n * Their only purpose is to help package managers while developing a package.\n */\nexport const DEFAULT_BINSHIM_DIR = 'shims';\n\n/**\n * Which directory relative to SRC + EXPORT_BASEDIR should be treated where all files are\n * treated as the interface for your package. In this folder the index.ts/js\n * files are treated specially as your main entry points.\n *\n * By default everything is exported that is directly in this directory except\n * directories.\n */\nexport const DEFAULT_PACKAGE_EXPORTS = '*';\n\n/**\n * What directory should be considered the 'root' of the package. The 'index'\n * file in this directory will be treated as the main export of the package.\n *\n * By default this is '.' to leave src/index.ts as the main entry point.\n */\nexport const DEFAULT_PACKAGE_EXPORT_BASEDIR = '.';\n\n/**\n * By default the exports map won't contain test files.\n */\nexport const DEFAULT_PACKAGE_EXPORT_IGNORES = ['*.(spec|test).*'];\n\n/**\n * What files should be just copied over to the DIST directory as is and also\n * export them.\n */\nexport const DEFAULT_STATIC_EXPORT_GLOBS = ['readme.md', 'static/**/*', 'export/**/*'];\n\n/**\n * What formats to expect to be built by default\n */\nexport const DEFAULT_EXPORT_FORMATS: LibraryFormats[] = ['es', 'cjs'];\n\nexport const ALL_ROLLUP_MODULE_FORMATS: readonly InternalModuleFormat[] = [\n\t'es',\n\t'cjs',\n\t'amd',\n\t'umd',\n\t'iife',\n\t'system',\n] as const;\n\nexport const ALL_VITE_LIBRARY_FORMATS: readonly LibraryFormats[] = [\n\t'es',\n\t'cjs',\n\t'umd',\n\t'iife',\n] as const;\n","/**\n * These are the kinds of packageJson files we distinguish. The on you interact\n * with during DEVELOPMENT is the source packageJson file, and will be\n * transformed prior to DISTRIBUTION.\n */\nexport const PACKAGE_JSON_KIND = {\n\t/**\n\t * Used in the repository as the source packageJson\n\t */\n\tDEVELOPMENT: 'development',\n\t/**\n\t * The packageJson that will be in the distributed package\n\t */\n\tDISTRIBUTION: 'distribution',\n} as const;\n\n/**\n * @deprecated use common\n */\nexport type ValuesOf<T> = T[keyof T];\n\nexport type PackageJsonKindType = ValuesOf<typeof PACKAGE_JSON_KIND>;\n\nexport const isPackageJsonKindType = (s: string): s is PackageJsonKindType => {\n\treturn Object.values(PACKAGE_JSON_KIND).includes(s as PackageJsonKindType);\n};\n","/**\n * These are the kinds of paths the entries in a packageJson's exports object\n * can point to.\n *\n * It is only used for the development/source packageJson. The distributed\n * packageJson will only have paths that refer to itself.\n */\nexport enum PackageJsonExportTarget {\n\t/**\n\t * This targets the source files.\n\t *\n\t * For example the `development` packageJson targets the local entry points\n\t * for types\n\t */\n\tSOURCE = 'source',\n\t/**\n\t * This targets the directory where compiled files end up in. Wherever\n\t * `outDir` points to.\n\t *\n\t * For example both the `development` and `distribution` packageJson files\n\t * target this for the actual imports.\n\t */\n\tDIST = 'dist',\n\t/**\n\t * The shim folder is used for local bins\n\t *\n\t * For example the `development` packageJson files bin entries target the\n\t * shim directory. So pnpm can link them event before the package is built.\n\t */\n\tSHIM = 'shim',\n}\n\nexport type PathMap<T extends string> = Record<string, Record<T, string>>;\n","/**\n * The hooks pnpm too will use.\n */\nexport const NPM_INSTALL_HOOKS = [\n\t'preinstall',\n\t'install',\n\t'postinstall',\n\t'prepublish',\n\t'preprepare',\n\t'prepare',\n\t'postprepare',\n];\n\n/**\n * From https://docs.npmjs.com/cli/v8/using-npm/scripts\n * And anything that start pre- and post- that also matches a user defined\n * script (prebuild and postbuild works if 'build' exists)\n */\nexport const ALL_NPM_HOOKS = [\n\t...NPM_INSTALL_HOOKS,\n\t'prepare',\n\t'prepack',\n\t'postpack',\n\t'prepublishOnly',\n\t'publish',\n\t'postpublish',\n\t'prerestart',\n\t'restart',\n\t'postrestart',\n];\n","import p from 'node:path';\n\nconst dtsExtension = '.d.ts';\n\n/**\n * Removes extensions from filenames. Which is usually whatever `extname`\n * returns (everything after the last `.`) but in the case of `.d.ts` files,\n * it will strip `.d.ts` by default, unless turned off.\n */\nexport const stripFileExtension = (name: string, options?: { stripDts: boolean }): string => {\n\tconst extension =\n\t\tname.endsWith(dtsExtension) && options?.stripDts !== false ? dtsExtension : p.extname(name);\n\treturn name.replace(new RegExp(`${extension}$`), '');\n};\n","import type { Defined } from '@alexaegis/common';\nimport p from 'node:path';\nimport type { AllBinPathCombinations } from '../../bin/auto-bin.class.js';\nimport type { AllExportPathCombinations } from '../auto-export.class.js';\nimport type { EntryPathVariantMap, PathVariantMap } from '../export-map.type.js';\nimport { stripFileExtension } from './strip-file-extension.function.js';\n\nexport interface CreateExportMapFromPathsOptions {\n\t/**\n\t * Where the paths were searched from, can be extended further using\n\t * the basepath.\n\t */\n\tsrcDir: string;\n\n\t/**\n\t * Where the bundler will place the resulting files\n\t */\n\toutDir: string;\n\n\t/**\n\t * The directory where shims for the bins are placed\n\t */\n\tshimDir?: string;\n\n\t/**\n\t * A path every other path was search from, so in the result they will\n\t * be prefixed with this\n\t *\n\t * @defaultValue '.'\n\t */\n\tbasePath?: string;\n\n\t/**\n\t * What kind of keys shall the resulting object contain?\n\t * - If set to 'extensionless-relative-path-from-base' then the keys will\n\t * equal to the input paths minus the extension\n\t * - If set to 'extensionless-filename-only' then the keys will be set to\n\t * the filename only.\n\t */\n\tkeyKind: 'extensionless-relative-path-from-base' | 'extensionless-filename-only';\n}\n\nexport type NormalizedCreateExportMapFromPathsOptions = Defined<CreateExportMapFromPathsOptions>;\n\n/**\n * The resulting paths still contain their original extensions.\n */\nexport const createExportMapFromPaths = <\n\tVariants extends AllExportPathCombinations | AllBinPathCombinations =\n\t\t| AllExportPathCombinations\n\t\t| AllBinPathCombinations,\n>(\n\tpathsFromBase: string[],\n\toptions: CreateExportMapFromPathsOptions,\n): EntryPathVariantMap<Variants> => {\n\tconst basePath = options.basePath ?? '.';\n\tconst exportMap: EntryPathVariantMap<Variants> = {};\n\n\tfor (const path of pathsFromBase) {\n\t\tconst key =\n\t\t\toptions.keyKind === 'extensionless-filename-only'\n\t\t\t\t? stripFileExtension(p.basename(path))\n\t\t\t\t: './' + stripFileExtension(path);\n\n\t\tconst pathVariants: Record<string, string> = {\n\t\t\t'development-to-source': './' + p.posix.join(options.srcDir, basePath, path), // The original full path, not used by default but there's an option if preferred\n\t\t\t'development-to-dist': './' + p.posix.join(options.outDir, path), // It is assumed that files in the outDir replicate their folder structure from the srcDir\n\t\t\t'distribution-to-dist': './' + path,\n\t\t};\n\n\t\tif (options.shimDir) {\n\t\t\tpathVariants['development-to-shim'] = './' + p.join(options.shimDir, path);\n\t\t}\n\n\t\texportMap[key] = pathVariants as PathVariantMap<Variants>;\n\t}\n\n\treturn exportMap;\n};\n","import p from 'node:path';\n\n/**\n * Moves one directory in into a path. It strips one directory off from\n * the beginning. if it started with a `./` it keeps it and strips the next\n * section off.\n *\n * @example 'foo/bar/file' => 'bar/file'\n */\nexport const enterPathPosix = (path: string, enterCount = 1): string => {\n\tconst explodedPath = p.posix.normalize(path).split(p.posix.sep);\n\tconst directoryCount = explodedPath.length - 1;\n\texplodedPath.splice(0, Math.min(enterCount, directoryCount));\n\tconst prefix = path.startsWith('./') ? './' : '';\n\treturn prefix + p.posix.join(...explodedPath);\n};\n","import type { Defined } from '@alexaegis/common';\nimport {\n\tDEFAULT_BINSHIM_DIR,\n\tDEFAULT_BIN_DIR,\n\tDEFAULT_BIN_GLOB,\n\tDEFAULT_PACKAGE_EXPORT_IGNORES,\n} from '../../internal/defaults.const.js';\nimport { ALL_NPM_HOOKS } from '../../package-json/package-json-npm-hooks.const.js';\n\nexport interface AutoBinOptions {\n\t/**\n\t * ### AutoBin\n\t *\n\t * The files to treat as bins elative from the `srcDir + binBaseDir`\n\t * directory.\n\t * It's usually `*` meaning all files directly here are considered the\n\t * entry points of the library.\n\t *\n\t * @defaultValue '*'\n\t */\n\tbins?: string | string[] | undefined;\n\n\t/**\n\t * ### AutoBin\n\t *\n\t * What paths to ignore when collecting bins in addition to\n\t * `defaultBinIgnore` so you're not dropping the defaults when you just\n\t * want to add additional ignore entries.\n\t *\n\t * @defaultValue []\n\t */\n\tbinIgnore?: string[] | undefined;\n\n\t/**\n\t * ### AutoBin\n\t *\n\t * By default test files are excluded\n\t *\n\t * @defaultValue ['*.(spec|test).*']\n\t */\n\tdefaultBinIgnore?: string[] | undefined;\n\n\t/**\n\t * ### AutoBin\n\t *\n\t * Relative path from `srcDir` if you want your exports to start from a\n\t * different directory.\n\t *\n\t * @defaultValue 'bin'\n\t */\n\tbinBaseDir?: string | undefined;\n\n\t/**\n\t * ### AutoBin\n\t *\n\t * If a bin's name matches with an entry here (which is by default every\n\t * NPM hook, 'postinstall' 'prebuild' etc.) then it will be automatically\n\t * added to your packageJson file's scripts. To not interfere with\n\t * development, hooks invoked during install are disabled for the source\n\t * packageJson and are only avilable in the distributed packageJson.\n\t *\n\t * @defaultValue ALL_NPM_HOOKS\n\t */\n\tenabledNpmHooks?: string[] | undefined;\n\n\t/**\n\t * ### AutoBin\n\t *\n\t * A directory where shims for the built bins would be placed\n\t * All these scripts do is to import the yet-to-be-built binary so\n\t * package managers hava something to symlink to before it's built.\n\t *\n\t * ! This folder has to be ignored by typescript as it contains broken\n\t * ! imports before the package is built\n\t *\n\t * @defaultValue 'shims'\n\t */\n\tshimDir?: string | undefined;\n}\n\nexport type NormalizedAutoBinOptions = Defined<AutoBinOptions>;\n\nexport const normalizeAutoBinOptions = (options?: AutoBinOptions): NormalizedAutoBinOptions => {\n\treturn {\n\t\tbinBaseDir: options?.binBaseDir ?? DEFAULT_BIN_DIR,\n\t\tbins: options?.bins ?? DEFAULT_BIN_GLOB,\n\t\tshimDir: options?.shimDir ?? DEFAULT_BINSHIM_DIR,\n\t\tdefaultBinIgnore: options?.defaultBinIgnore ?? DEFAULT_PACKAGE_EXPORT_IGNORES,\n\t\tbinIgnore: options?.binIgnore ?? [],\n\t\tenabledNpmHooks: options?.enabledNpmHooks ?? ALL_NPM_HOOKS,\n\t};\n};\n","/**\n * Takes out the @ in front of a packageName and replaces / with a -\n */\nexport const normalizePackageName = (packageName: string | undefined): string => {\n\treturn packageName?.replace(/^@/, '').replace('/', '-') ?? '';\n};\n","import { getPrettierFormatter, toAbsolute, turnIntoExecutable } from '@alexaegis/fs';\nimport {\n\tgetPackageJsonTemplateVariables,\n\ttype PackageJson,\n\ttype WorkspacePackage,\n} from '@alexaegis/workspace-tools';\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rename, rm, symlink, writeFile } from 'node:fs/promises';\nimport posix, { basename, dirname, join, relative } from 'node:path/posix';\nimport type { InternalModuleFormat } from 'rollup';\n\nimport type { SimpleObjectKey } from '@alexaegis/common';\nimport { globby } from 'globby';\nimport type { NormalizedPakkContext, ViteFileNameFn } from '../../index.js';\nimport {\n\tNPM_INSTALL_HOOKS,\n\tPACKAGE_JSON_KIND,\n\tPackageJsonExportTarget,\n\ttype PathMap,\n} from '../../package-json/index.js';\nimport { createExportMapFromPaths } from '../export/helpers/create-export-map-from-paths.function.js';\nimport { enterPathPosix } from '../export/helpers/enter-path.function.js';\nimport { stripFileExtension } from '../export/helpers/strip-file-extension.function.js';\nimport type { PackageExportPathContext } from '../export/package-export-path-context.interface.js';\nimport type { PackageExaminationResult, PakkFeature } from '../pakk-feature.type.js';\nimport {\n\tnormalizeAutoBinOptions,\n\ttype AutoBinOptions,\n\ttype NormalizedAutoBinOptions,\n} from './auto-bin.class.options.js';\nimport { normalizePackageName } from './helpers/normalize-package-name.function.js';\n\n/**\n * TODO: use the one in core\n */\nconst mapObject = <T extends Record<SimpleObjectKey, unknown>, K>(\n\to: T,\n\tmap: (value: T[keyof T], key: keyof T) => K,\n): Record<keyof T, K> => {\n\treturn Object.fromEntries(\n\t\tObject.entries(o).map(([key, value]) => {\n\t\t\treturn [key, map(value as T[keyof T], key)];\n\t\t}),\n\t) as Record<keyof T, K>;\n};\n\nexport const allBinPathCombinations = [\n\t`${PACKAGE_JSON_KIND.DEVELOPMENT}-to-${PackageJsonExportTarget.SOURCE}`,\n\t`${PACKAGE_JSON_KIND.DEVELOPMENT}-to-${PackageJsonExportTarget.DIST}`,\n\t`${PACKAGE_JSON_KIND.DISTRIBUTION}-to-${PackageJsonExportTarget.DIST}`,\n\t`${PACKAGE_JSON_KIND.DEVELOPMENT}-to-${PackageJsonExportTarget.SHIM}`,\n] as const;\n\nexport const mapPathMapToFormat = (\n\tbinPaths: PathMap<string>,\n\tformat: InternalModuleFormat | 'SOURCE',\n\tfileNameFn: ViteFileNameFn,\n): BinPathMap => {\n\treturn mapObject(binPaths, (kindsOfPaths, _binName) => {\n\t\treturn mapObject(kindsOfPaths, (path, _pathKind) => {\n\t\t\tconst fileName = basename(path);\n\t\t\tconst extensionlessFileName = stripFileExtension(fileName);\n\t\t\tconst dir = dirname(path);\n\t\t\treturn posix.join(\n\t\t\t\tdir,\n\t\t\t\tformat === 'SOURCE' ? fileName : fileNameFn(format, extensionlessFileName),\n\t\t\t);\n\t\t});\n\t});\n};\n\n/**\n * BinPaths never point into the nothing. Dist points to dist but source only\n * points to a shim generated by AutoBin not to confuse package managers when\n * an unbuilt package is installed locally. The shim will be there for them.\n * The shim will not be usable until the package is built though.\n *\n * TODO: generate shims that can self trigger builds when called and not built\n */\nexport type AllBinPathCombinations = (typeof allBinPathCombinations)[number];\n\nexport type BinPathMap = PathMap<AllBinPathCombinations>;\n\nconst markComment = ' # autogenerated';\n\n/**\n * Generates bin entries from files under `srcDir` + `autoBinDirectory`\n * It also treats all files named as npm hooks as npm hooks, prefixing them\n * and adding them as hooks for the npm artifact\n *\n * For example a file called `postinstall.ts` in a package called\n * `@org/name`, it will generate an npm script entry as such:\n * `\"postinstall\": \"bin/postinstall.js\"`. The hook is still treated as a\n * `bin` so you can invoke it directly. To avoid name collisions, all\n * \"hookbins\" are prefixed with the normalized packagename like so:\n * `org-name-postinstall`\n *\n * For a simpler packageJson, directories.bin could also be used in\n * https://docs.npmjs.com/cli/v9/configuring-npm/package-json#directories\n */\nexport class AutoBin implements PakkFeature {\n\tpublic readonly order = 3;\n\n\tprivate readonly options: NormalizedAutoBinOptions;\n\tprivate readonly context: NormalizedPakkContext;\n\n\tprivate outDirAbs: string;\n\tprivate shimDirAbs: string;\n\tprivate outBinDirAbs: string;\n\n\tprivate binPathMap: BinPathMap = {};\n\tprivate existingManualBinEntries: Record<string, string> = {};\n\n\tconstructor(context: NormalizedPakkContext, options?: AutoBinOptions) {\n\t\tthis.options = normalizeAutoBinOptions(options);\n\t\tthis.context = context;\n\n\t\tthis.outDirAbs = toAbsolute(this.context.outDir, this.context);\n\t\tthis.shimDirAbs = join(this.context.cwd, this.options.shimDir);\n\t\tthis.outBinDirAbs = join(this.outDirAbs, this.options.binBaseDir);\n\t}\n\n\tprivate collectManualBinEntries(workspacePackage: WorkspacePackage): Record<string, string> {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(workspacePackage.packageJson.bin ?? {}).filter(\n\t\t\t\t([, path]) =>\n\t\t\t\t\t!path.startsWith('.' + posix.sep + posix.normalize(this.options.shimDir)) ||\n\t\t\t\t\t!path.endsWith('js') ||\n\t\t\t\t\tpath.includes('manual'),\n\t\t\t),\n\t\t);\n\t}\n\n\tasync examinePackage(\n\t\tworkspacePackage: WorkspacePackage,\n\t): Promise<Partial<PackageExaminationResult>> {\n\t\tthis.existingManualBinEntries = this.collectManualBinEntries(workspacePackage);\n\t\tthis.context.logger.trace('existingManualBinEntries', this.existingManualBinEntries);\n\n\t\tconst absoluteBinBaseDir = toAbsolute(join(this.context.srcDir, this.options.binBaseDir), {\n\t\t\tcwd: workspacePackage.packagePath,\n\t\t});\n\n\t\tconst binFiles = await globby(this.options.bins, {\n\t\t\tcwd: absoluteBinBaseDir,\n\t\t\tignore: [...this.options.binIgnore, ...this.options.defaultBinIgnore],\n\t\t\tonlyFiles: true,\n\t\t\tdot: true,\n\t\t});\n\n\t\tthis.binPathMap = createExportMapFromPaths(binFiles, {\n\t\t\toutDir: this.context.outDir,\n\t\t\tshimDir: this.options.shimDir,\n\t\t\tsrcDir: this.context.srcDir,\n\t\t\tbasePath: this.options.binBaseDir,\n\t\t\tkeyKind: 'extensionless-filename-only',\n\t\t});\n\t\tfor (const binPath of binFiles) {\n\t\t\tconst binName = stripFileExtension(basename(binPath));\n\n\t\t\tthis.binPathMap[binName] = {\n\t\t\t\t'development-to-source': join(\n\t\t\t\t\tthis.context.srcDir,\n\t\t\t\t\tthis.options.binBaseDir,\n\t\t\t\t\tbinPath,\n\t\t\t\t),\n\t\t\t\t'development-to-dist': join(this.context.outDir, this.options.binBaseDir, binPath),\n\t\t\t\t'distribution-to-dist': join(this.options.binBaseDir, binPath),\n\t\t\t\t'development-to-shim': join(this.options.shimDir, binPath),\n\t\t\t};\n\t\t}\n\n\t\tconst packageJsonUpdates: PackageJson = {};\n\n\t\t// Making sure removed bins and scripts will be dropped at the end\n\t\tpackageJsonUpdates.bin = undefined;\n\t\tfor (const script in packageJsonUpdates.scripts) {\n\t\t\tif (packageJsonUpdates.scripts[script]?.endsWith(markComment)) {\n\t\t\t\tpackageJsonUpdates.scripts[script] = undefined;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tpackageJsonUpdates,\n\t\t\tbundlerEntryFiles: binFiles.reduce<Record<string, string>>((acc, binFile) => {\n\t\t\t\tconst path = posix.join(this.context.srcDir, this.options.binBaseDir, binFile);\n\t\t\t\tconst alias = posix.join(this.options.binBaseDir, stripFileExtension(binFile));\n\t\t\t\tacc[alias] = path;\n\t\t\t\treturn acc;\n\t\t\t}, {}),\n\t\t};\n\t}\n\n\t/**\n\t * for module based packages, bins are modules too and the adjust path\n\t * step only acts for the 'es' format\n\t */\n\tasync process(\n\t\tpackageJson: PackageJson,\n\t\tpathContext: PackageExportPathContext,\n\t): Promise<PackageJson | undefined> {\n\t\tif (this.context.primaryFormat === pathContext.format) {\n\t\t\tconst binPathMapForFormat = mapPathMapToFormat(\n\t\t\t\tthis.binPathMap,\n\t\t\t\tthis.context.primaryFormat,\n\t\t\t\tthis.context.fileName,\n\t\t\t);\n\n\t\t\tconst packageName = normalizePackageName(packageJson.name);\n\n\t\t\tawait this.ensureEsmBinEntriesRenamed();\n\n\t\t\tif (pathContext.packageJsonKind === PACKAGE_JSON_KIND.DEVELOPMENT) {\n\t\t\t\tawait this.createShims(\n\t\t\t\t\tObject.values(binPathMapForFormat).map(\n\t\t\t\t\t\t(pathKinds) => pathKinds['development-to-shim'],\n\t\t\t\t\t),\n\t\t\t\t\tthis.context.primaryFormat,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Mark all bins and shims as executable\n\t\t\tawait Promise.allSettled(\n\t\t\t\tObject.values(binPathMapForFormat)\n\t\t\t\t\t.flatMap((pathKinds) => [\n\t\t\t\t\t\tpathKinds['development-to-dist'],\n\t\t\t\t\t\tpathKinds['development-to-shim'],\n\t\t\t\t\t])\n\t\t\t\t\t.filter((executable) => existsSync(executable))\n\t\t\t\t\t.map((executable) =>\n\t\t\t\t\t\tturnIntoExecutable(executable, {\n\t\t\t\t\t\t\tcwd: this.context.cwd,\n\t\t\t\t\t\t\tlogger: this.context.logger,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t);\n\n\t\t\tawait this.preLink(\n\t\t\t\tmapObject(binPathMapForFormat, (pathKinds) => pathKinds['development-to-dist']),\n\t\t\t\tpackageName,\n\t\t\t);\n\n\t\t\tconst update = Object.entries(binPathMapForFormat).reduce<PackageJson>(\n\t\t\t\t(result, [key, value]) => {\n\t\t\t\t\tif (result.scripts && this.options.enabledNpmHooks.includes(key)) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!packageJson.scripts?.[key] ||\n\t\t\t\t\t\t\tpackageJson.scripts[key]?.endsWith(markComment)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tif (pathContext.packageJsonKind === PACKAGE_JSON_KIND.DISTRIBUTION) {\n\t\t\t\t\t\t\t\tresult.scripts[key] = value['distribution-to-dist'] + markComment; // before update\n\t\t\t\t\t\t\t} else if (NPM_INSTALL_HOOKS.includes(key)) {\n\t\t\t\t\t\t\t\t// Disable local postinstall hooks\n\t\t\t\t\t\t\t\tresult.scripts[key] =\n\t\t\t\t\t\t\t\t\t'# local install hooks are disabled' + markComment;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Otherwise just point to the shim\n\t\t\t\t\t\t\t\tresult.scripts[key] = value['development-to-shim'] + markComment; // before update\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Hooks are renamed to avoid conflicts, except for their scripts\n\t\t\t\t\t\tkey = packageName + '-' + key;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (key.endsWith('index')) {\n\t\t\t\t\t\tkey = key.replace('index', '');\n\t\t\t\t\t}\n\n\t\t\t\t\tif (key === '') {\n\t\t\t\t\t\tconst packageJsonName = getPackageJsonTemplateVariables(packageJson);\n\t\t\t\t\t\tkey = packageJsonName.packageNameWithoutOrg;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!result.bin) {\n\t\t\t\t\t\tresult.bin = {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// the distributed build artifacts bins point to the built bins\n\t\t\t\t\t// otherwise, the bins are pointing to their shims\n\t\t\t\t\tresult.bin[key] =\n\t\t\t\t\t\t'.' +\n\t\t\t\t\t\tposix.sep +\n\t\t\t\t\t\t(pathContext.packageJsonKind === PACKAGE_JSON_KIND.DISTRIBUTION\n\t\t\t\t\t\t\t? value['distribution-to-dist']\n\t\t\t\t\t\t\t: value['development-to-shim']);\n\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbin: this.existingManualBinEntries,\n\t\t\t\t\tscripts: {},\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (typeof update.bin === 'object' && Object.keys(update.bin).length === 0) {\n\t\t\t\tdelete update.bin;\n\t\t\t}\n\n\t\t\tif (typeof update.scripts === 'object' && Object.keys(update.scripts).length === 0) {\n\t\t\t\tdelete update.scripts;\n\t\t\t}\n\n\t\t\treturn [{ bin: undefined }, update];\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Ensures shimDir exists and creates simple javascript files that are\n\t * importing their counterpart from `outDir`\n\t */\n\tprivate async createShims(shimPaths: string[], format: InternalModuleFormat): Promise<void> {\n\t\tif (\n\t\t\t(this.context.packageType === 'module' && format === 'es') ||\n\t\t\t(this.context.packageType === 'commonjs' && format !== 'es')\n\t\t) {\n\t\t\tthis.context.logger.info(\n\t\t\t\t`Creating shims for bins in ${format}/${this.context.packageType} format`,\n\t\t\t);\n\t\t\t// Clean up\n\t\t\tawait rm(this.shimDirAbs, { force: true, recursive: true });\n\n\t\t\tconst shimDirToOutBin = relative(this.shimDirAbs, this.outBinDirAbs);\n\t\t\tconst formatJs = await getPrettierFormatter();\n\n\t\t\t// check writable shim files\n\t\t\tconst shimPathsToMake = await Promise.all(\n\t\t\t\tshimPaths.map((path) =>\n\t\t\t\t\treadFile(toAbsolute(path, this.context), {\n\t\t\t\t\t\tencoding: 'utf8',\n\t\t\t\t\t})\n\t\t\t\t\t\t.then((content) =>\n\t\t\t\t\t\t\tcontent.includes('// autogenerated') ? path : undefined,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.catch(() => path),\n\t\t\t\t),\n\t\t\t).then((results) => results.filter((result): result is string => result !== undefined));\n\n\t\t\tif (shimPathsToMake.length > 0) {\n\t\t\t\tthis.context.logger.info(`create shims for ${shimPathsToMake.join('; ')}`);\n\n\t\t\t\tawait Promise.allSettled(\n\t\t\t\t\tshimPathsToMake.map(async (path) => {\n\t\t\t\t\t\tconst outBinPath = enterPathPosix(path, 1);\n\t\t\t\t\t\t//const outBinPath = path;\n\t\t\t\t\t\tconst builtBinFromShims = shimDirToOutBin + posix.sep + outBinPath;\n\t\t\t\t\t\tconst formattedESShimContent = await formatJs(\n\t\t\t\t\t\t\t`// autogenerated-by-pakk\nexport * from '${builtBinFromShims}';\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst formattedCJSShimContent = await formatJs(\n\t\t\t\t\t\t\t`// autogenerated-by-pakk, as seen from tsc\n/* eslint-disable unicorn/prefer-module */\n/* eslint-disable @typescript-eslint/no-var-requires */\n/* eslint-disable no-prototype-builtins */\nvar __createBinding = function(o, m, k, k2) {\n\tif (k2 === undefined) k2 = k;\n\tObject.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n};\n\nvar __exportStar = function(m, exports) {\n\tfor (var p in m) if (p !== 'default' && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);\n};\n\n__exportStar(require('${builtBinFromShims}'), exports);\n`,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst shimPathAbs = join(this.shimDirAbs, outBinPath);\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait mkdir(dirname(shimPathAbs), { recursive: true });\n\t\t\t\t\t\t\tawait writeFile(\n\t\t\t\t\t\t\t\tshimPathAbs,\n\t\t\t\t\t\t\t\tformat === 'es' ? formattedESShimContent : formattedCJSShimContent,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tthis.context.logger.error(\n\t\t\t\t\t\t\t\t\"Couldn't write\",\n\t\t\t\t\t\t\t\tshimPathAbs,\n\t\t\t\t\t\t\t\t'error happened',\n\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Ensures that all .js files in the dist folder are renamed to the\n\t * expected name this plugin added them to the bin entry.\n\t */\n\tprivate async ensureEsmBinEntriesRenamed(): Promise<void> {\n\t\tif (this.context.packageType === 'module') {\n\t\t\tconst esBinPathsMap = mapPathMapToFormat(this.binPathMap, 'es', this.context.fileName);\n\t\t\tconst data = Object.entries(esBinPathsMap).flatMap(([_binName, binPath]) => {\n\t\t\t\tconst extensionlessPath = stripFileExtension(binPath['development-to-dist']);\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tbinPath: extensionlessPath + '.js',\n\t\t\t\t\t\tnewBinPath: binPath['development-to-dist'],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tbinPath: extensionlessPath + '.js.map',\n\t\t\t\t\t\tnewBinPath: binPath['development-to-dist'] + '.map',\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t});\n\n\t\t\tawait Promise.all(\n\t\t\t\tdata\n\t\t\t\t\t.filter(({ binPath }) => existsSync(binPath))\n\t\t\t\t\t.map(({ binPath, newBinPath }) =>\n\t\t\t\t\t\trename(binPath, newBinPath).catch(() => false),\n\t\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\t// TODO: something is funky, there are extensionless files in the distbin dir and they are not executable.\n\t/**\n\t *\n\t */\n\tprivate async preLink(binRecord: Record<string, string>, packageName: string): Promise<void> {\n\t\tconst workspaceBinDirectoryPath = join(\n\t\t\tthis.context.rootWorkspacePackage.packagePath,\n\t\t\t'node_modules',\n\t\t\t'.bin',\n\t\t);\n\n\t\tconst packageBinDirectoryPath = toAbsolute(join('node_modules', '.bin'), this.context);\n\n\t\tconst symlinksToMake = Object.entries(binRecord).flatMap(([binName, binPath]) => {\n\t\t\tif (this.options.enabledNpmHooks.includes(binName)) {\n\t\t\t\tbinName = packageName + '-' + binName;\n\t\t\t}\n\n\t\t\treturn [\n\t\t\t\tjoin(workspaceBinDirectoryPath, binName),\n\t\t\t\tjoin(packageBinDirectoryPath, binName),\n\t\t\t].map((targetFilePath) => {\n\t\t\t\tconst relativeFromTargetBackToFile = relative(dirname(targetFilePath), binPath);\n\t\t\t\treturn { relativeFromTargetBackToFile, targetFilePath };\n\t\t\t});\n\t\t});\n\n\t\tawait Promise.all(\n\t\t\tsymlinksToMake.map(async ({ targetFilePath, relativeFromTargetBackToFile }) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait symlink(relativeFromTargetBackToFile, targetFilePath);\n\t\t\t\t\tthis.context.logger.info(\n\t\t\t\t\t\t`symlinked ${targetFilePath} to ${relativeFromTargetBackToFile}`,\n\t\t\t\t\t);\n\t\t\t\t} catch {\n\t\t\t\t\tthis.context.logger.info(`${targetFilePath} is already present`);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t}\n}\n","import { toAbsolute } from '@alexaegis/fs';\nimport type { PackageJson, WorkspacePackage } from '@alexaegis/workspace-tools';\nimport { existsSync } from 'node:fs';\nimport { cp } from 'node:fs/promises';\nimport p from 'node:path';\nimport { PACKAGE_JSON_KIND, type NormalizedPakkContext } from '../../index.js';\nimport type { PackageExportPathContext } from '../export/package-export-path-context.interface.js';\nimport type { PackageExaminationResult, PakkFeature } from '../pakk-feature.type.js';\n\n/**\n * Automatically copies the license file to the outDir so it can be part\n * of the distributed package. It uses the license file you defined in the\n * root of your project. Or if you wish to override it, place one into\n * the packages folder.\n */\nexport class AutoCopyLicense implements PakkFeature {\n\tpublic readonly order = 4;\n\n\tprivate readonly context: NormalizedPakkContext;\n\n\tprivate licensePath: string | undefined;\n\n\tconstructor(context: NormalizedPakkContext, _options: unknown) {\n\t\tthis.context = context;\n\t}\n\n\texaminePackage(workspacePackage: WorkspacePackage): Partial<PackageExaminationResult> {\n\t\tconst pathsOfInterest = [\n\t\t\tworkspacePackage.packagePath,\n\t\t\tthis.context.rootWorkspacePackage.packagePath,\n\t\t];\n\n\t\tconst possibleLiceseFileNames = ['license', 'LICENSE'];\n\n\t\tconst possibleLicenseFileLocations = pathsOfInterest.flatMap((path) =>\n\t\t\tpossibleLiceseFileNames.map((fileName) => p.join(path, fileName)),\n\t\t);\n\n\t\tthis.licensePath = possibleLicenseFileLocations.find((path) => existsSync(path));\n\n\t\tif (this.licensePath) {\n\t\t\tthis.context.logger.trace('found license file at', this.licensePath);\n\t\t} else {\n\t\t\tthis.context.logger.warn(\n\t\t\t\t'no license file found in the following locations',\n\t\t\t\tpossibleLicenseFileLocations,\n\t\t\t);\n\t\t}\n\n\t\treturn {};\n\t}\n\n\tasync process(_packageJson: PackageJson, pathContext: PackageExportPathContext): Promise<void> {\n\t\tif (pathContext.packageJsonKind === PACKAGE_JSON_KIND.DISTRIBUTION) {\n\t\t\tif (!this.licensePath) {\n\t\t\t\tthis.context.logger.warn('No license file found!');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst licenseFileDestination = p.join(\n\t\t\t\ttoAbsolute(this.context.outDir, this.context),\n\t\t\t\tp.basename(this.licensePath),\n\t\t\t);\n\n\t\t\ttry {\n\t\t\t\tawait cp(this.licensePath, licenseFileDestination);\n\t\t\t\tthis.context.logger.info('Copied license file from', this.licensePath);\n\t\t\t} catch (error) {\n\t\t\t\tthis.context.logger.error(\n\t\t\t\t\t\"Couldn't copy license file from\",\n\t\t\t\t\tthis.licensePath,\n\t\t\t\t\t'to',\n\t\t\t\t\tthis.context.outDir,\n\t\t\t\t\t'error happened',\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { PackageJson, RegularWorkspacePackage } from '@alexaegis/workspace-tools';\n\nimport { deepMapObject } from '@alexaegis/common';\nimport type { NormalizedPakkContext } from '../../index.js';\nimport { type PackageJsonKindType } from '../../package-json/index.js';\nimport type { PakkFeature } from '../pakk-feature.type.js';\n\nexport const pakkDirectivePrefix = 'pakk:';\nexport const pakkDirectiveNotDistributed = `${pakkDirectivePrefix}not-distributed`;\nexport const everyPakkDirective = [pakkDirectiveNotDistributed] as const;\n\n/**\n * Processes pakk directives in the packageJson. They are strings that could\n * be present at either on a key or on a value. They can start with a # to let\n * them be interpreted as comments by the shell.\n *\n * - pakk:not-distributed will remove the entry when compiling the distributed\n * package.json. When placed on a postinstall script, its effect will be\n * similar to what `pinst` does.\n *\n * ```json\n * {\n * \"scripts\": {\n * \"postinstall\": \"svelte-kit sync # pakk:not-distributed\",\n * }\n * }\n * ```\n */\nexport class AutoDirective implements PakkFeature {\n\tpublic readonly order = 5;\n\n\tprivate readonly context: NormalizedPakkContext;\n\n\tconstructor(context: NormalizedPakkContext) {\n\t\tthis.context = context;\n\t\tthis.context.logger.info('enabled directives:');\n\t\tthis.context.logger.info(pakkDirectiveNotDistributed);\n\t}\n\n\tpostprocess(\n\t\tworkspacePackage: RegularWorkspacePackage,\n\t\tpackageJsonKind: PackageJsonKindType,\n\t): PackageJson {\n\t\treturn deepMapObject<PackageJson>(workspacePackage.packageJson, (key, value) => {\n\t\t\tif (\n\t\t\t\tpackageJsonKind === 'development' &&\n\t\t\t\ttypeof key === 'string' &&\n\t\t\t\tkey.includes(pakkDirectivePrefix) &&\n\t\t\t\teveryPakkDirective.every((directive) => !key.includes(directive))\n\t\t\t) {\n\t\t\t\tthis.context.logger.warn(\n\t\t\t\t\t'key contains a pakk directive that is not recognized',\n\t\t\t\t\tkey,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tpackageJsonKind === 'development' &&\n\t\t\t\ttypeof value === 'string' &&\n\t\t\t\tvalue.includes(pakkDirectivePrefix) &&\n\t\t\t\teveryPakkDirective.every((directive) => !value.includes(directive))\n\t\t\t) {\n\t\t\t\tthis.context.logger.warn(\n\t\t\t\t\t'value contains a pakk directive that is not recognized',\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn packageJsonKind === 'distribution' &&\n\t\t\t\t((typeof key === 'string' && key.includes(pakkDirectiveNotDistributed)) ||\n\t\t\t\t\t(typeof value === 'string' && value.includes(pakkDirectiveNotDistributed)))\n\t\t\t\t? undefined\n\t\t\t\t: value;\n\t\t});\n\t}\n}\n","import type { Defined } from '@alexaegis/common';\nimport { PackageJsonExportTarget } from '../../index.js';\nimport {\n\tDEFAULT_PACKAGE_EXPORTS,\n\tDEFAULT_PACKAGE_EXPORT_BASEDIR,\n\tDEFAULT_PACKAGE_EXPORT_IGNORES,\n} from '../../internal/defaults.const.js';\n\nexport const DEFAULT_PACKAGE_JSON_EXPORT_PATH = './package.json';\n\nexport interface AutoExportAndExportStaticCommonOptions {\n\t/**\n\t * Whether or not automatically export the package.json file too.\n\t *\n\t * Note: If you want to refer to the actual distributed\n\t * package.json in your scripts, you should import it through an export\n\t * and not use a direct json import, your bundler will bundle your\n\t * compile time package.json in, and your users will end up using that\n\t * information, not what was published.\n\t *\n\t * @defaultValue true\n\t */\n\texportPackageJson?: boolean | undefined;\n}\n\nexport interface AutoExportOptions extends AutoExportAndExportStaticCommonOptions {\n\t/**\n\t * ### AutoExport\n\t *\n\t * The files to treat as entry points to be exported from relative from\n\t * the `srcDir + exportBaseDir` directory.\n\t * It's usually `*` meaning all files directly here are considered the\n\t * entry points of the library.\n\t *\n\t * @defaultValue '*'\n\t */\n\texports?: string | string[] | undefined;\n\n\t/**\n\t * ### AutoExport\n\t *\n\t * What paths to ignore when collecting exports in addition to\n\t * `defaultExportsIgnore` so you're not dropping the defaults when you just\n\t * want to add additional ignore entries.\n\t *\n\t * @defaultValue undefiend\n\t */\n\texportsIgnore?: string[] | undefined;\n\n\t/**\n\t * ### AutoExport\n\t *\n\t * By default test files are excluded.\n\t *\n\t * This option is here if you deliberately want to drop the default ignores.\n\t * Otherwise use `exportsIgnore`.\n\t *\n\t * @defaultValue '*.(spec|test).*'\n\t */\n\tdefaultExportsIgnore?: string[] | undefined;\n\n\t/**\n\t * ### AutoExport\n\t *\n\t * Relative path to `srcDir` if you want your exports to start from a\n\t * different directory.\n\t *\n\t * @example With the default settings src/index.ts will be the \".\" export\n\t * on your package json. If `exportBaseDir` is set to 'api' then\n\t * \"src/api/index.ts\" will be the \".\" export. If on top of this, you\n\t * change exports to be [\"*\", \"sub/*\"]\n\t *\n\t * @defaultValue '.'\n\t */\n\texportBaseDir?: string | undefined;\n\n\t/**\n\t * Where should exports point to in your development packageJson file\n\t *\n\t * By default, to let you develop locally with the same code as you'd\n\t * publish, the development packageJson targets the outDir where your\n\t * built package is supposed to be. This expects you to build the package\n\t * before running it. (Turbo can orchestrate this for you!)\n\t *\n\t * But if you wish your local packages to use the source code directly\n\t * you can set this to 'source' and then exports will point inside your\n\t * 'src' folder. This can be useful for packages that are not transpiled\n\t * and are supposed to be used as is.\n\t *\n\t * Types always point to the source dir so the typescript LSP can provide\n\t * real-time feedback in other packages too without having to rebuild all\n\t * the time!\n\t *\n\t * @defaultValue 'dist'\n\t */\n\tdevelopmentPackageJsonExportsTarget?: 'dist' | 'source' | undefined;\n\n\t/**\n\t * Add svelte export conditions or not\n\t *\n\t * @defaultValue false\n\t */\n\tsvelte?: boolean | undefined;\n}\n\nexport type NormalizedAutoExportOptions = Defined<AutoExportOptions>;\n\nexport const normalizeAutoExportOptions = (\n\toptions?: AutoExportOptions,\n): NormalizedAutoExportOptions => {\n\treturn {\n\t\texports: options?.exports ?? DEFAULT_PACKAGE_EXPORTS,\n\t\texportsIgnore: options?.exportsIgnore ?? [],\n\t\tdefaultExportsIgnore: options?.defaultExportsIgnore ?? DEFAULT_PACKAGE_EXPORT_IGNORES,\n\t\texportBaseDir: options?.exportBaseDir ?? DEFAULT_PACKAGE_EXPORT_BASEDIR,\n\t\tdevelopmentPackageJsonExportsTarget:\n\t\t\toptions?.developmentPackageJsonExportsTarget ?? PackageJsonExportTarget.DIST,\n\t\tsvelte: options?.svelte ?? false,\n\t\texportPackageJson: options?.exportPackageJson ?? true,\n\t};\n};\n","import type { Defined } from '@alexaegis/common';\nimport { DEFAULT_STATIC_EXPORT_GLOBS } from '../../internal/defaults.const.js';\nimport type { AutoExportAndExportStaticCommonOptions } from '../export/auto-export.class.options.js';\n\nexport interface AutoExportStaticOptions extends AutoExportAndExportStaticCommonOptions {\n\t/**\n\t * ### AutoExportStatic\n\t *\n\t * Relative to cwd, a folder whats content will be simply copied to\n\t * `outDir` and made available using simple, additional export statements.\n\t * Make sure their names don't overlap with other exports!\n\t *\n\t * @defaultValue [\"readme.md\", \"static/\\*\\*\", \"export/**\"]\n\t */\n\tstaticExports?: string[] | undefined;\n}\n\nexport type NormalizedAutoExportStaticOptions = Defined<AutoExportStaticOptions>;\n\nexport const normalizeAutoExportStaticOptions = (\n\toptions?: AutoExportStaticOptions,\n): NormalizedAutoExportStaticOptions => {\n\treturn {\n\t\tstaticExports: options?.staticExports ?? DEFAULT_STATIC_EXPORT_GLOBS,\n\t\texportPackageJson: options?.exportPackageJson ?? true,\n\t};\n};\n","import type { PackageJson, WorkspacePackage } from '@alexaegis/workspace-tools';\nimport { globby } from 'globby';\nimport { existsSync } from 'node:fs';\nimport { cp } from 'node:fs/promises';\nimport posix, { basename, join } from 'node:path/posix';\nimport type { NormalizedPakkContext } from '../../internal/pakk.class.options.js';\nimport { PACKAGE_JSON_KIND } from '../../package-json/package-json-kind.enum.js';\nimport { DEFAULT_PACKAGE_JSON_EXPORT_PATH } from '../export/auto-export.class.options.js';\nimport { stripFileExtension } from '../export/helpers/strip-file-extension.function.js';\nimport type { PackageExportPathContext } from '../export/package-export-path-context.interface.js';\nimport type { PackageExaminationResult, PakkFeature } from '../pakk-feature.type.js';\nimport {\n\tnormalizeAutoExportStaticOptions,\n\ttype AutoExportStaticOptions,\n\ttype NormalizedAutoExportStaticOptions,\n} from './auto-export-static.class.options.js';\n\nexport class AutoExportStatic implements PakkFeature {\n\tpublic readonly order = 2;\n\n\tprivate readonly options: NormalizedAutoExportStaticOptions;\n\tprivate readonly context: NormalizedPakkContext;\n\n\tprivate staticExports: Record<string, string> = {};\n\n\tconstructor(context: NormalizedPakkContext, options?: AutoExportStaticOptions) {\n\t\tthis.options = normalizeAutoExportStaticOptions(options);\n\t\tthis.context = context;\n\t}\n\n\tprivate static collectFileMap = async (\n\t\tcwd: string,\n\t\tglobs: string[],\n\t): Promise<Record<string, string>> => {\n\t\tconst globbyResult = await globby(globs, { cwd, dot: true });\n\t\treturn globbyResult.reduce<Record<string, string>>((accumulator, next) => {\n\t\t\tconst key = `.${posix.sep}${stripFileExtension(basename(next))}`;\n\t\t\taccumulator[key] = `.${posix.sep}${next}`;\n\t\t\treturn accumulator;\n\t\t}, {});\n\t};\n\n\tprivate static copyAll = async (\n\t\tcwd: string,\n\t\trelativeSourceFiles: string[],\n\t\toutDirectory: string,\n\t): Promise<void> => {\n\t\tawait Promise.allSettled(\n\t\t\trelativeSourceFiles\n\t\t\t\t.map((sourceFile) => ({\n\t\t\t\t\tsourceFile: join(cwd, sourceFile),\n\t\t\t\t\ttargetFile: join(cwd, outDirectory, sourceFile),\n\t\t\t\t}))\n\t\t\t\t.filter(\n\t\t\t\t\t({ sourceFile, targetFile }) =>\n\t\t\t\t\t\texistsSync(sourceFile) && !existsSync(targetFile),\n\t\t\t\t)\n\t\t\t\t.map(({ sourceFile, targetFile }) =>\n\t\t\t\t\tcp(sourceFile, targetFile, {\n\t\t\t\t\t\tpreserveTimestamps: true,\n\t\t\t\t\t\trecursive: true,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t);\n\t};\n\n\tasync examinePackage(\n\t\t_workspacePackage: WorkspacePackage,\n\t): Promise<Partial<PackageExaminationResult>> {\n\t\tthis.staticExports = await AutoExportStatic.collectFileMap(\n\t\t\tthis.context.workspacePackage.packagePath,\n\t\t\tthis.options.staticExports,\n\t\t);\n\n\t\tif (this.options.exportPackageJson) {\n\t\t\tthis.staticExports[DEFAULT_PACKAGE_JSON_EXPORT_PATH] = DEFAULT_PACKAGE_JSON_EXPORT_PATH;\n\t\t}\n\n\t\treturn {};\n\t}\n\n\tasync process(\n\t\t_packageJson: PackageJson,\n\t\tpathContext: PackageExportPathContext,\n\t): Promise<PackageJson> {\n\t\tif (pathContext.packageJsonKind === PACKAGE_JSON_KIND.DISTRIBUTION) {\n\t\t\tconst staticFilePaths = Object.values(this.staticExports);\n\n\t\t\tthis.context.logger.info('copy all static files', staticFilePaths);\n\t\t\tawait AutoExportStatic.copyAll(\n\t\t\t\tthis.context.workspacePackage.packagePath,\n\t\t\t\tstaticFilePaths,\n\t\t\t\tthis.context.outDir,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\texports: this.staticExports,\n\t\t} as PackageJson;\n\t}\n\n\tpostprocess(workspacePackage: WorkspacePackage): PackageJson {\n\t\tif (workspacePackage.packageJson.exports) {\n\t\t\tfor (const [key, value] of Object.entries(workspacePackage.packageJson.exports)) {\n\t\t\t\t// Remove no longer existing static exports\n\t\t\t\tif (typeof value === 'string' && !this.staticExports[key]) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\t\tdelete workspacePackage.packageJson.exports[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn workspacePackage.packageJson;\n\t}\n}\n","import type { PackageJson, PackageJsonExportConditions } from '@alexaegis/workspace-tools';\nimport p from 'node:path';\nimport type { PackageExaminationResult, PakkFeature } from '../pakk-feature.type.js';\nimport { stripFileExtension } from './helpers/strip-file-extension.function.js';\n\nimport { toAbsolute } from '@alexaegis/fs';\nimport { globby } from 'globby';\nimport { dirname } from 'node:path/posix';\nimport type { LibraryFormats } from 'vite';\nimport type { NormalizedPakkContext } from '../../internal/pakk.class.options.js';\nimport {\n\tPACKAGE_JSON_KIND,\n\tPackageJsonExportTarget,\n\ttype PathMap,\n} from '../../package-json/index.js';\nimport {\n\tDEFAULT_PACKAGE_JSON_EXPORT_PATH,\n\tnormalizeAutoExportOptions,\n\ttype AutoExportOptions,\n\ttype NormalizedAutoExportOptions,\n} from './auto-export.class.options.js';\nimport type { EntryPathVariantMap } from './export-map.type.js';\nimport { createExportMapFromPaths } from './helpers/create-export-map-from-paths.function.js';\nimport type { PackageExportPathContext } from './package-export-path-context.interface.js';\n\nexport const allExportPathCombinations = [\n\t`${PACKAGE_JSON_KIND.DEVELOPMENT}-to-${PackageJsonExportTarget.SOURCE}`,\n\t`${PACKAGE_JSON_KIND.DEVELOPMENT}-to-${PackageJsonExportTarget.DIST}`,\n\t`${PACKAGE_JSON_KIND.DISTRIBUTION}-to-${PackageJsonExportTarget.DIST}`,\n] as const;\nexport type AllExportPathCombinations = (typeof allExportPathCombinations)[number];\nexport type ExportPathMap = PathMap<AllExportPathCombinations>;\n\nexport type ExportTargetFileFormats = LibraryFormats;\n\n/**\n * Generates exports entries automatically\n */\nexport class AutoExport implements PakkFeature {\n\tpublic readonly order = 1;\n\n\tprivate readonly options: NormalizedAutoExportOptions;\n\tprivate readonly context: NormalizedPakkContext;\n\n\tprivate exportMap: EntryPathVariantMap<AllExportPathCombinations> = {};\n\n\tconstructor(context: NormalizedPakkContext, options?: AutoExportOptions) {\n\t\tthis.context = context;\n\t\tthis.options = normalizeAutoExportOptions(options);\n\t}\n\n\tasync examinePackage(_packageJson: PackageJson): Promise<Partial<PackageExaminationResult>> {\n\t\tconst absoluteExportBaseDir = toAbsolute(\n\t\t\tp.posix.join(this.context.srcDir, this.options.exportBaseDir),\n\t\t\t{\n\t\t\t\tcwd: this.context.workspacePackage.packagePath,\n\t\t\t},\n\t\t);\n\n\t\tconst ignore = [...this.options.exportsIgnore, ...this.options.defaultExportsIgnore];\n\t\tthis.context.logger.trace('ignoring exports', ignore);\n\n\t\tconst entryFiles = await globby(this.options.exports, {\n\t\t\tcwd: absoluteExportBaseDir,\n\t\t\tignore,\n\t\t\tonlyFiles: true,\n\t\t\tdot: true,\n\t\t});\n\t\tthis.context.logger.info('detected package exports', entryFiles);\n\n\t\tthis.exportMap = createExportMapFromPaths(entryFiles, {\n\t\t\toutDir: this.context.outDir,\n\t\t\tsrcDir: this.context.srcDir,\n\t\t\tbasePath: this.options.exportBaseDir,\n\t\t\tkeyKind: 'extensionless-relative-path-from-base',\n\t\t});\n\n\t\tthis.context.logger.trace('exportMap', this.exportMap);\n\n\t\treturn {\n\t\t\tbundlerEntryFiles: entryFiles.reduce<Record<string, string>>((acc, entryFile) => {\n\t\t\t\tconst path = p.posix.join(\n\t\t\t\t\tthis.context.srcDir,\n\t\t\t\t\tthis.options.exportBaseDir,\n\t\t\t\t\tentryFile,\n\t\t\t\t);\n\t\t\t\tconst alias = stripFileExtension(entryFile);\n\t\t\t\tacc[alias] = path;\n\t\t\t\treturn acc;\n\t\t\t}, {}),\n\t\t};\n\t}\n\n\t/**\n\t * This plugin compiles the exports object for a packageJson file\n\t *\n\t * For the distributed packageJson it should always contain paths that are\n\t * targeting the dist folder from the dist folder.\n\t *\n\t * For development packageJson the types always target the source for\n\t * immediate feedback by the LSP by local consumers of the package.\n\t * The actual code that's being imported by node has two options,\n\t * by default they target the outDir and expect libraries to be built\n\t * before actually running them in a local setting.\n\t * There's an alternative mode however that will target the source files.\n\t */\n\tprocess(_packageJson: PackageJson, pathContext: PackageExportPathContext): PackageJson {\n\t\tconst entryExports: Record<string, PackageJsonExportConditions | string> = {};\n\n\t\tif (this.options.exportPackageJson) {\n\t\t\tthis.context.logger.debug('adding the package.json export entry');\n\t\t\tentryExports[DEFAULT_PACKAGE_JSON_EXPORT_PATH] = DEFAULT_PACKAGE_JSON_EXPORT_PATH;\n\t\t}\n\n\t\tfor (const [key, pathVariants] of Object.entries(this.exportMap)) {\n\t\t\tlet path: string;\n\t\t\tlet typesPath: string = pathVariants['development-to-source'];\n\n\t\t\tconst isSvelteFile = pathVariants['distribution-to-dist'].endsWith('.svelte');\n\t\t\t// Forcing dev package to consume only source files.\n\t\t\tconst developmentPackageJsonExportsTarget