qoi-cli
Version:
515 lines (510 loc) • 17.1 kB
JavaScript
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 };