UNPKG

@umijs/plugins

Version:
298 lines (295 loc) 9.74 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/utils/modelUtils.ts var modelUtils_exports = {}; __export(modelUtils_exports, { Model: () => Model, ModelUtils: () => ModelUtils, getNamespace: () => getNamespace, transformSync: () => transformSync }); module.exports = __toCommonJS(modelUtils_exports); var import_bundler_utils = require("@umijs/bundler-utils"); var parser = __toESM(require("@umijs/bundler-utils/compiled/babel/parser")); var import_traverse = __toESM(require("@umijs/bundler-utils/compiled/babel/traverse")); var t = __toESM(require("@umijs/bundler-utils/compiled/babel/types")); var import_esbuild = require("@umijs/bundler-utils/compiled/esbuild"); var import_fs = require("fs"); var import_path = require("path"); var import_plugin_utils = require("umi/plugin-utils"); var import_astUtils = require("./astUtils"); function transformSync(content, opts) { if (!opts.tsconfig && !opts.tsconfigRaw) { opts.tsconfigRaw = { compilerOptions: { experimentalDecorators: true } }; } return (0, import_esbuild.transformSync)(content, opts); } function getNamespace(absFilePath, absSrcPath) { const relPath = (0, import_plugin_utils.winPath)((0, import_path.relative)((0, import_plugin_utils.winPath)(absSrcPath), (0, import_plugin_utils.winPath)(absFilePath))); const parts = relPath.split("/"); const dirs = parts.slice(0, -1); const file = parts[parts.length - 1]; const validDirs = dirs.filter( (dir) => !["src", "pages", "models"].includes(dir) ); let normalizedFile = file; normalizedFile = (0, import_path.basename)(file, (0, import_path.extname)(file)); if (normalizedFile.endsWith(".model")) { normalizedFile = normalizedFile.split(".").slice(0, -1).join("."); } return [...validDirs, normalizedFile].join("."); } var Model = class { file; namespace; id; exportName; deps; constructor(file, absSrcPath, sort, id) { let namespace; let exportName; const [_file, meta] = file.split("#"); if (meta) { const metaObj = JSON.parse(meta); namespace = metaObj.namespace; exportName = metaObj.exportName; } this.file = _file; this.id = `model_${id}`; this.namespace = namespace || getNamespace(_file, absSrcPath); this.exportName = exportName || "default"; this.deps = sort ? this.findDeps(sort) : []; } findDeps(sort) { const content = (0, import_fs.readFileSync)(this.file, "utf-8"); const loader = (0, import_path.extname)(this.file).slice(1); const result = transformSync(content, { loader, sourcemap: false, minify: false }); const deps = /* @__PURE__ */ new Set(); const ast = parser.parse(result.code, { sourceType: "module", sourceFilename: this.file, plugins: [] }); sort; (0, import_traverse.default)(ast, { CallExpression: (path) => { if (t.isIdentifier(path.node.callee, { name: "useModel" }) && t.isStringLiteral(path.node.arguments[0])) { deps.add(path.node.arguments[0].value); } } }); return [...deps]; } }; var ModelUtils = class _ModelUtils { api; opts = {}; count = 1; constructor(api, opts) { this.api = api; this.opts = opts; } getAllModels(opts) { this.count = 1; const models = [ ...this.getModels({ base: (0, import_path.join)(this.api.paths.absSrcPath, "models"), pattern: "**/*.{ts,tsx,js,jsx}" }), ...this.getModels({ base: (0, import_path.join)(this.api.paths.absPagesPath), pattern: "**/models/**/*.{ts,tsx,js,jsx}" }), ...this.getModels({ base: (0, import_path.join)(this.api.paths.absPagesPath), pattern: "**/model.{ts,tsx,js,jsx}" }), ...opts.extraModels ].map((file) => { return new Model( file, this.api.paths.absSrcPath, opts.sort, this.count++ ); }); const namespaces = models.map((model) => model.namespace); if (new Set(namespaces).size !== namespaces.length) { throw new Error( `Duplicate namespace in models: ${namespaces.sort().join(", ")}` ); } if (opts.sort) { const namespaces2 = _ModelUtils.topologicalSort(models); models.sort( (a, b) => namespaces2.indexOf(a.namespace) - namespaces2.indexOf(b.namespace) ); } return models; } getModels(opts) { return import_plugin_utils.glob.sync(opts.pattern || "**/*.{ts,js}", { cwd: opts.base, absolute: true }).map(import_plugin_utils.winPath).filter((file) => { if (/\.d.ts$/.test(file)) return false; if (/\.(test|e2e|spec).([jt])sx?$/.test(file)) return false; const content = (0, import_fs.readFileSync)(file, "utf-8"); return this.isModelValid({ content, file }); }); } isModelValid(opts) { var _a; const { file, content } = opts; if (this.opts.contentTest && this.opts.contentTest(content)) { return true; } let result = null; try { const ext = (0, import_path.extname)(file).slice(1); const loader = ext === "js" ? "jsx" : ext; result = transformSync(content, { loader, sourcemap: false, minify: false, sourcefile: file }); } catch (e) { if ((_a = e.errors) == null ? void 0 : _a.length) { (0, import_bundler_utils.prettyPrintEsBuildErrors)(e.errors, { path: file, content }); delete e.errors; } throw e; } let ret = false; const ast = parser.parse(result.code, { sourceType: "module", sourceFilename: file, plugins: [] }); (0, import_traverse.default)(ast, { ExportDefaultDeclaration: (path) => { let node = path.node.declaration; node = (0, import_astUtils.getIdentifierDeclaration)(node, path); if (this.opts.astTest && this.opts.astTest({ node, content })) { ret = true; } } }); return ret; } // https://github.com/umijs/umi/issues/9837 static topologicalSort = (models) => { const graph = []; const namespaceToNode = {}; models.forEach((model, index) => { const node = { namespace: model.namespace, deps: model.deps, index, in: 0, childs: [] }; if (namespaceToNode[model.namespace]) { throw new Error(`Duplicate namespace in models: ${model.namespace}`); } namespaceToNode[model.namespace] = node; graph.push(node); }); graph.forEach((node) => { node.deps.forEach((dep) => { const depNode = namespaceToNode[dep]; if (!depNode) { throw new Error(`Model namespace not found: ${dep}`); } depNode.childs.push(node); node.in++; }); }); const queue = []; while (true) { const zeronode = graph.find((n) => { return n && n.in === 0; }); if (!zeronode) { break; } queue.push(zeronode.namespace); zeronode.childs.forEach((child) => { child.in--; }); zeronode.childs = []; delete graph[zeronode.index]; } const leftNodes = graph.filter(Boolean); if (leftNodes.length > 0) { throw new Error( `Circle dependency detected in models: ${leftNodes.map((m) => import_plugin_utils.chalk.red(m.namespace)).join(", ")}` ); } return queue; }; static getModelsContent(models) { const imports = []; const modelProps = []; models.forEach((model) => { const fileWithoutExt = (0, import_plugin_utils.winPath)( (0, import_path.format)({ dir: (0, import_path.dirname)(model.file), base: (0, import_path.basename)(model.file, (0, import_path.extname)(model.file)) }) ); if (model.exportName !== "default") { imports.push( `import { ${model.exportName} as ${model.id} } from '${fileWithoutExt}';` ); } else { imports.push(`import ${model.id} from '${fileWithoutExt}';`); } modelProps.push( `${model.id}: { namespace: '${model.namespace}', model: ${model.id} },` ); }); return ` ${imports.join("\n")} export const models = { ${modelProps.join("\n")} } as const`; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Model, ModelUtils, getNamespace, transformSync });