UNPKG

mp-lens

Version:

微信小程序分析工具 (Unused Code, Dependencies, Visualization)

176 lines 7.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WXMLParser = void 0; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Could not find a declaration file for module '@wxml/parser' const parser_1 = require("@wxml/parser"); const debug_logger_1 = require("../utils/debug-logger"); const wxml_path_1 = require("../utils/wxml-path"); /** * Parser for WXML files that finds dependencies to other files using AST parsing. * * Path resolution rules for WeChat Mini Program WXML files: * 1. Paths starting with '/' are relative to the mini program root * Example: <import src="/templates/header.wxml" /> * * 2. Paths starting with './' or '../' are relative to the current file's directory * Example: <import src="../templates/header.wxml" /> * * 3. Paths with no prefix (like "templates/header.wxml") should be treated as relative * to the current file's directory, equivalent to adding a './' prefix. * This parser automatically adds the './' prefix to follow Mini Program conventions. */ class WXMLParser { constructor() { // No dependencies needed for pure text analysis } async parse(content, filePath) { try { const dependencies = new Set(); // Parse WXML content to AST const ast = (0, parser_1.parse)(content); this.processImportIncludeTags(ast, dependencies); this.processWxsTags(ast, dependencies); this.processImageSources(ast, dependencies); // NOTE: processCustomComponents is intentionally omitted as component // dependencies are defined in JSON files. return Array.from(dependencies); } catch (e) { debug_logger_1.logger.warn(`Error parsing WXML file ${filePath}: ${e.message}`); throw e; // Re-throw } } /** * Processes import and include tags to extract template dependencies */ processImportIncludeTags(ast, dependencies) { this.findImportIncludeTags(ast, (path) => { const normalizedPath = (0, wxml_path_1.normalizeWxmlImportPath)(path); debug_logger_1.logger.debug(`Found import/include: ${path} -> normalized: ${normalizedPath}`); dependencies.add(normalizedPath); }); } /** * Processes wxs tags to extract WXS script dependencies */ processWxsTags(ast, dependencies) { this.findWxsTags(ast, (path) => { const normalizedPath = (0, wxml_path_1.normalizeWxmlImportPath)(path); debug_logger_1.logger.debug(`Found wxs: ${path} -> normalized: ${normalizedPath}`); dependencies.add(normalizedPath); }); } /** * Processes image tags to extract image dependencies */ processImageSources(ast, dependencies) { this.findImageTags(ast, (src) => { // Skip data URIs, remote URLs, and template expressions if (src.startsWith('data:') || /^(http|https):\/\//.test(src) || /{{.*?}}/.test(src)) { return; } const normalizedPath = (0, wxml_path_1.normalizeWxmlImportPath)(src); debug_logger_1.logger.debug(`Found image: ${src} -> normalized: ${normalizedPath}`); dependencies.add(normalizedPath); }); } /** * Recursively finds import and include tags in the AST */ findImportIncludeTags(ast, callback) { var _a; if (ast.type === 'WXElement' && (ast.name === 'import' || ast.name === 'include')) { // Find src attribute from startTag.attributes const attrs = (_a = ast.startTag) === null || _a === void 0 ? void 0 : _a.attributes; if (attrs && Array.isArray(attrs)) { const srcAttr = attrs.find((attr) => attr.key === 'src'); if (srcAttr && srcAttr.value) { callback(srcAttr.value); } } } // Recursively process children if (ast.type === 'WXElement' && Array.isArray(ast.children)) { for (const child of ast.children) { this.findImportIncludeTags(child, callback); } } // Handle Program/body if (ast.type === 'Program' && Array.isArray(ast.body)) { for (const node of ast.body) { this.findImportIncludeTags(node, callback); } } } /** * Recursively finds wxs tags in the AST */ findWxsTags(ast, callback) { var _a, _b; // Handle WXScript (wxs tags) if (ast.type === 'WXScript' && ast.name === 'wxs') { // Find src attribute from startTag.attributes const attrs = (_a = ast.startTag) === null || _a === void 0 ? void 0 : _a.attributes; if (attrs && Array.isArray(attrs)) { const srcAttr = attrs.find((attr) => attr.key === 'src'); if (srcAttr && srcAttr.value) { callback(srcAttr.value); } } } // Also handle WXElement in case wxs is parsed as a regular element if (ast.type === 'WXElement' && ast.name === 'wxs') { // Find src attribute from startTag.attributes const attrs = (_b = ast.startTag) === null || _b === void 0 ? void 0 : _b.attributes; if (attrs && Array.isArray(attrs)) { const srcAttr = attrs.find((attr) => attr.key === 'src'); if (srcAttr && srcAttr.value) { callback(srcAttr.value); } } } // Recursively process children if (ast.type === 'WXElement' && Array.isArray(ast.children)) { for (const child of ast.children) { this.findWxsTags(child, callback); } } // Handle Program/body if (ast.type === 'Program' && Array.isArray(ast.body)) { for (const node of ast.body) { this.findWxsTags(node, callback); } } } /** * Recursively finds image tags in the AST */ findImageTags(ast, callback) { var _a; if (ast.type === 'WXElement' && ast.name === 'image') { // Find src attribute from startTag.attributes const attrs = (_a = ast.startTag) === null || _a === void 0 ? void 0 : _a.attributes; if (attrs && Array.isArray(attrs)) { const srcAttr = attrs.find((attr) => attr.key === 'src'); if (srcAttr && srcAttr.value) { callback(srcAttr.value); } } } // Recursively process children if (ast.type === 'WXElement' && Array.isArray(ast.children)) { for (const child of ast.children) { this.findImageTags(child, callback); } } // Handle Program/body if (ast.type === 'Program' && Array.isArray(ast.body)) { for (const node of ast.body) { this.findImageTags(node, callback); } } } } exports.WXMLParser = WXMLParser; //# sourceMappingURL=wxml-parser.js.map