@ices/locale-webpack-plugin
Version:
webpack plugin for parsing locale files
162 lines • 6.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDeclarations = exports.getModuleDetails = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const utils_1 = require("./utils");
// 确保模块依赖被正确声明
function ensureDependencies(moduleName, version) {
const pkgPath = path_1.default.resolve('package.json');
const pkgModule = require(pkgPath);
const { dependencies = {}, devDependencies = {} } = pkgModule;
let needUpdate = false;
let depsVersion;
if ((depsVersion = devDependencies[moduleName])) {
delete devDependencies[moduleName];
needUpdate = true;
}
if (!dependencies[moduleName]) {
dependencies[moduleName] = depsVersion || `^${version}`;
needUpdate = true;
}
if (!pkgModule.dependencies) {
pkgModule.dependencies = dependencies;
}
if (needUpdate) {
(0, utils_1.writeFileSync)(pkgPath, JSON.stringify(pkgModule, null, 2));
}
}
// 追加引用声明到工程的types声明文件
// 如果工程没有在代码里导入模块包,tsc不会去找已经在package.json里声明了的模块
// 只有在代码里导入了模块,tsc才会根据依赖解析规则去找声明文件
// 所以,这里还是需要把声明引用添加到工程的声明文件中去
function appendReferenceToProject(moduleName) {
const cwd = fs_1.default.realpathSync(process.cwd());
if (cwd === (0, utils_1.getSelfContext)()) {
return;
}
const typesPath = ensureFileHelper(['src/react-app-env.d.ts', 'src/types.d.ts'], cwd, false);
if (typesPath) {
const refCode = `/// <reference types="${moduleName}" />`;
const content = fs_1.default.readFileSync(typesPath, 'utf8');
if (!new RegExp(`^\s*${(0, utils_1.escapeRegExpCharacters)(refCode)}\s*$`, 'm').test(content)) {
(0, utils_1.writeFileSync)(typesPath, `${refCode}\n${content}`);
}
}
}
// 追加引用声明到Lib的types声明文件
function appendReferenceToLib(moduleDetails, declarationFile) {
const { packageModule, context } = moduleDetails;
const { types, typings } = packageModule;
// 查找声明文件
const typesPath = ensureFileHelper([types, typings, 'index.d.ts'], context);
// 追加资源模块声明引用
const refPath = (0, utils_1.normalizePath)(path_1.default.join(context, declarationFile), path_1.default.dirname(typesPath));
const refCode = `/// <reference path="${refPath}" />`;
const content = fs_1.default.readFileSync(typesPath, 'utf8');
if (!new RegExp(`^\s*${(0, utils_1.escapeRegExpCharacters)(refCode)}\s*$`, 'm').test(content)) {
(0, utils_1.writeFileSync)(typesPath, `${refCode}\n${content}`);
}
// 同步types声明
if (!(0, utils_1.isSamePath)(typesPath, packageModule.types, context)) {
packageModule.types = (0, utils_1.normalizePath)(typesPath, context);
(0, utils_1.writeFileSync)(path_1.default.join(context, 'package.json'), JSON.stringify(packageModule, null, 2));
}
}
// 检查文件路径列表,并确保存在至少一个文件(非目录)
// 最后一个文件会被创建,如果所有路径都不存在的话
function ensureFileHelper(paths, context, createLast = true) {
let file;
const tests = [...paths];
while ((file = tests.shift())) {
if (typeof file === 'string') {
const filePath = path_1.default.join(context, file);
if (fs_1.default.existsSync(filePath) && !fs_1.default.statSync(filePath).isDirectory()) {
return filePath;
}
if (!tests.length && createLast) {
// 最后一个文件了,还不存在,创建这个文件
(0, utils_1.writeFileSync)(filePath, '');
return filePath;
}
}
}
return '';
}
// 资源模块导出代码
function getResourceModuleCode(ext, declarationExports) {
return ('\n' +
`declare module ${JSON.stringify(`*${ext.startsWith('.') ? '' : '.'}${ext}`)} {\n${declarationExports}\n}\n`);
}
// 解析模块包描述文件路径
function resolveModulePackage(name) {
const cwd = fs_1.default.realpathSync(process.cwd());
const selfDir = (0, utils_1.getSelfContext)();
let pkgPath = '';
try {
// 从当前工作目录解析依赖包
pkgPath = require.resolve(name, { paths: [cwd] });
}
catch (e) {
if (selfDir && cwd !== selfDir) {
// 从自身模块目录解析依赖包
// 模块自测时需要在当前模块下引入依赖包
try {
pkgPath = require.resolve(name, { paths: [selfDir] });
}
catch (e) {
throw new Error(`Can not resolve module path of ${name}`);
}
}
}
return pkgPath;
}
/**
* 获取Locale组件模块的详情
* @param name 模块名称
*/
function getModuleDetails(name) {
// 解析模块的包描述文件路径
const pkgPath = resolveModulePackage(`${name}/package.json`);
const context = path_1.default.dirname(pkgPath);
const packageModule = require(pkgPath);
const loaderPath = ensureFileHelper([packageModule.loader, 'loader.js', 'lib/loader.js'], context, false);
if (!loaderPath) {
throw new Error(`Can not get loader of module ${name}`);
}
return {
name,
context,
packageModule,
loaderModule: require(loaderPath),
};
}
exports.getModuleDetails = getModuleDetails;
/**
* 创建资源模块的类型声明文件。
* @param moduleDetails 可用于处理资源模块的Lib模块详情。
* @param extensions 支持的资源类型后缀名称。
* @param targetFile 类型声明文件的路径名称(相对于Lib模块根目录)。
*/
function createDeclarations(moduleDetails, extensions, targetFile) {
const { loaderModule, packageModule, context, name } = moduleDetails;
const { getModuleExports } = loaderModule;
if (typeof getModuleExports !== 'function') {
throw new Error(`Can not find the export method named by getModuleExports for ${name}`);
}
const declarationExports = getModuleExports({});
if (typeof declarationExports !== 'string') {
throw new Error(`Module exports declaration of ${name} is not a string value`);
}
const declarationCodes = [];
for (const ext of extensions) {
declarationCodes.push(getResourceModuleCode(ext, declarationExports));
}
(0, utils_1.writeFileSync)(path_1.default.join(context, targetFile), declarationCodes.join(''));
appendReferenceToLib(moduleDetails, targetFile);
ensureDependencies(name, packageModule.version);
appendReferenceToProject(name);
}
exports.createDeclarations = createDeclarations;
//# sourceMappingURL=module.js.map