UNPKG

qoi-cli

Version:

515 lines (510 loc) 17.1 kB
import { rmSync, existsSync as existsSync$1, statSync as statSync$1, mkdirSync } from 'node:fs'; import { copyFile, writeFile, mkdir } from 'node:fs/promises'; import { join as join$1, dirname as dirname$1, resolve, basename } from 'node:path'; import { builtinModules, createRequire } from 'node:module'; import { rollup } from 'rollup'; import { commonjs, nodeResolve } from './build.vendor.DcZhO2EW.js'; import { MagicString } from './vendor.BMdwWrjP.js'; import { existsSync, statSync } from 'fs'; import { join, dirname, extname } from 'path'; import { transformSync, minifySync } from '@swc/core'; import { createDefaultConfig } from './register.js'; const EXTENSIONS = [ 'ts', 'tsx' ]; function pathResolver(extensions) { const exts = [ ...EXTENSIONS, 'js', 'jsx', ...[] ]; const resolveFile = (resolved, index = false)=>{ for (const extension of exts){ const file = index ? join(resolved, `index.${extension}`) : `${resolved}.${extension}`; if (existsSync(file)) { return file; } } return null; }; return function resolveId(id, origin) { if (origin && id[0] === '.') { const resolved = join(dirname(origin), id); const file = resolveFile(resolved); if (file) { return file; } if (existsSync(resolved) && statSync(resolved).isDirectory()) { const coreFile = resolveFile(resolved, true); if (coreFile) { return coreFile; } } } }; } const minify = (code, options)=>{ return minifySync(code, { sourceMap: typeof options?.sourceMaps == 'string' ? true : options.sourceMaps, module: options?.jsc?.minify?.module ?? true, compress: true, mangle: { toplevel: true } }); }; function swcPlugin(options) { const extensions = EXTENSIONS.map((ext)=>`.${ext}`); const filter = (id)=>extensions.includes(extname(id)); const filter$ = options?.createFilter?.(); const { createFilter, ...rest } = options ?? {}; const defaults = createDefaultConfig(rest); const opts = { ...defaults, jsc: { ...defaults.jsc ?? {}, ...{ baseUrl: rest?.jsc?.baseUrl ?? process.cwd() }, ...{ paths: rest?.jsc?.paths ?? {} } } }; return { name: 'swc', resolveId: pathResolver(), transform (code, id) { if (id.includes('node_modules')) return null; if (filter$?.tsFilter?.(id) || filter$?.cssFilter?.(id) || filter(id)) { return transformSync(code, { filename: id, ...opts }); } }, renderChunk (code) { return rest?.minify ? minify(code, rest) : null; } }; } /* istanbul ignore file */ function replace(string, needle, replacement, options = {}) { if (typeof string !== 'string') { throw new TypeError(`Expected input to be a string, got ${typeof string}`); } if (!(needle.length > 0) || false) { return string; } let result = ''; let matchCount = 0; /// @ts-ignore let prevIndex = options.fromIndex > 0 ? options.fromIndex : 0; if (prevIndex > string.length) { return string; } while(true){ const index = string.indexOf(needle, prevIndex); if (index === -1) { break; } matchCount++; const replaceStr = replacement ; const beginSlice = matchCount === 1 ? 0 : prevIndex; result += string.slice(beginSlice, index) + replaceStr; prevIndex = index + needle.length; } if (matchCount === 0) { return string; } return result + string.slice(prevIndex); } const baseDir = ()=>{ return process.env.APP_ROOT_PATH ?? process.cwd(); }; const configBaseDir = ()=>{ return process.env.QOI_CONFIG_ROOT_DIR ?? process.cwd(); }; const getPackageNameScope = (name)=>{ const names = name.split('/'); return names.length > 1 ? names[1] : names.pop(); }; const getPackage = (filePath)=>{ const pkgPath = join$1(baseDir(), 'package.json'); return requireModule(pkgPath); }; const requireModule = (modulePath)=>{ try { return require(modulePath); } catch { return createRequire(import.meta.url)(modulePath); } }; const updateExternalWithResolve = (options)=>{ const { resolve, external } = options; if (typeof resolve == "boolean" && resolve) { return []; } if (Array.isArray(resolve)) { return Array.from(external).filter((value)=>!resolve.includes(value)); } if (typeof resolve == "string") { const resolves = resolve.split(','); const externals = Array.from(external).filter((value)=>!resolves.includes(value)); return externals; } return external ?? []; }; const removeLicense = (minify)=>{ const toMinify = (code)=>{ const content = new MagicString(code); return { code: replace(content.toString(), '@license', ''), map: content.generateMap({ hires: true }) }; }; return { name: 'license', transform (code) { return minify && toMinify(code); } }; }; const geTsConfigPaths = ()=>{ const require$ = createRequire(import.meta.url); const tsconfigPath = join$1(process.cwd(), 'tsconfig.json'); return existsSync$1(tsconfigPath) ? require$(tsconfigPath)?.compilerOptions?.paths ?? undefined : undefined; }; const tsPaths = (dts)=>{ return geTsConfigPaths() && (dts || process.platform.includes('win32')) ? [ requireModule('./ts-paths').tsconfigPaths() ] : []; }; const createOutputOptions = (options)=>{ const { output, outDir: dir = 'dist', pkg, format, sourcemap } = options; const filename = getPackageNameScope(pkg.name) + (options.module ? '.mjs' : '.js'); const outputs = format.split(',').map((format)=>{ const outputOptions = { dir: format.includes('cjs') ? join$1(dir, 'cjs') : dir, format: options.module ? 'es' : format, sourcemap, entryFileNames: filename, chunkFileNames: '[name].[hash].js' }; return output?.(outputOptions) ?? outputOptions; }); return outputs; }; const createOptions = ({ config, options, pkg })=>{ const isLiterals = typeof options.minify == 'string' && options.minify.includes('literals'); const minify = typeof options.minify == 'boolean' ? options.minify : isLiterals; const swc = { ...config.swc, sourceMaps: config.sourcemap || options.sourcemap || false, minify }; const toMinifyLiterals = ()=>{ if (!isLiterals) return []; return [ requireModule('minify-template-literals').minifyLiterals() ]; }; return { input: config.input || getEntryFile({ pkgName: pkg.name, dir: options.dir }), external: updateExternalWithResolve({ resolve: config.resolve ?? options.resolve ?? false, external: [ ...(options.external || '').split(','), ...config.external || [], ...baseExternals(pkg) ] }), plugins: [ ...config.plugins && Array.isArray(config.plugins) ? config.plugins.flat() : config.plugins ? [ config.plugins ] : [], ...tsPaths(), removeLicense(minify), commonjs({ transformMixedEsModules: true, requireReturnsDefault: true }), nodeResolve(), swcPlugin(swc), ...toMinifyLiterals() ], output: createOutputOptions({ ...options, sourcemap: swc.sourceMaps, pkg, output: config.output }) }; }; const build = async (options, write = true)=>{ const { output } = options; const outputOptions = Array.isArray(output) ? output : [ output ]; const bundle = await rollup(options); return Promise.all(outputOptions.map((outputOption)=>{ return bundle[write ? 'write' : 'generate'](outputOption); })); }; const getDtsResolve = (resolve)=>{ if (resolve && typeof resolve == 'boolean') { return resolve; } if (resolve && Array.isArray(resolve) && resolve.length > 0) { return true; } return false; }; const dtsBuild = async (options)=>{ const { input, output: o, external, pkg, dts, config } = options; const dtsPlugin = await import('./rollup-plugin-dts.B4ORVFkg.js'); const createDefaultOptions = ()=>{ const output = Array.isArray(o) ? o : [ o ]; const file = output[0].entryFileNames; const dir = output[0].dir; return { file: file && typeof file == 'string' ? join$1(dir, file.includes('.js') ? basename(file, '.js') + '.d.ts' : file) : join$1(dir, getPackageNameScope(pkg.name) + '.d.ts'), write: true, resolve: false }; }; const opts = typeof dts == 'boolean' || typeof dts == 'string' ? createDefaultOptions() : { ...createDefaultOptions(), ...dts || {} }; const resolve = typeof dts == 'string' && dts === 'only' ? config.resolve : opts.resolve; const bundle = await rollup({ input, external: updateExternalWithResolve({ resolve, external: [ ...(external || '').split(','), ...config.external || [], ...baseExternals(pkg) ] }), plugins: [ { name: 'style', transform (_, id) { return (id.includes('.css') || id.includes('.scss')) && { code: '' }; } }, ...tsPaths(true), dtsPlugin.default({ respectExternal: getDtsResolve(resolve) }) ] }); return bundle[opts.write ? 'write' : 'generate']({ file: opts.file, format: 'es' }); }; const copyReadMeFile = async (options)=>{ const fileName = 'README.md'; const src = options?.filePath ?? join$1(baseDir(), fileName); const destPath = join$1(options?.output ?? 'dist', fileName); mkdirSync(dirname$1(destPath), { recursive: true }); existsSync$1(src) && await copyFile(src, destPath); }; const createCommonjsPackageFile = async (outDir)=>{ const outputFile = join$1(outDir, 'cjs', 'package.json'); await mkdir(dirname$1(outputFile), { recursive: true }); await writeFile(outputFile, JSON.stringify({ type: 'commonjs' }, null, 2)); }; const copyPackge = async (options)=>{ const { pkg, outDir, legacy, packageJson } = options; const name = getPackageNameScope(pkg.name); const main = pkg.main || `${name}.js`; const hasLegacy = legacy && !pkg.exports; const packageFile = { name: pkg.name, version: pkg.version, ...pkg.bin ? { bin: { ...pkg.bin } } : {}, type: pkg.type || 'module', main, module: main, ...hasLegacy ? { exports: { require: `./cjs/${main}`, import: `./${main}` } } : {}, typings: pkg.typings || `${name}.d.ts`, keywords: pkg.keywords, author: pkg.author, license: pkg.license, ...pkg.peerDependencies ? { peerDependencies: pkg.peerDependencies } : {}, ...pkg.dependencies ? { dependencies: pkg.dependencies } : {} }; const pkgJsonFunc = typeof packageJson == 'boolean' ? undefined : packageJson; const json = pkgJsonFunc?.(packageFile) ?? packageFile; const outputFile = join$1(outDir, 'package.json'); await writeFile(outputFile, JSON.stringify(json, null, 2)); hasLegacy && await createCommonjsPackageFile(outDir); }; const configPaths = ()=>{ const configs = [ 'qoi.config.ts', 'qoi.config.js', 'qoi.config.mjs' ]; return [ ...configs, ...configs.map((c)=>join$1('dist', c)) ]; }; const resolveConfigFile = (...directories)=>{ const configs = configPaths(); for (const config of configs){ const rootDir = resolve(configBaseDir()); const CONFIG_FULL_PATH = join$1(rootDir, ...directories || [], config); if (existsSync$1(CONFIG_FULL_PATH) && statSync$1(CONFIG_FULL_PATH).isFile()) return CONFIG_FULL_PATH; } return null; }; const requireConfig$ = (cPath)=>{ const config$ = requireModule(cPath)?.default; return typeof config$ == 'function' ? config$() : config$; }; const createPackageConfigPath = (configFile)=>{ const config = resolveConfigFile('node_modules', configFile); return config ? requireConfig$(configFile + '/' + config) : null; }; const createConfigFile = (configFile)=>{ const file = join$1(configBaseDir(), 'node_modules', configFile); return existsSync$1(file) && statSync$1(file).isFile() ? requireConfig$(file) : null; }; function loadConfig(configFile) { const CONFIG_FULL_PATH = join$1(configBaseDir(), configFile || ''); if (existsSync$1(CONFIG_FULL_PATH) && statSync$1(CONFIG_FULL_PATH).isFile()) { return requireConfig$(CONFIG_FULL_PATH); } const config = resolveConfigFile(); if (config) { return requireConfig$(config) ?? {}; } return configFile ? createPackageConfigPath(configFile) ?? createConfigFile(configFile) ?? {} : {}; } const getEntryFile = (options)=>{ const extensions = [ '.ts', '.js', '.tsx', '.jsx', '.mjs' ]; const createExtensions = (value)=>extensions.map((e)=>`${value}${e}`); const { dir = 'src', pkgName } = options || {}; const name = getPackageNameScope(pkgName); const entryFiles = [ ...createExtensions('index'), ...createExtensions('main'), ...name ? createExtensions(name) : [] ]; const file = entryFiles.find((entry)=>existsSync$1(join$1(dir, entry))); if (file) { return join$1(dir, file); } throw new Error('Entry file is not exist.'); }; const isDtsOnly = (options, config)=>{ return typeof options.dts == 'string' && options.dts === 'only' || typeof config.dts == 'string' && config.dts === 'only'; }; function baseExternals(pkg) { pkg = pkg ?? getPackage(); return [ ...builtinModules, ...Object.keys(pkg.peerDependencies || {}), ...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.devDependencies || {}) ]; } function getOptions(options) { return { format: 'es', outDir: 'dist', sourcemap: false, cleanOutDir: false, write: true, ...options || {} }; } async function handler(options) { const config = loadConfig(options.c ?? options.config), pkg = getPackage(); const configs$ = Array.isArray(config) ? config : [ config ]; const names = options.name?.split(',') || []; const configs = names.length ? configs$.filter((c)=>options.name.split(',').includes(c.name)) : configs$; !names.length && options.cleanOutDir && rmSync(options.outDir, { force: true, recursive: true }); await Promise.all(configs.map(async (c)=>{ const opts = createOptions({ config: c, options, pkg }); if (names.find((n)=>n.includes(c.name))) { const outDir = Array.isArray(opts.output) ? opts.output[0].dir : opts.output.dir; options.cleanOutDir && rmSync(outDir || options.outDir, { force: true, recursive: true }); } requireModule('./dotenv').parse$(c.env); await Promise.all([ (typeof options.dts === 'boolean' && options.dts || !isDtsOnly(options, c)) && build(opts), (options.dts || c.dts) && dtsBuild({ ...opts, config: c, external: options.external, dts: c.dts || options.dts }), copyReadMeFile({ output: options.outDir }), copyPackge({ pkg, outDir: options.outDir, packageJson: c.packageJson, legacy: options.format.split(',').includes('cjs') }) ]); c.buildEnd && await c.buildEnd(); })); } const defineConfig = (config)=>config; export { baseExternals, defineConfig, getOptions, handler, swcPlugin };