neo-builder
Version:
the fastest tiny script packager written in javascript and supporting iife dynamic chaining w/o extra runtime
1,429 lines (1,131 loc) • 118 kB
JavaScript
import require$$1 from 'fs';
import require$$0$1 from 'path';
import require$$0 from 'perf_hooks';
import 'child_process';
var main = {};
var utils = {};
var benchmarks = {};
//@ts-check
const { performance } = require$$0 || { performance: Date };
/**
* @type {Record<string, {time: number, count: number}>}
*/
const benchStore = Object.setPrototypeOf({}, {
toString() {
let r = Object.entries(this).map(([k, v]) => typeof v === 'object' ? `- \x1B[90m${k}: \x1B[32m${v.count} times (${v.time.toFixed(3)} ms)\x1B[0m` : '').join('\n');
return r //+ '\n'
}
});
/**
* @param {Function} func
* @param {any[]} args
*/
function benchmarkFunc$1(func, ...args) {
const start = performance.now();
const result = func(...args);
const funcName = func.name || func.toString();
_commitMark$(start, funcName);
return result;
}
/**
* @param {number} [start]
* @param {string} [funcName]
*/
function _commitMark$(start, funcName) {
if (!benchStore[funcName]) {
benchStore[funcName] = {
time: performance.now() - start,
count: 1
};
}
else {
benchStore[funcName].time += performance.now() - start;
benchStore[funcName].count++;
}
}
benchmarks.benchmarkFunc = benchmarkFunc$1;
benchmarks.benchStore = benchStore;
benchmarks.commitMark$ = _commitMark$;
//@ts-check
//\/ <reference path="../types/utils.d.ts" />
const path$1 = require$$0$1;
const fs$1 = require$$1;
const { benchmarkFunc } = benchmarks;
/**
* @typedef {import("sourcemap-codec").SourceMapMappings} SourceMapMappings
* @typedef {{
* sources: string[],
* sourcesContent: string[],
* mappings?: string
* }} MapInfo
*/
/**
* @description Merge advanced map (`externalMap`) for preprocessed multifiles with inside maps based also on multi files
*
* @param {{ mapping: SourceMapMappings; sourcesContent: string[]; files: string[]; }} insideMapInfo
* @param {{
* outsideMapInfo: MapInfo,
* outsideMapping: SourceMapMappings;
* }} externalMap
* @param {(arg: import("sourcemap-codec").SourceMapSegment[][]) => string} [encode]
* @returns {{
* outsideMapInfo: MapInfo,
* mergedMap: import("sourcemap-codec").SourceMapSegment[][],
* }}
*/
function deepMergeMap$1(insideMapInfo, externalMap, encode) {
const { outsideMapInfo, outsideMapping } = externalMap;
const { sourcesContent, files } = insideMapInfo;
/// update file links inside:
const mapping = insideMapInfo.mapping.map(line => {
if (line && line.length) {
line.forEach((ch, i) => {
if (line[i][1] < files.length - 1) line[i][1] += outsideMapInfo.sources.length;
});
return line;
}
return [];
});
/// merge itself SourceMapMappings (reduce whatever lines to root lines):
let mergedMap = mapping.map((line, i) => {
if (!line || !line.length) return [];
let _line = (line || []).map((ch, j, arr) => {
const origCharMap = outsideMapping[line[j][2]];
if (origCharMap && origCharMap.length) return origCharMap[0];
else {
if (ch[1] > outsideMapInfo.sources.length - 1) return ch;
else {
return null;
}
}
});
return _line.filter(l => l);
});
outsideMapInfo.sources = outsideMapInfo.sources.concat(files.slice(0, -1));
outsideMapInfo.sourcesContent = outsideMapInfo.sourcesContent.concat((sourcesContent || []).slice(0, -1));
if (encode) {
outsideMapInfo.mappings = encode(mergedMap);
}
return { mergedMap, outsideMapInfo }
/// Further: outsideMap.mappings = encode(mergedMap);
}
// * @param {{
// * mapStartToken?: string, // [mapStartToken='//# sourceMappingURL=data:application/json;charset=utf-8;base64,']
// * pluginMapping?: import('./utils').SourceMapMappings,
// * decode: (arg: string) => ([number] | [number, number, number, number] | [number, number, number, number, number])[][]
// * }} options
// * @template P
// * @typedef {P extends SourceMapMappings ? {}
// * : {
// * decode: (arg: string) => ([number] | [number, number, number, number] | [number, number, number, number, number])[][]
// * }
// * } MergeMapsOptions
/**
* @description merge advancedMap for preprocessed finished single file (code) with origin map based on multi files
* @param {string} builtCode
* @param {import('sourcemap-codec').SourceMapMappings} originMapSheet
* @param {{
* mapStartToken?: string, // [mapStartToken='//# sourceMappingURL=data:application/json;charset=utf-8;base64,']
* pluginMapping?: import('./utils').SourceMapMappings,
* decode?: (arg: string) => SourceMapMappings
* }} options
* @returns {[string, import('sourcemap-codec').SourceMapMappings]}
*/
function mergeFlatMaps(builtCode, originMapSheet, options) {
const { mapStartToken, pluginMapping, decode } = options || {};
if (pluginMapping) var advancedMap = pluginMapping;
else {
var [advancedMap, $, code] = extractEmbedMap(builtCode, { sourceMapToken: mapStartToken, decode });
}
// jsMap[tsMap.map(el => el ? el[0] : null)[2][2]]
/// CHECKED (TS?)?
const mergedMap = advancedMap.map(line => line ? line[0] : []).map(line => originMapSheet[line[2]]);
/// CHECKED ON CODEPEN WITH BUBLE
// const mergedMap = advancedMap.map(line => (line && line.length) ? [line[0]] : []).map(line => line.length ? (originMapSheet[line[0][2]] || []) : [])
/// ALERNATIVES (SIMPLEST. NOT CHECKED YET):
// tsMap.map(line => jsMap[line[0][2]])
// or
// let mergedMap = tsMap.map(m => m.map(c => jsMap[c[2]])); // its wrong fow some reason and ts swears!!!
return [code || builtCode, mergedMap];
}
/**
* @description extract origin sourcemap from inline code
* @param {string} code
* @param {{
* sourceMapToken?: string,
* decode: (arg: string) => SourceMapMappings
* }} options
* @returns {[import('sourcemap-codec').SourceMapMappings, {sourcesContent: string[], sources: string[], mappings: string, file: string, files: string[]}, string]}
*/
function extractEmbedMap(code, options) {
let { sourceMapToken } = options || {};
sourceMapToken = sourceMapToken || '//# sourceMappingURL=data:application/json;charset=utf-8;base64,';
const sourceMapIndex = code.lastIndexOf(sourceMapToken);
if (~sourceMapIndex) {
const baseOriginSourceMap = code.slice(sourceMapIndex + sourceMapToken.length);
const originSourceMap = JSON.parse(globalThis.document
? globalThis.atob(baseOriginSourceMap)
: Buffer.from(baseOriginSourceMap, 'base64').toString()
);
const jsMap = options.decode(originSourceMap.mappings);
return [jsMap, originSourceMap, code.slice(0, sourceMapIndex)];
}
return [null, null, code.slice(0, sourceMapIndex)];
}
utils.deepMergeMap = deepMergeMap$1;
utils.mergeFlatMaps = mergeFlatMaps;
utils.extractEmbedMap = extractEmbedMap;
/**
* generates fileStoreName under rool: root + fileName.replace('.?./' => '')
* @param {string} root
* @param {string} fileName
* @returns
*/
utils.genfileStoreName = function genfileStoreName(root, fileName) {
// const _genfileStoreName = ((root || '').replace('./', '') + fileName).replace(/[\/]/g, '$') // .replace(/\./g, '');
// ((root || '').replace('./', '') + (filename = filename.replace(/^\.\//m, ''))).replace(/\//g, '$') // .replace(/\./g, '')
const isrelative = fileName.match(/^\.?\.\//g, );
var _root = '';
if (isrelative) {
// fileName = fileName.replace(/^\.?\.\//g, '')
var parentDir = path$1.dirname(fileName);
// if (isrelative[0].startsWith('..')) {
// debugger
// }
_root = (parentDir !== '.')
? path$1.join(root || '', parentDir)
: (root || '');
}
// const _fileName = isrelative ? path.basename(fileName) : fileName
const _fileName = (isrelative ? path$1.basename(fileName) : fileName).replace(/\.[\w]+$/m, ''); // <- remove extension...
// const _genfileStoreName = ((_root || '').replace('./', '') + '__' + _fileName.replace('.', '')).replace('@', '$$').replace(/[\/\\\-]/g, '$');
// const _genfileStoreName = ((_root || '').replace('./', '') + '$' + _fileName.replace('.', '')).replace('@', '__').replace(/[\/\\\-]/g, '$');
// const _genfileStoreName = path.join(_root, fileName).replace('@', '__').replace(/[\/\\\-]/g, '$')
const _genfileStoreName = path$1.join(_root, _fileName).replace('@', '__').replace(/[\/\\]/g, '$').replace(/-/g, '_');
// if (_genfileStoreName == '__$uppy$utils$lib$getFileNameAndExtension') {
// debugger
// }
// else if (_genfileStoreName == '$uppy$utils$lib__getFileNameAndExtension') {
// debugger
// }
// if (_genfileStoreName == '__uppy$dashboard$lib$locale') {
// // msw$lib$utils$internal$isStringEqual
// debugger
// // locale ... on dashboard
// }
// else if (_genfileStoreName == 'msw$lib$utils$internal$isStringEqual') {
// debugger
// }
// else if (_genfileStoreName == 'swiper$modules$shared$create_element_if_not_defined') {
// debugger
// }
// else if (_genfileStoreName == 'shared$create_element_if_not_defined') {
// debugger
// }
if (~_genfileStoreName.indexOf('.')) {
if (_genfileStoreName == '') {
debugger
}
// debugger
// return _genfileStoreName.replace('.', '');
return _genfileStoreName.replace(/\./g, '');
}
return _genfileStoreName;
};
/**
* @param {string} nodeModulesPath
* @param {string} fileName
* @param {{ existsSync: (arg0: string) => boolean; }} [fs]
*/
function findPackagePath$1(nodeModulesPath, fileName, fs) {
const pathTree = fileName.split('/');
let basePath = nodeModulesPath;
let currentPath = fileName;
for (let i = 0; i < pathTree.length; i++) {
basePath += '/' + pathTree[i];
currentPath = path$1.join(basePath, 'package.json');
if (fs.existsSync(currentPath)) {
return currentPath
}
}
return currentPath
}
/**
* @this {Importer}
* @param {string} sourcePath
* @param {import("./main").BuildOptions & {targetFname?: string}} options
* @returns {string} - node_modules absolute path
*/
function findProjectRoot$1(sourcePath, options) {
if (fs$1.existsSync(path$1.join(sourcePath, 'package.json'))) {
const nodeModulesName = options.advanced?.nodeModulesDirname || 'node_modules';
return path$1.join(sourcePath, nodeModulesName)
}
else {
const parentDir = path$1.dirname(sourcePath);
if (parentDir.length > 4) {
return findProjectRoot$1(parentDir, options)
}
else {
throw new Error('Project directory and according node_modules folder are not found');
}
}
}
utils.findPackagePath = findPackagePath$1;
utils.findProjectRoot = findProjectRoot$1;
/**
* @description find main file inside package json
* @param {string} packageJson
* -param {{ readFileSync: (filename: string) => { toString (): string }; }} [fs]
* @returns {string}
*/
function findMainfile$1(packageJson) {
/**
* @type {{main?: string, module?: string, exports?: string | Record<string, {default?: string}>}}
*/
const packageInfo = JSON.parse(fs$1.readFileSync(packageJson).toString());
var relInsidePathname = packageInfo.module || packageInfo.main;
if (!relInsidePathname && packageInfo.exports) {
relInsidePathname = typeof packageInfo.exports == 'string' ? packageInfo.exports : packageInfo.exports['.'].default;
}
if (!relInsidePathname) {
debugger
}
return relInsidePathname || undefined;
}
utils.findMainfile = findMainfile$1;
const extensions = ['.js', '.ts', ''];
utils.extensions = extensions;
utils.fileNameRefine = function fileNameRefine(_fileName) {
for (var ext of extensions) {
if (benchmarkFunc(fs$1.existsSync, _fileName + ext)) {
_fileName = _fileName + ext;
break;
}
}
return [_fileName, ext];
};
utils.refineExtension = function fileNameRefineByDir(_fileName) {
const _extensions = extensions.slice(0, -1);
if (!~_extensions.indexOf(path$1.extname(_fileName))) {
// for existing app.js.js and passed app.js - possible bug
const basename = path$1.basename(_fileName);
// just the check takes 15ms! TODO optimize!
/**
* @type {string[]}
*/
//@ts-ignore string[]|Buffer[] => string[]
// const _execls = benchmarkFunc(execSync, `ls ${path.dirname(_fileName)}`).toString().split('\n').filter(f => !f.endsWith('.map') && f)
// const _execls = benchmarkFunc(fs.readdirSync, path.dirname(_fileName), {
// // withFileTypes: true
// });
const _execls = benchmarkFunc(readDir$1, path$1.dirname(_fileName));
// let fileExists = false;
for (var ext of extensions) {
// if (fileExists = fs.existsSync(_fileName + ext)) {
if (~_execls.indexOf(basename + ext)) {
_fileName = _fileName + ext;
// break;
return [_fileName, ext];
}
}
}
return [_fileName, ext];
};
const _dirsCache = {};
/**
* @param {string} dirname
*/
function readDir$1(dirname) {
if (_dirsCache[dirname]) {
return _dirsCache[dirname]
}
else {
// return dirsCache[dirname] || (dirsCache[dirname] = benchmarkFunc(fs.readdirSync, path.dirname(dirname), {
return (_dirsCache[dirname] = benchmarkFunc(fs$1.readdirSync, dirname, {
// withFileTypes: true
}).filter(f => !f.endsWith('.map')))
}
}
const symlinksCache = {};
function isSymbolLink$1(packageName) {
if (symlinksCache[packageName]) {
return symlinksCache[packageName]
}
else if (Object.keys(symlinksCache).filter(w => packageName.startsWith(w)).length) {
return symlinksCache[packageName]
}
else {
return (symlinksCache[packageName] = benchmarkFunc(fs$1.lstatSync, packageName).isSymbolicLink())
}
}
utils.readDir = readDir$1;
utils.isSymbolLink = isSymbolLink$1;
var declarations$ = {};
declarations$.AbstractImporter = class AbstractImporter{
/**
* @type {Array<string>} - for dynamic imports
*/
dynamicModulesExported = null;
/**
* @description - file, where imprting is in progress
* @type {string}
*/
get currentFile() {
return this.progressFilesStack.at(-1)
}
/**
* current file stack of all handled files at the momend (includes dyn and stat imports)
*/
progressFilesStack = []
/**
* @description current linked modules path stack
* @type {string[]}
*/
linkedModulePaths = [];
// /**@debug */
// /**
// *
// */
// benchmarkFunc = benchmarkFunc
// /**@end_debug */
};
var exports$ = {};
var _versions = {};
// export const version = Date.now();
_versions.version = Date.now();
// exports.version = new Date().getTime()
const statHolder$2 = {
imports: 0,
requires: 0,
dynamicImports: 0,
exports: {
cjs: 0
},
get importsAmount() {
return this.imports + this.requires
}
};
_versions.statHolder = statHolder$2;
//@ts-check
const { statHolder: statHolder$1 } = _versions;
/**
* @augment O(1) - 18 times ==> ~1ms (-100ms)
* @param {string} content
* @param {string} _exports
* @param {{
* fileStoreName: string
* extractinNames: Set<string>
* globalOptions?: import("../main").BuildOptions
* }} options
* @returns {{content: string, _exports: string}}
*/
function commonjsExportsApply$1(content, _exports, { fileStoreName, extractinNames, globalOptions }) {
let withCondition = false;
// cjs format
// does not take into account the end of the file
// TODO support default exports for objects: module.exports = {}
content = content.replace(/^(?: *module\.)?exports(?<export_name>\.[\w\$][\w\d\$]*)?[ ]=\s*(?<exports>[\s\S]+?(?:\n\}|;))/mg, function (_match, exportName, exportsValue) {
withCondition = _match.startsWith(' ');
if (withCondition) {
if (!globalOptions.experimental?.withConditions) {
globalOptions.advanced?.debug && console.warn(`>> condition export detected for ${fileStoreName}. May be need specifying withConditions option`);
withCondition = false;
return _match;
}
// debugger
}
statHolder$1.exports.cjs++;
// ((?<entityName>function|class|\([\w\d$,:<>]*) =>) [name])
// matches.push(exportName.slice(1));
if (exportName) {
exportName = exportName.slice(1);
if (!globalOptions.advanced?.treeShake) {
_exports += (_exports && ', ') + exportName;
}
else if (extractinNames.has(exportName)) {
_exports += (_exports && ', ') + exportName;
}
else if (typeof globalOptions.advanced?.treeShake == 'object' && globalOptions.advanced?.treeShake.cjs !== false) {
// TODO tree shke it here (TODO check all functions in the file like by es imports)
return '';
}
}
else {
_exports += (_exports && ', ') + 'default: $default';
if (exportsValue.match(/^\w+;$/)) {
_exports += ', ' + exportsValue.slice(0, -1);
}
}
// _exports += (exportName || ' default: $default').slice(1) // + ', ';
// return `var ${(exportName || ' $default').slice(1)} = ${exportsValue}`;
return `var ${exportName || '$default'} = ${exportsValue}`;
});
if (withCondition) {
content = content.replace('typeof module', '"object"');
}
return { content, _exports };
}
/**
* @param {string} content
* @param {string} _exports
* @param {boolean} isbuilt
* @deprecated
*/
function defaultExprsRemove(content, _exports, isbuilt) {
if (isbuilt) { // 3-3.5s
/// remove export keyword from content
// content = content.replace(/;export( default ([\w\d_\$]+(?:;|\n))?)?(\{[\s\S]+?\})?/gm, '').trimEnd();
// content = content.replace(/;export( default ([\w\d_\$]+(?:|\n))?)?(\{[\s\S]+?\})?/gm, '').trimEnd(); // fix comma autoremoving by comma removing - i am confused
content = content.replace(/(?<=;|\})export( default ([\w\d_\$]+(?:;|\n))?)?(\{[\s\S]+?\})?;?/gm, '').trimEnd();
// remove export
}
else if(_exports) {
// last group (\{[\s\S]+?[\n;]\}) => (\{[\s\S]+?[\n]\}) ??
// content = content.replace(/^export (default ([\w\d_\$]+(?:;|\n))?)?((\{[^\n]+\}[\n;])|(\{[^\n]+\}$)|(\{[\s\S]+?[\n;]\}))?;?/gm, '').trimEnd()
let m = content.match(/^export (default ([\w\d_\$]+(?:;|\n))?)?((\{[^\n]+\}[\n;])|(\{[^\n]+\}$)|(\{[\s\S]+?[\n;]\}))?;?/gm);
if (m) {
debugger
}
}
else ;
return content;
}
function applyDefaultExports(content, { isbuilt, extract, _exports, globalOptions }) {
/// export default (class|function )? A...
// let defauMatch = content.match(/^export default \b([\w_\$]+)\b( [\w_\$]+)?/m); // \b on $__a is failed cause of $ sign in start
// let defauMatch = content.match(/^export default ([\w_\$\.]+)\b( [\w_\$]+)?/m); // added export default Array.from support;
// let defauMatch = content.match(/^export default (\(?[\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?/m) // added export default (() => {}) support
// const defauMatch = content.match(/^export default ((?:\(|\[)?['"\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?/m) // added export default [..] support
// const defauMatch = content.match(/(?:^export)|((?<=;)export) default ((?:\(|\[)?['"\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?/m)
const defauMatch = content.match(isbuilt // added ;exports support
? /(?<=;)export default ((?:\(|\[)?['"\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?/m
// : /^export default ((?:\(|\[)?['"\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?/m
: /^export default (?:((?:\(|\[)?['"\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?((?:\*)? \w+)?)/m // async function* gen +
// : /^export default (?:((?:\(|\[)?['"\(\)\w_\d\$,\{\}\.]+)\b( [\w_\$]+)?((?:\*)? \w+)?)|(?:(\{[ \w\d,\(\):;'"\n\[\]]*?\})|(\{[\s\S]*\n\}))/m // async function* gen +
/**
* - 1 - full match (`export default function crelt`)
* - 2 - expr (async|function|class|$name|[...]|(...))
* - 3 - expr name (just for $2 == function|class) or expr last name - `function` (for async)
* - 4 - iterator (*) if $3 == function
*/
);
if (defauMatch) {
// export default (function|class name)|name|[...]|(() => ...) // -|{...}
if (globalOptions.advanced?.treeShake && !extract.default && !~extract.names.indexOf('default')) ;
// else if (defauMatch[4] || defauMatch[5]) {
// const $1 = defauMatch[4] || defauMatch[5]
// content.replace($1, `var _default = ${$1};\nexport default _default;`);
// }
else if (defauMatch[1] == 'async' && defauMatch[3]) {
_exports += (_exports && ', ') + 'default: ' + defauMatch[3].replace(/^\* /, '');
}
else if (~['function', 'class'].indexOf(defauMatch[1])) { // what if ' function'
// export default (function|class name)
if (!defauMatch[2]) {
/// there is not name
/// export default (class|function) () {}
content = content.replace(/^export default \b([\w_]+)\b/m, 'export default $1 $default');
}
/// export default (class|function) entityName
_exports += `${_exports && ', '}default: ` + (defauMatch[2] || '$default');
}
else {
if (defauMatch[1][0] == '(' || defauMatch[1][0] == '[') {
/// export default [...]|(() => ...)
content = content.replace(/^export default /m, 'const _default = ');
defauMatch[1] = '_default';
}
_exports += (_exports && ', ') + 'default: ' + defauMatch[1];
}
}
else {
// console.log(ls++)
// TODO #1 join default replaces to performance purpose: UP: check it, may be one of them is unused; (may be optimized ==> 90ms => 87ms for codemirror)
/// export default {...}
content = content.replace(
// /^export default[ ]+(\{[\s\S]*?\}(?:\n|;))/m
// /^export default[ ]+(\{[\s\S]*?\})[;\n]/m, 'var _default = $1;\n\nexport default _default;' // an incident with strings containing }, nested objs {}, etc...
// /^export default[ ]+(\{[\s\S]*?\})/m, 'var _default = $1;export default _default;' // ; - met me inside strings
// /^export default[ ]+(\{[ \w\d,\(\):;'"\n\[\]]*?\})/m, function (m, $1, $2) {
/^export default[ ]+((\{[ \w\d,\(\):;'"\n\[\]]*?\})|(\{[\s\S]*\n\}))/m, function (m, $1, $2) {
// /^export default[ ]+(\{[\s\S]*\n\})/m, function (m, $1) { // fixed export default { ...: {}}
return `var _default = ${$1};\nexport default _default;`;
// 'var _default = $1;\nexport default _default;'
}
);
}
return { content, _exports };
}
exports$.defaultExprsRemove = defaultExprsRemove;
exports$.applyDefaultExports = applyDefaultExports;
exports$.commonjsExportsApply = commonjsExportsApply$1;
var monadutils = {};
/**
* chainging function calling
* @param {Function} fn
* @param {number} cnt
* @param {string} arg
* @returns
*/
function chainingCall$1(fn, cnt, arg) {
if (!cnt) return arg;
var res = fn(...Array.prototype.slice.call(arguments, 2));
if (cnt - 1) return chainingCall$1(fn, cnt - 1, res)
else {
return res;
}
}
monadutils.chainingCall = chainingCall$1;
/**
* chai
* @param {(arg: T) => T} func
* @param {(arg?: T) => boolean} condfunc
* @param {T} arg
* @template T
*/
function conditionalChain$1(func, condfunc, arg, maxcallstack=5) {
const r = func(arg);
if (condfunc(r)) return r;
else if (!maxcallstack) return null;
else {
return conditionalChain$1(func, condfunc, r, maxcallstack-1)
}
}
monadutils.conditionalChain = conditionalChain$1;
function releaseProcess$1(options, content) {
if (options.sourceMaps) {
console.warn('Generate truth sourcemaps with options `release = true` is not guaranteed');
}
// remove comments:
// keeps line by line sourcemaps:
content = content.replace(/console\.log\([^\n]+?\);/g, ''); //*/ remove logs
// content = content.replace(/(?<!\*)[\s]*\/\/[\s\S]*?\n/g, options.sourceMaps ? '\n' : ''); //*/ remove comments?
// content = content.replace(/^[\s]*\/\/[\s\S]*?\n/gm, options.sourceMaps ? '\n' : ''); /*/ remove one-line comments
// content = content.replace(/(?<=\n[^'"]*)\/\/[\s\S]*?\n/gm, options.sourceMaps ? '\n' : ''); //*/ remove one-line comments - just in end of
// content = content.replace(/(?<=\n[^'"]*)(?<!\\)[\t ]*\/\/[\s\S]*?\n/gm, options.sourceMaps ? '\n' : ''); //*/ remove one-line comments - works fine, but too slowly!
// content = content.replace(/(?<!['"][^\n]*?)[\t ]+\/\/[\s\S]*?\n/gm, options.sourceMaps ? '\n' : ''); //*/ remove one-line comments -
content = content.replace(/(?<!['"/][^\n]*?)[\t ]*\/\/[\s\S]*?\n/gm, options.sourceMaps ? '\n' : ''); //*/ remove one-line comments
/// it breaks sourcemaps:
if (!options.sourceMaps) {
content = content.replace(/^([\s]*?\n){3}([\s]*?\n)*/gm, '\n'); //*/ // remove empty lines
// drop sourcemaps:
/// TODO? here it would be possible to edit the sorsmap in the callback:
content = content.replace(/(?<!['"/][^\n]*?)\/\*[\s\S]*?\*\//g, () => ''); // remove multiline comments
// it breaks sourcemaps
content = content.replace(/^[\t ]+\{[\n\r,\w\t ]+\}\r?\n/gm, ''); // remove useles scopes // (?: \/\/[\s\S]*?)
}
return content;
}
/**
* Remove code fragments marked as lazy inclusions
* @param {string} content - content
*/
function cleaningDebugBlocks$1(content) {
// return content.replace(/\/\*@lazy\*\/[\s\S]*?\/\*_lazy\*\//, '');
return content.replace(/\/\*\@if_dev ?\*\/[\s\S]*?\/\*\@end_if ?\*\//, '');
/**@if_dev */
/// this code will be removed:
/// for example here may be placed time measurement or another statistic and advanced object to store it
/// TODO /**@else */
/**@end_if */
}
var release$ = {
cleaningDebugBlocks: cleaningDebugBlocks$1,
releaseProcess: releaseProcess$1
};
var treeShaking = {};
//@ts-check
/**
*
* @param {import("../main").BuildOptions} globalOptions
* @param {string} mergedContent
* @param {Record<string, string>} modules
*/
treeShaking.violentShake = function (globalOptions, mergedContent, modules) {
return modules
};
treeShaking.theShaker = {
globalOptions: null,
/**
* @description store tree shaked modules to compare w dynamic import modules
* @type {Record<string, {
* content: string,
* shaked: string[],
* extracted?: string[]
* }>}
*/
shakedStore: {},
/**
*
* @param {*} exports
* @param {{
* exports$: string[],
* content: string,
* preShakeUp(s: string)
* onMiss(s?: string) // miss tree shaking
* }} _oprions
* @returns {string}
*/
work({ extracting, exports$, content, preShakeUp, onMiss }) {
const globalOptions = this.globalOptions;
for (const _export of exports$) {
const [outName, inName] = _export.split(':').map(s => s.trim());
if (~extracting.indexOf(outName)){
continue
}
const reg = new RegExp(`(function) ${_export}\\([\\w\\d, \\{\\}\\$]*\\)\\s*\\{[\\s\\S]*?\\n\\}\\r?\\n`, 'm');
const funcDef = content.match(reg) || content.match(
new RegExp(`(const|let|var) ${_export} = \\([\\w\\d, \\{\\}\\$]*\\) ? =\\> \\{[\\s\\S]*?\\n\\}\\r?\\n`)
) || content.match(new RegExp(
`class ${_export}( (?:extends|implements) [\\w\\d\\$_]+,)? ?\\{[\\s\\S]*?\\n\\}\\r?\\n`
));
// || content.match(new RegExp(`(const|var|let) ${_exp} = (\\d+|['"][\s\S]*['"]);?\\r?\\n`))
if (!funcDef) {
if (globalOptions.verbose && globalOptions.advanced.debug) {
onMiss(_export);
// console.warn(`-> tree-shaking: skiped shaking of '${_export}' export during "${importer.currentFile}" importing (is alias or is not function or unfound)`);
}
// return content;
continue
}
let treeShakedModule = content.replace(funcDef[0], ''); // .replace(exportsReg, m => m.replace(new RegExp(`${_export},? ?`), '')); // `${_exp},? ?`
if (treeShakedModule.match(new RegExp(`\\b${_export}\\b`))) {
continue
// return content;
}
else {
// IF the exported func DOES NOT USED ANYMORE
const shakedEffect = [_export];
// TODO also replace all unused classes and imported stuffs
content = treeShakedModule.replace(
/\n?\t?(?<isExported>export (?:default ))?function (?<fname>[\w\d\$_]+)\([\w\d_\$, \{\}]*?\) ?\{[\S\s]*?\n\}/g,
(m, isExported, name) => {
if (~extracting.indexOf(name)) {
return m;
}
else if (!~name.indexOf('$')) {
const used = treeShakedModule.replace(m, '').match(new RegExp(`\\b${name}\\b`));
if (used) return m;
else {
if (~exports$.indexOf(name)) {
shakedEffect.push(name);
}
return `// function "${name}" violently tree shaked `
}
}
else {
return m;
}
}
);
preShakeUp(shakedEffect);
// check all modules function used inside the treeshaked function
}
// }
}
return content;
}
};
var buildFile_1;
var packFile;
var combineContent_1;
var buildContent;
var build;
//@ts-check
const fs = require$$1;
const path = require$$0$1;
const { deepMergeMap, genfileStoreName, findPackagePath, findMainfile, findProjectRoot, fileNameRefine, refineExtension, readDir, isSymbolLink } = utils;
// const { benchmarkFunc, benchStore, commitMark$: $_commitMark } = require("./utils/benchmarks");
const { AbstractImporter } = declarations$;
const { commonjsExportsApply } = exports$;
const { chainingCall, conditionalChain } = monadutils;
const { releaseProcess, cleaningDebugBlocks } = release$;
const { violentShake: forceTreeShake, theShaker } = treeShaking;
const { version, statHolder } = _versions;
// const { performance } = require('perf_hooks');
// const regex = /^import (((\{([\w, ]+)\})|([\w, ]+)|(\* as \w+)) from )?".\/([\w\-\/]+)"/gm;
// const regex = /^import (((\{([\w, ]+)\})|([\w, ]+)|(\* as \w+)) from )?\".\/([\w\-\/]+)\"/gm;
// const regex = /^import (((\{([\w, ]+)\})|([\w, ]+)|(\* as \w+)) from )?\"(.\/)?([@\w\-\/]+)\"/gm; // @ + (./)
// const regex = /^import (((\{([\w, \$]+)\})|([\w, ]+)|(\* as [\w\$]+)) from )?["'](.?.\/)?([@\w\-\/\.]+)["']/gm; // '"
// const regex = /^import (((\{([\w,\s\$]+)\})|([\w, ]+)|(\* as [\w\$]+)) from )?["'](.?.\/)?([@\w\-\/\.]+)["'];?/gm; // '"
const namedImportsExpRegex = /^import ((((?<_D>\w+, )?\{([\w,\s\$]+)\})|([\w, ]+)|(\* as [\w\$]+)) from )?["'](.?.\/)?([@\w\-\/\.]+)["'];?/gm; // '"
// in the regex possible bug is if the `default` will be placed after named imports (`import {a, b}, d from "a"`)(to fix)
// const { encodeLine, decodeLine } = require("./__map");
/**
* @typedef {{
* root?: string;
* _needMap?: boolean | 1;
* extract: {
* names?: string[],
* default?: string
* },
* isEsm?: boolean
* }} SealingOptions
*
* /// UNDER QUESTION:
* onTreeShake?: (skiped?: boolean) => void
*/
/**
* @type {{
* sameAsImport: 'as esm import',
* doNothing?: 'do nothing'
* }}
*
* inlineTo?: 'inline to script',
* applyAndInline?: 'apply and inline',
*/
const requireOptions = {
sameAsImport: 'as esm import', // default for all node_modules
// asDynamic: 'as dynamic w await import', // not inside node_modules/
doNothing: 'do nothing'
};
const fastShaker = {};
// /**
// * @type {{
// * ModuleNotFound: {
// * doNothing: 0,
// * useDefaultHandler: 1,
// * raiseError: 2
// * }
// * }}
// */
// export const OnErrorActions = {
// ModuleNotFound: {
// doNothing: 0,
// useDefaultHandler: 1,
// raiseError: 2
// }
// }
/**
* @typedef {[number, number, number, number, number?]} VArray
* @typedef {import("fs").PathOrFileDescriptor} PathOrFileDescriptor
*/
let startWrapLinesOffset = 1;
let endWrapLinesOffset = 5;
var rootOffset = 0;
/**
* @description expoerted files for uniqie control inside getContent
* @type {string[]}
*/
var exportedFiles = [];
let logLinesOption = false;
let incrementalOption = false;
/**
* @type {Importer}
*/
let importer = null;
// exports = {
// default: combine,
// build: combine,
// combine: combine,
// integrate,
// }
/**
* @description preapare (remove lazy, prepare options) and build content under rootPath and as per options (applyes importInserts into content)
* @param {string} content - source code content;
* @param {string} rootPath - path to root of source directory name (required for sourcemaps etc)
* @param {BuildOptions & {targetFname?: string}} options - options
* @param {Function?} [onSourceMap=null] - onSourceMap
* @return {string} code with imported involves
*/
function combineContent(content, rootPath, options, onSourceMap) {
globalOptions = options;
globalOptions.advanced?.treeShake && (theShaker.globalOptions = globalOptions);
globalOptions.target = options.targetFname;
const originContent = content;
/// initial global options:
rootOffset = 0;
sourcemaps.splice(0, sourcemaps.length);
Object.keys(modules).forEach(key => delete modules[key]);
logLinesOption = options.logStub;
incrementalOption = options.advanced ? options.advanced.incremental : false;
if (incrementalOption) {
// look up
startWrapLinesOffset = 3; // start_WrapLinesOffset + 2
endWrapLinesOffset = 8; // end_WrapLinesOffset + 3
}
exportedFiles = [];
if (options.purgeDebug) {
if (options.sourceMaps || options.getSourceMap) {
console.warn('\x1B[33m' + 'removeLazy option uncompatible with sourceMap generation now. Therefore it`s passed' + '\x1B[0m');
options.sourceMaps = null;
options.getSourceMap = null;
}
content = cleaningDebugBlocks(content);
}
content = importInsert(content, rootPath, options);
content = mapGenerate({
target: options.targetFname,
options,
originContent,
content,
// cachedMap: mapping
});
// here plugins
if (options.advanced && options.advanced.ts) {
// exportedFiles.some(w => w.endsWith('.ts') || w.endsWith('.tsx'))
// sourcemaps for ts is not supported now
content = options.advanced.ts(content);
}
console.log(`\n\x1b[34mIn total handled ${statHolder.importsAmount} imports\x1b[0m`);
globalOptions.advanced?.debug && console.log(`\x1b[34m- ${statHolder.exports.cjs} cjs exports is found\x1b[0m`);
statHolder.imports = 0;
statHolder.requires = 0;
statHolder.exports.cjs = 0;
return content;
}
/**
*
* @param {string} entrypoint - file name
* @param {string} target - target name
* @param {Omit<BuildOptions, 'entryPoint'> & {entryPoint?: string}} options - options
* @returns
*/
function buildFile(entrypoint, target, options) {
const timeSure = "File \x1B[32m\"" + target + "\"\x1B[33m built in";
console.time(timeSure);
const originContent = fs.readFileSync(entrypoint).toString();
const srcFileName = path.resolve(entrypoint);
const targetFname = target || path.parse(srcFileName).dir + path.sep + path.parse(srcFileName).name + '.js';
const buildOptions = Object.assign(
{
entryPoint: path.basename(srcFileName),
release: false,
targetFname
},
options
);
try {
var legacyFiles = fs.readdirSync ? fs.readdirSync(path.dirname(buildOptions['targetFname'])) : null;
}
catch (er) {
console.warn(`Target dir "${buildOptions['targetFname']}" does not exists. It'll be autocreated.`);
fs.mkdirSync(path.dirname(buildOptions['targetFname']));
}
// let mapping = null;
let content = combineContent(originContent, path.dirname(srcFileName), buildOptions
// function onSourceMap() {
// // sourcemaps adds to content with targetName
// mapping = sourcemaps.map(s => s.debugInfo).reduce((p, n) => p.concat(n));
// mapping.push(null); // \n//# sourceMappingURL=${path.basename(to)}.map`
// return mapping;
// }
);
// content = mapGenerate({
// target: targetFname,
// options,
// originContent,
// content,
// cachedMap: mapping
// });
if (legacyFiles) legacyFiles.forEach(file => (path.extname(file) == '.js') && fs.rmSync(path.join(path.dirname(targetFname), file)));
fs.writeFileSync(targetFname, content);
console.log('\x1B[33m');
console.timeEnd(timeSure);
console.log('\x1B[0m');
// console.log(benchStore.toString())
// console.table(benchStore)
// console.table(Object.fromEntries(Object.entries(benchStore).filter(([k, v]) => !k.startsWith('bound'))))
// console.table(Object.fromEntries(Object.entries(benchStore).reverse()))
return content
}
/**
* path manager
*/
class PathMan {
/**
* used for static imports inside dynamic imports (TODO check it (on purp perf optimization): why not startsWith condition applied for this in getContext?)
* @legacy
* @type {string}
*/
basePath
/**
* @type {Importer?}
*/
importer
/*
* @description keep links (on symlinks) to modules
* @TODO use instead of importer.linkedModulePaths
*/
linkedModules = []
/**
* @param {string} dirname
* @param { (fileName: PathOrFileDescriptor) => string} pullContent
*/
constructor(dirname, pullContent) {
/**
* root directory of source code (not project path. it's different)
*/
this.dirPath = dirname;
/**
*
*/
this.getContent = pullContent || getContent;
}
}
class Importer extends AbstractImporter {
/**
* @type {PathMan}
*/
pathMan
/**
*
* @param {PathMan} pathMan
*/
constructor(pathMan) {
super();
// this.namedImportsApply = applyNamedImports;
this.namedImportsApply = namedImportsApply;
/*
* module sealing ()
*/
this.moduleStamp = moduleSealing;
this.pathMan = pathMan;
this.isFastShaking = typeof globalOptions.advanced?.treeShake === 'object' && globalOptions.advanced?.treeShake.method == 'surface';
pathMan.importer = this;
}
/**
* @description call moduleSealing and generate sourcemaps for it
* @returns {boolean}
* @param {string} fileName
* @param {string} fileStoreName,
* @param {SealingOptions} args
*/
attachModule(fileName, fileStoreName, { root, _needMap, extract }) {
this.progressFilesStack.push(fileName);
let moduleInfo = this.moduleStamp(fileName, { root: root || undefined, _needMap, extract });
this.progressFilesStack.pop();
if (moduleInfo) {
// .slice(moduleInfo.wrapperLinesOffset) =>? .slice(moduleInfo.wrapperLinesOffset, -5?) -> inside moduleSealing
const linesMap = moduleInfo.lines.map(([moduleInfoLineNumber, isEmpty], /** @type {number} */ i) => {
/**
номер столбца в сгенерированном файле (#2);
индекс исходника в «sources» (#3);
номер строки исходника (#4);
номер столбца исходника (#5);
индекс имени переменной/функции из списка «names»;
*/
/**
* @type {string|unknown}
* TODO check type (string or boolean)
* */
let lineValue = isEmpty;
if (i >= (moduleInfo.lines.length - endWrapLinesOffset) || i < startWrapLinesOffset) {
return null;
}
/** @type {VArray | Array<VArray>} */
let r = _needMap === 1
? [].map.call(lineValue, (/** @type {any} */ ch, /** @type {any} */ i) => [i, (sourcemaps.length - 1) + 1, moduleInfoLineNumber - startWrapLinesOffset, i]) // i + 1
: [[0, (sourcemaps.length - 1) + 1, moduleInfoLineNumber - startWrapLinesOffset, 1]];
return r;
});
sourcemaps.push({
name: fileStoreName.replace('$$', '@').replace(/(\$|__)/g, '/') + '.js',
// mappings: linesMap.map(line => line ? encodeLine(line) : '').join(';'),
//@ts-ignore (TODO fix type)
debugInfo: linesMap
});
return true;
}
return false;
}
/**
*
* @param {SealingOptions} options
* @param {(name: string) => boolean} inspectUnique
* @returns
*/
generateConverter(options, inspectUnique) {
const { root, _needMap, extract } = options;
// TODO fix `import pTimeout, { TimeoutError } from 'p-timeout'`
return (match, __, $, $$, _defauName, /** @type {string} */ classNames, defauName, moduleName, isrelative, fileName, offset, source) => {
if (!options.isEsm) options.isEsm = true;
if (_defauName) {
defauName = _defauName.match(/[\w_\d\$]+/)[0];
}
statHolder.imports += 1;
let rawNamedImports = classNames?.split(',');
if (classNames && globalOptions.advanced?.treeShake && extract?.names) {
//TODO insert before this the first algorithm to remove unused export const name = {} ... (cause of export may not used)
/// tree shakes expressions generated from `export * from '...'` (just for named)
// - ((removes if import is unused for export and at source code -> remove all import at all))
// - does not tree shake (does not remove) nothing at all if at least one of the imports is used inside code (usefull just for reexport how it have said)
const namesRequired = new Set(extract.names);
var _imports = rawNamedImports?.map(w => w.trim().split(' as '));
const _exports = _imports.map(names => names.slice().pop());
var requiredExports = _exports.filter(name => {
if (namesRequired.has(name)) return true
else {
// check on using:
// const _matched = source.replace(match, '').match(new RegExp(`\\b${name}\\b`), ''); // confuse: Uppy is found in filename import before
const _matched = source.slice(offset + match.length).match(new RegExp(`\\b${name}\\b`), '');
if (_matched) {
// debugger
return true;
}
else {
rawNamedImports = rawNamedImports.filter(named => !named.trimEnd().endsWith(name)); // to content: ;
_imports = rawNamedImports?.map(w => w.trim().split(' as ')); // to nested extract
return false;
}
}
});
if (!requiredExports.length && globalOptions.advanced?.treeShake) {
return `// ==> "${fileName}" has shaken`
}
}
const fileStoreName = this.attachFile(fileName, isrelative, {
extract: {
names: _imports?.map(names => names.slice()[0]) || rawNamedImports?.map(w => w.trim().split(' ')[0]),
default: defauName
}, root, _needMap
});
/// replace imports to spreads into place:
if (defauName && inspectUnique(defauName)) {
return `const { default: ${defauName} } = $${fileStoreName.replace('@', '_')}Exports;`;
}
else if (defauName) {
const error = new Error(`Variable '${defauName}' is duplicated by import './${fileName}.js'`);
error.name = 'DublicateError';
// throw error;
// console.log('\x1b[31m%s\x1b[0m', `${error.name}: ${error.message}`, '\x1b[0m');
console.log('\x1b[31m%s\x1b[0m', `Detected ${error.name} during build process: ${error.message}`, '\x1b[0m');
console.log('Fix the errors and restart the build.');
process.exit(1);
}
else if (moduleName) {
return `const ${moduleName.split(' ').pop()} = $${fileStoreName.replace('@', '_')}Exports;`;
}
else {
// TODO optimize:
let entities = rawNamedImports.map(w => {
if (~w.indexOf(' as ')) {
const importStruct = w.trim().split(' ');
// var _impexp = (`${importStruct.pop()}: ${importStruct[0]}`)
var _impexp = (`${importStruct[0]}: ${importStruct.pop()}`);
return _impexp.trim()
}
return w;
});
for (let entity of entities) {
if (~entity.indexOf(':')) {
entity = entity.split(': ').pop();
}
inspectUnique(entity);
}
return `const { ${entities.join(', ')} } = $${fileStoreName.replace('@', '_')}Exports`;
}
};
}
/**
* @param {string} fileName
* @param {string} isrelative
* @param {SealingOptions} params
*/
attachFile(fileName, isrelative, { root, _needMap, extract} ) {
const _filename = path.extname(fileName)
? fileName.slice(0, -path.extname(fileName).length)
// : fileName.replace(/\.\.\//g, '')
: fileName; // .replace(/\.\.\//g, './')
// const _root = root