UNPKG

react-imported-component

Version:
140 lines (139 loc) 9 kB
/* tslint:disable no-console */ import { __assign, __awaiter, __generator } from "tslib"; import { existsSync } from 'fs'; import { dirname, extname, resolve } from 'path'; // @ts-ignore import scanDirectory from 'scan-directory'; import { CLIENT_SIDE_ONLY } from '../configuration/constants'; import { getFileContent, getMatchString, getRelative, normalizePath, pWriteFile } from './shared'; var RESOLVE_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx', '.mjs']; var trimImport = function (str) { return str.replace(/['"]/g, ''); }; var getImportMatch = getMatchString("(['\"]?[\\w-/.@]+['\"]?)\\)", 1); var getImports = function (str) { return getImportMatch(str // remove comments .replace(/\/\*([^\*]*)\*\//gi, '') .replace(/\/\/(.*)/gi, '') // remove new lines .replace(/\n/gi, '') // remove spaces? .replace(/[\s]+\)/i, ')')); }; var getComment = getMatchString(/\/\*.*\*\//, 0); var getChunkName = getMatchString('webpackChunkName: "([^"]*)"', 1); var clientSideOnly = function (comment) { return comment.indexOf(CLIENT_SIDE_ONLY) >= 0; }; var clearComment = function (str) { return str.replace('webpackPrefetch: true', '').replace('webpackPreload: true', ''); }; var getImportString = function (pattern, selected) { return function (str) { return getMatchString(pattern, selected)(str).map(function (statement) { return { name: trimImport(getImports(statement + ')')[0] || ''), comment: clearComment(getComment(statement)[0] || ''), }; }); }; }; export var getDynamicImports = getImportString("import[\\s]?\\((([^)])+['\"]?)\\)", 1); export var cleanFileContent = function (content) { var mapping = []; // wrap var wrapped = content.replace(new RegExp("import[\\s]?\\((([^)])+['\"]?)\\)", 'g'), function (match) { var placement = mapping.push(match) - 1; return "imported_" + placement + "_replacement"; }); var cleaned = wrapped.replace(new RegExp('//.*', 'g'), '').replace(new RegExp('\\/\\*[\\s\\S]*?\\*\\/', 'gm'), ''); var unwrapped = cleaned.replace(new RegExp('imported_([\\d]*)_replacement', 'g'), function (_, b) { return mapping[+b]; }); return unwrapped; }; var mapImports = function (file, imports) { return imports.map(function (dep) { var name = dep.name; if (name && name.charAt(0) === '.') { return __assign(__assign({}, dep), { file: file, name: resolve(dirname(file), name), doNotTransform: false }); } return __assign(__assign({}, dep), { file: file, doNotTransform: true }); }); }; var rejectSystemFiles = function (test) { return function (file, stats) { if (stats.isDirectory()) { return !test(file); } return false; }; }; var rejectNodeModulesAndDotFolders = function (file) { return !(file.match(/node_modules/) || file.match(/(\/\.\w+)/)); }; export var remapImports = function (data, root, targetDir, getRelativeName, imports, testImport, chunkName) { return data .map(function (_a) { var file = _a.file, content = _a.content; return mapImports(file, getDynamicImports(cleanFileContent(content))); }) .forEach(function (importBlock) { return importBlock.forEach(function (_a) { var name = _a.name, comment = _a.comment, doNotTransform = _a.doNotTransform, file = _a.file; var rootName = doNotTransform ? name : getRelativeName(root, name); var fileName = doNotTransform ? name : getRelativeName(targetDir, name); var sourceName = getRelativeName(root, file); if (testImport(rootName, sourceName)) { var isClientSideOnly = clientSideOnly(comment); var givenChunkName = getChunkName(comment)[0] || ''; var def = "[() => import(" + comment + "'" + fileName + "'), '" + ((chunkName && chunkName(rootName, sourceName, { chunkName: givenChunkName })) || givenChunkName) + "', '" + rootName + "', " + isClientSideOnly + "] /* from " + sourceName + " */"; var slot = getRelativeName(root, name); // keep the maximal definition imports[slot] = !imports[slot] ? def : imports[slot].length > def.length ? imports[slot] : def; } }); }); }; export function scanTop(root, start, target) { function scan() { return __awaiter(this, void 0, void 0, function () { var sourceDir, configurationFile, _a, _b, testFolder, _c, testFile, _d, testImport, chunkName, configuration, files, data, imports, targetDir; var _this = this; return __generator(this, function (_e) { switch (_e.label) { case 0: sourceDir = resolve(root, start); console.log('scanning', sourceDir, 'for imports...'); configurationFile = resolve(root, '.imported.js'); _a = existsSync(configurationFile) ? require(configurationFile) : {}, _b = _a.testFolder, testFolder = _b === void 0 ? rejectNodeModulesAndDotFolders : _b, _c = _a.testFile, testFile = _c === void 0 ? function () { return true; } : _c, _d = _a.testImport, testImport = _d === void 0 ? function () { return true; } : _d, chunkName = _a.chunkName, configuration = _a.configuration; return [4 /*yield*/, scanDirectory(sourceDir, undefined, rejectSystemFiles(testFolder))]; case 1: files = (_e.sent()) .filter(function (name) { return normalizePath(name).indexOf(target) === -1; }) .filter(function (name) { return RESOLVE_EXTENSIONS.indexOf(extname(name)) >= 0; }) .filter(function (name) { return testFile(name); }) .sort(); return [4 /*yield*/, Promise.all(files.map(function (file) { return __awaiter(_this, void 0, void 0, function () { var content; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, getFileContent(file)]; case 1: content = _a.sent(); return [2 /*return*/, { file: file, content: content, }]; } }); }); }))]; case 2: data = _e.sent(); imports = {}; targetDir = resolve(root, dirname(target)); remapImports(data, root, targetDir, getRelative, imports, testImport, chunkName); console.log(Object.keys(imports).length + " imports found, saving to " + target); pWriteFile(target, "\n /* eslint-disable */\n /* tslint:disable */\n \n // generated by react-imported-component, DO NOT EDIT \n import {assignImportedComponents} from 'react-imported-component/macro';\n " + (configuration && "import {setConfiguration} from 'react-imported-component/boot';\n// as configured in .imported.js\nsetConfiguration(" + JSON.stringify(configuration, null, 2) + ");\n ") + " \n \n // all your imports are defined here\n // all, even the ones you tried to hide in comments (that's the cost of making a very fast parser)\n // to remove any import from here\n // 1) use magic comment `import(/* client-side */ './myFile')` - and it will disappear\n // 2) use file filter to ignore specific locations (refer to the README - https://github.com/theKashey/react-imported-component/#server-side-auto-import)\n // 3) use .imported.js to control this table generation (refer to the README - https://github.com/theKashey/react-imported-component/#-imported-js)\n \n const applicationImports = assignImportedComponents([\n" + Object.keys(imports) .map(function (key) { return " " + imports[key] + ","; }) .sort() .join('\n') + "\n ]);\n \n export default applicationImports;\n \n // @ts-ignore\n if (module.hot) {\n // these imports would make this module a parent for the imported modules.\n // but this is just a helper - so ignore(and accept!) all updates\n \n // @ts-ignore\n module.hot.accept(() => null);\n } \n "); return [2 /*return*/]; } }); }); } return scan(); }