From 35172905274b98e2884174a3d06d333915c03a5d Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Fri, 17 Jan 2025 17:54:00 +0800 Subject: [PATCH 1/9] feat: update jscard package result: extract template and json while keeping sourcemap Signed-off-by: lileirjyb --- packages/hap-compiler/src/style/process.js | 2 +- packages/hap-compiler/src/style/validator.js | 2 +- packages/hap-compiler/src/template/exp.js | 10 +- packages/hap-compiler/src/template/index.js | 14 +- .../hap-compiler/src/template/validator.js | 107 ++++- .../src/loaders/ux-fragment-utils.js | 26 +- packages/hap-dsl-xvm/src/loaders/ux-loader.js | 9 +- packages/hap-packager/src/common/utils.js | 16 +- .../{lite-card-plugin.js => card-plugin.js} | 137 ++++-- .../src/plugins/card-script-handle-plugin.js | 186 ++++++++ packages/hap-packager/src/plugins/index.js | 4 +- .../src/plugins/remove-modules-plugin.js | 105 +++++ .../src/plugins/resource-plugin.js | 3 +- .../src/plugins/widget-fingerprint-plugin.js | 4 +- .../hap-packager/src/post-handler/index.js | 426 +----------------- .../src/post-handler/js-card-post.js | 297 ++++++++++++ .../src/post-handler/lite-card-post.js | 407 +++++++++++++++++ packages/hap-packager/src/signature/index.js | 2 +- .../hap-packager/src/subpackages/service.js | 3 +- packages/hap-packager/src/webpack.post.js | 10 +- packages/hap-shared-utils/src/index.js | 38 ++ packages/hap-toolkit/src/utils.js | 7 +- 22 files changed, 1277 insertions(+), 538 deletions(-) rename packages/hap-packager/src/plugins/{lite-card-plugin.js => card-plugin.js} (69%) create mode 100644 packages/hap-packager/src/plugins/card-script-handle-plugin.js create mode 100644 packages/hap-packager/src/plugins/remove-modules-plugin.js create mode 100644 packages/hap-packager/src/post-handler/js-card-post.js create mode 100644 packages/hap-packager/src/post-handler/lite-card-post.js diff --git a/packages/hap-compiler/src/style/process.js b/packages/hap-compiler/src/style/process.js index c21f3bdd..149b1c4d 100644 --- a/packages/hap-compiler/src/style/process.js +++ b/packages/hap-compiler/src/style/process.js @@ -141,7 +141,7 @@ function processImport(csscode, dir, log, depList) { * @param {String} filePath - 文件路径 * @param {Array} depFiles - 使用到的资源集合 */ -function processSingleClass(rule, jsonStyle, ruleResult, log, filePath, depFiles) { +function processSingleClass(rule, jsonStyle, ruleResult, log, filePath, depFiles, options) { rule.declarations.forEach(function (declaration) { const subType = declaration.type diff --git a/packages/hap-compiler/src/style/validator.js b/packages/hap-compiler/src/style/validator.js index 262cad8f..3a3c6e82 100755 --- a/packages/hap-compiler/src/style/validator.js +++ b/packages/hap-compiler/src/style/validator.js @@ -2672,7 +2672,7 @@ function validate(name, value, options) { const validator = validatorMap[name] if (typeof validator === 'function') { - if (typeof value !== 'function') { + if (typeof value !== 'function' && value.indexOf('function') < 0) { if (mightReferlocalResource(name)) { result = validator(value, options) } else { diff --git a/packages/hap-compiler/src/template/exp.js b/packages/hap-compiler/src/template/exp.js index ee5ac312..c5c86e15 100644 --- a/packages/hap-compiler/src/template/exp.js +++ b/packages/hap-compiler/src/template/exp.js @@ -35,7 +35,7 @@ function trimhtml(str) { * @param isLite is lite card * @returns {*} */ -function transExpr(expContent, toFunc, isLite) { +function transExpr(expContent, toFunc, isLite, isCard) { let ret const trimExpContent = expContent.trim() if (!textParser.isExpr(trimExpContent)) { @@ -64,8 +64,12 @@ function transExpr(expContent, toFunc, isLite) { ret = ret.join(' + ') if (toFunc !== false) { try { - /* eslint-disable no-eval */ - ret = eval('(function () {return ' + ret + '})') + if (isCard) { + ret = 'function () {return ' + ret + '}' + } else { + /* eslint-disable no-eval */ + ret = eval('(function () {return ' + ret + '})') + } /* eslint-enable no-eval */ } catch (err) { err.isExpressionError = true diff --git a/packages/hap-compiler/src/template/index.js b/packages/hap-compiler/src/template/index.js index 329db3e8..0e3f905b 100644 --- a/packages/hap-compiler/src/template/index.js +++ b/packages/hap-compiler/src/template/index.js @@ -128,9 +128,15 @@ function traverse(node, output, previousNode, conditionList, options) { if (name.match(/^model:/)) { // 解析model指令,model指令格式:model:name="{{youName}}" validator.checkModel(name, value, output, node, locationInfo, options) + if (output.isCard) { + throw new Error('卡片不支持 model 指令') + } } else if (name.match(/^dir:/)) { // 解析自定义指令,自定义指令格式:dir:指令名称="{{data}}" validator.checkCustomDirective(name, value, output, node) + if (output.isCard) { + throw new Error('卡片不支持自定义指令') + } } else { // 其余为普通属性 validator.checkAttr(name, value, output, node.tagName, locationInfo, options) @@ -362,7 +368,13 @@ function parse(source, options) { { treeAdapter: parse5.treeAdapters.default, locationInfo: true }, options.filePath ) - const output = { result: {}, log: [], depFiles: [], isLite: !!options.lite } + const output = { + result: {}, + log: [], + depFiles: [], + isCard: !!options.card, + isLite: !!options.lite + } // 模板为空或解析失败 /* istanbul ignore if */ diff --git a/packages/hap-compiler/src/template/validator.js b/packages/hap-compiler/src/template/validator.js index 4c747dc1..2723baf2 100644 --- a/packages/hap-compiler/src/template/validator.js +++ b/packages/hap-compiler/src/template/validator.js @@ -1420,7 +1420,13 @@ function checkTagName(node, output, options = {}) { */ function checkId(id, output) { if (id) { - output.result.id = exp.isExpr(id) ? exp(id, true, output.isLite) : id + const isLite = output.isLite + const isCard = output.isCard + output.result.id = exp.isExpr(id) ? exp(id, true, isLite, isCard) : id + output.result.idExpr = true + if (isCard && !isLite) { + output.result.idRaw = id + } } } @@ -1456,7 +1462,8 @@ function checkClass(className, output) { let classList = [] className = className.trim() - + const isLite = output.isLite + const isCard = output.isCard if (className) { let start = 0 let end = 0 @@ -1477,7 +1484,6 @@ function checkClass(className, output) { } segs.push(className.slice(start)) // trailing static classes - const isLite = output.isLite classList = segs.reduce((list, seg) => { if (exp.isExpr(seg)) { hasBinding = true @@ -1500,14 +1506,19 @@ function checkClass(className, output) { err.expression = className throw err } - output.result.class = className output.result.classList = classList } else if (hasBinding) { - const code = '(function () {return [' + classList.join(', ') + ']})' try { - /* eslint-disable no-eval */ - output.result.classList = eval(code) - /* eslint-enable no-eval */ + let code = '' + if (isCard) { + code = 'function () {return [' + classList.join(', ') + ']}' + output.result.classList = code + } else { + code = '(function () {return [' + classList.join(', ') + ']})' + /* eslint-disable no-eval */ + output.result.classList = eval(code) + /* eslint-enable no-eval */ + } } catch (err) { err.isExpressionError = true err.expression = className @@ -1520,6 +1531,12 @@ function checkClass(className, output) { ) } } + if (isCard) { + output.result.class = className + if (!isLite) { + output.result.classListRaw = className + } + } } /** @@ -1532,9 +1549,11 @@ function checkClass(className, output) { */ function checkStyle(cssText, output, locationInfo, options) { let style = {} + let styleRaw = {} const log = output.log if (cssText) { const isLite = output.isLite + const isCard = output.isCard if (exp.singleExpr(cssText)) { // 检测是否嵌套{{}} const incText = exp.removeExprffix(cssText) @@ -1545,9 +1564,12 @@ function checkStyle(cssText, output, locationInfo, options) { reason: 'ERROR: style 属性不能嵌套多层{{}}' }) } else { - style = exp(cssText, true, isLite) + style = exp(cssText, true, isLite, isCard) } output.result.style = style + if (isCard && !isLite) { + output.result.styleRaw = cssText + } return } // 如果是 a: {{}}; b: {{}};, 则分解处理 @@ -1563,13 +1585,18 @@ function checkStyle(cssText, output, locationInfo, options) { k = pair[0].trim() k = hyphenedToCamelCase(k) v = pair[1].trim() - v = exp(v, true, isLite) // 处理值表达式 + + const valueRaw = v + v = exp(v, true, isLite, isCard) // 处理值表达式 vResult = styler.validateDelaration(k, v, options) v = vResult.value v.forEach((t) => { // 如果校验成功,则保存转换后的属性值 if (isValidValue(t.v) || typeof t.v === 'function') { style[t.n] = t.v + if (isCard && !isLite) { + styleRaw[t.n] = valueRaw + } } }) if (vResult.log) { @@ -1590,6 +1617,9 @@ function checkStyle(cssText, output, locationInfo, options) { } } output.result.style = style + if (isCard && !isLite) { + output.result.styleRaw = styleRaw + } } } @@ -1604,9 +1634,14 @@ function checkIs(value, output, locationInfo) { if (value) { // 如果没有,补充上{{}} value = exp.addExprffix(value) + const isLite = output.isLite + const isCard = output.isCard // 将表达式转换为function - output.result.is = exp(value, true, output.isLite) + output.result.is = exp(value, true, isLite, isCard) + if (isCard && !isLite) { + output.result.isRaw = value + } } else { log.push({ line: locationInfo.line || 1, @@ -1628,6 +1663,7 @@ function checkIf(value, output, not, locationInfo, conditionList) { // 如果没有,补充上{{}} value = exp.addExprffix(value) const isLite = output.isLite + const isCard = output.isCard if (not) { value = '{{' + buildConditionExp(conditionList) + '}}' } else { @@ -1636,7 +1672,10 @@ function checkIf(value, output, not, locationInfo, conditionList) { conditionList.push(`${value.substr(2, value.length - 4)}`) } // 将表达式转换为function - output.result.shown = isLite ? value : exp(value, true) + output.result.shown = isLite ? value : exp(value, true, isLite, isCard) + if (isCard && !isLite) { + output.result.shownRaw = value + } } else { if (!not) { log.push({ @@ -1674,11 +1713,15 @@ function checkElif(value, cond, output, locationInfo, conditionList) { value = exp.addExprffix(value) cond = exp.addExprffix(cond) const isLite = output.isLite + const isCard = output.isCard newcond = '{{(' + value.substr(2, value.length - 4) + ') && ' + buildConditionExp(conditionList) + '}}' // 将表达式转换为function - output.result.shown = isLite ? newcond : exp(newcond) + output.result.shown = isLite ? newcond : exp(newcond, true, isLite, isCard) + if (isCard && !isLite) { + output.result.shownRaw = newcond + } conditionList.push(`${value.substr(2, value.length - 4)}`) } else { log.push({ @@ -1719,12 +1762,15 @@ function checkFor(value, output, locationInfo) { value = '{{' + value + '}}' const isLite = output.isLite - let repeat + const isCard = output.isCard + let repeat, repeatRaw if (!key && !val) { - repeat = exp(value, true, isLite) + repeat = exp(value, true, isLite, isCard) + repeatRaw = value } else { // 如果指定key,value - repeat = { exp: exp(value, true, isLite) } + repeat = { exp: exp(value, true, isLite, isCard) } + repeatRaw = { expRaw: value } if (key) { repeat.key = key } @@ -1733,6 +1779,9 @@ function checkFor(value, output, locationInfo) { } } output.result.repeat = repeat + if (isCard && !isLite) { + output.result.repeatRaw = repeatRaw + } } else { log.push({ line: locationInfo.line || 1, @@ -1775,11 +1824,15 @@ function checkEvent(name, value, output) { value = '{{' + funcName + '(' + params.join(',') + ')}}' try { // 将事件转换为函数对象 - /* eslint-disable no-eval */ - value = output.isLite - ? value - : eval('(function (evt) { return ' + exp(value, false).replace('this.evt', 'evt') + '})') - /* eslint-enable no-eval */ + if (output.isCard) { + value = 'function (evt) { return ' + exp(value, false).replace('this.evt', 'evt') + '}' + } else if (!output.isLite) { + /* eslint-disable no-eval */ + value = eval( + '(function (evt) { return ' + exp(value, false).replace('this.evt', 'evt') + '})' + ) + /* eslint-enable no-eval */ + } } catch (err) { err.isExpressionError = true err.expression = originValue @@ -1809,7 +1862,7 @@ function checkCustomDirective(name, value, output, node) { output.result.directives = output.result.directives || [] output.result.directives.push({ name: dirName, - value: exp.isExpr(value) ? exp(value, true, output.isLite) : value + value: exp.isExpr(value) ? exp(value, true, output.isLite, output.isCard) : value }) } @@ -1840,8 +1893,13 @@ function checkAttr(name, value, output, tagName, locationInfo, options) { value = resolvePath(value, options.filePath) output.depFiles.push(value) } + const isLite = output.isLite + const isCard = output.isCard output.result.attr = output.result.attr || {} - output.result.attr[hyphenedToCamelCase(name)] = exp(value, true, output.isLite) + output.result.attr[hyphenedToCamelCase(name)] = exp(value, true, isLite, isCard) + if (isCard && !isLite) { + output.result.attr[hyphenedToCamelCase(name) + 'Raw'] = value + } if (name === 'value' && tagName === 'text') { output.log.push({ line: locationInfo.line, @@ -1982,6 +2040,9 @@ function hasIfOrFor(nodes) { return flag } +/** + * 检查class数组是否为常量和变量混合的方式,如 "clazz1 {{myClass}}" + */ function isValidClassArray(arr) { const filterArr = arr.filter((clazz) => clazz.length > 0) diff --git a/packages/hap-dsl-xvm/src/loaders/ux-fragment-utils.js b/packages/hap-dsl-xvm/src/loaders/ux-fragment-utils.js index 0d95ce15..2f5cc9a3 100644 --- a/packages/hap-dsl-xvm/src/loaders/ux-fragment-utils.js +++ b/packages/hap-dsl-xvm/src/loaders/ux-fragment-utils.js @@ -263,12 +263,14 @@ function makeLoaderString(type, config, uxType) { * @param $loader * @param imports - 外部导入的组件列表 * @param importNames - 外部导入的组件名列表 - * @param {number} lite 1:轻卡; 0:普通卡 + * @param {number} card 1:卡片 + * @param {number} lite 1:轻卡 * @returns {string} */ -function processImportFrag($loader, imports, importNames, lite) { +function processImportFrag($loader, imports, importNames, card, lite) { let retStr = '' if (imports.length) { + const cardParam = card ? `&card=${card}` : '' const liteParam = lite ? `&lite=${lite}` : '' for (let i = 0; i < imports.length; i++) { const imp = imports[i] @@ -306,7 +308,7 @@ function processImportFrag($loader, imports, importNames, lite) { let reqStr = makeRequireString( $loader, makeLoaderString(FRAG_TYPE.IMPORT), - `${importSrc}?uxType=${ENTRY_TYPE.COMP}&name=${importName}${liteParam}` + `${importSrc}?uxType=${ENTRY_TYPE.COMP}&name=${importName}${cardParam}${liteParam}` ) if (compileOptionsObject.stats) { @@ -326,9 +328,10 @@ function processImportFrag($loader, imports, importNames, lite) { * @param templates * @param uxType * @param importNames - * @param {number} lite 1:轻卡; 0:普通卡 + * @param {number} card 1:卡片 + * @param {number} lite 1:轻卡 */ -function processTemplateFrag($loader, templates, uxType, importNames, lite) { +function processTemplateFrag($loader, templates, uxType, importNames, card, lite) { let retStr = '{}' if (!templates.length) { $loader.emitError(new Error('需要模板