react-imported-component
Version:
I will import your component, and help to handle it
140 lines (139 loc) • 9 kB
JavaScript
/* 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();
}