From 8e624224f7df899de8d056664fce0948af01b630 Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Wed, 4 Dec 2024 09:49:02 +0800 Subject: [PATCH 01/10] feat: add support for theme style Signed-off-by: lileirjyb --- packages/hap-compiler/src/style/validator.js | 42 +++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/hap-compiler/src/style/validator.js b/packages/hap-compiler/src/style/validator.js index 793a052c..262cad8f 100755 --- a/packages/hap-compiler/src/style/validator.js +++ b/packages/hap-compiler/src/style/validator.js @@ -235,6 +235,29 @@ const REGEXP_CUBIC_BEZIER = const REGEXP_STEPS = /steps\(\s*(\d+)\s*(?:,\s*(jump-start|jump-end|jump-none|jump-both|start|end))?\)/ +const wrapperCached = new Map() +/** + * 封装一个校验器,使其接受 theme. 开头的变量值 + * + * @param {Function} validator - 校验器 + * @returns {Function} + */ +function builtInVarsWrapper(validator) { + let cached = wrapperCached.get(validator) + if (!cached) { + cached = function wrappedValidator() { + const result = validator.apply(null, arguments) + if (!result.value && arguments[0].startsWith('theme.')) { + result.value = arguments[0] + result.reason = undefined + } + return result + } + wrapperCached.set(validator, cached) + } + return cached +} + function toCamelCase(str) { var re = /-(\w)/g return str.replace(re, function ($0, $1) { @@ -2377,6 +2400,21 @@ const validator = { } } +/** + * 为各个 validator 加上放行 theme 开头属性校验器 + */ +function addBuiltInVarsWrapper() { + for (const key in validator) { + const validatorFn = validator[key] + const noNeed = ['arraynumber', 'arraylength', 'arraycolor', 'arraycolorstop', 'enum'] + if (typeof validatorFn === 'function' && noNeed.indexOf(key) === -1) { + validator[key] = builtInVarsWrapper(validatorFn) + } + } +} + +addBuiltInVarsWrapper() + /** * 生成指定单位的长度校验函数 * @param units 单位值 @@ -2406,7 +2444,7 @@ function makeMultipleAttributesValidator(validatorMap) { * @returns {validator_enum} */ function makeEnumValidator(list) { - return validator.enum.bind(null, list) + return builtInVarsWrapper(validator.enum.bind(null, list)) } /** @@ -2416,7 +2454,7 @@ function makeEnumValidator(list) { * @returns {validator_$type} */ function makeAbbrAttrValidator(type, list) { - return validator[type].bind(null, list) + return builtInVarsWrapper(validator[type].bind(null, list)) } // background属性校验表 From ec525e047c4d9fcf7b277723cd830dff865e799a Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Wed, 4 Dec 2024 09:53:50 +0800 Subject: [PATCH 02/10] fix: modify manifest velidation error message Signed-off-by: lileirjyb --- packages/hap-toolkit/src/gen-webpack-conf/manifest-schema.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/hap-toolkit/src/gen-webpack-conf/manifest-schema.js b/packages/hap-toolkit/src/gen-webpack-conf/manifest-schema.js index 64871f4e..296d9205 100644 --- a/packages/hap-toolkit/src/gen-webpack-conf/manifest-schema.js +++ b/packages/hap-toolkit/src/gen-webpack-conf/manifest-schema.js @@ -283,7 +283,6 @@ export default { }, errorMessage: { type: ' 类型必须为 object', - required: - "必须包含 'package'、'name'、'versionName'、'versionCode'、'minPlatformVersion'、'icon'、'pages' 字段" + required: "必须包含 'package'、'name'、'icon'、'versionCode'、'config'、'router' 字段" } } From 8a6bea897e05e463dc62ed4975b40e4fbfc3ff6f Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Wed, 4 Dec 2024 10:05:55 +0800 Subject: [PATCH 03/10] feat: trim manifest for lite widget subpackages Signed-off-by: lileirjyb --- .../hap-packager/src/plugins/zip-plugin.js | 3 +- packages/hap-packager/src/process/index.js | 23 +++++--- .../hap-packager/src/subpackages/service.js | 53 ++++++++++++++++++- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/packages/hap-packager/src/plugins/zip-plugin.js b/packages/hap-packager/src/plugins/zip-plugin.js index 786ee6c4..2100cfa4 100644 --- a/packages/hap-packager/src/plugins/zip-plugin.js +++ b/packages/hap-packager/src/plugins/zip-plugin.js @@ -396,7 +396,8 @@ ZipPlugin.prototype.apply = function (compiler) { subPackages, this.signConfig, options.disableStreamPack, - compiler.watchMode + compiler.watchMode, + !options.disableSubpackages && options.subpackages && options.subpackages.length > 0 ) fs.ensureDirSync(options.output) diff --git a/packages/hap-packager/src/process/index.js b/packages/hap-packager/src/process/index.js index a604d9d1..f7338009 100644 --- a/packages/hap-packager/src/process/index.js +++ b/packages/hap-packager/src/process/index.js @@ -120,13 +120,20 @@ async function buildProjectAndOutput( subPackages, signConfig, disableStreamPack, - watchMode + watchMode, + isAppSubpackage ) { // 如果是watch模式,走快速编译的模式 if (watchMode) { return buildDebugModeProjectAndOutput.apply(null, arguments) } + // 如果不是快应用分包,则移除第一个 base 包 + // 只有快应用分包才需要base包,卡片分包不需要 + if (!isAppSubpackage) { + subPackages.shift() + } + // Step1. 生成整包rpk let fullPackageBuffer = await createZipBufferForPackage(fullPackage) @@ -158,12 +165,14 @@ async function buildProjectAndOutput( if (subPackageBuffers.length) { const rpksFileList = [] - - // 添加整包 - rpksFileList.push({ - path: fullPackage.fileName, - content: fullPackageBuffer - }) + if (isAppSubpackage) { + // 只有快应用分包才需要保留整包(历史遗留保持现状) + // 卡片分包不需要保留 + rpksFileList.push({ + path: fullPackage.fileName, + content: fullPackageBuffer + }) + } // 添加各个子包 subPackageBuffers.forEach((buffer, index) => { diff --git a/packages/hap-packager/src/subpackages/service.js b/packages/hap-packager/src/subpackages/service.js index 3fa8211b..129885be 100644 --- a/packages/hap-packager/src/subpackages/service.js +++ b/packages/hap-packager/src/subpackages/service.js @@ -6,13 +6,14 @@ import fs from 'fs' import path from 'path' -import { compileOptionsMeta } from '@hap-toolkit/shared-utils' +import { compileOptionsMeta, readJson } from '@hap-toolkit/shared-utils' import { calcDataDigest } from '../common/utils' import { createFullPackage, createSubPackages } from './package' import { BUILD_INFO_FILE } from '../common/constant' const MAIN_PKG_NAME = compileOptionsMeta.MAIN_PKG_NAME const SPLIT_CHUNKS_PAGE_NAME = compileOptionsMeta.splitChunksNameEnum.PAGE +const MANIFEST_TO_TRIM = ['features', 'display', 'subpackages', 'router.entry', 'router.pages'] /** * 创建完整包和分包列表 @@ -66,6 +67,49 @@ function getBuildInfoResource(buildInfo, widgetDigestMap) { return [buildPath, buf, digest] } +function trimSubPkgManifest(pkg, fileBuildPath, fileAbsPath) { + // 普通的独立分包不需要精简 manifest.json + if (!pkg._widget) return + + const manifest = readJson(fileAbsPath) + + // 删除 manifest 中卡片不需要的字段(快应用项目的字段) + MANIFEST_TO_TRIM.forEach((fieldPath) => { + let keys = fieldPath.split('.') + let current = manifest + + // 递归遍历对象,直到达到要删除字段的前一个对象 + for (let i = 0; i < keys.length - 1; i++) { + if (current[keys[i]]) { + current = current[keys[i]] + } else { + // 如果路径中的某个属性不存在,则跳出循环 + return + } + } + + // 删除指定的字段 + delete current[keys[keys.length - 1]] + }) + + // 删除 router.widgets 中不属于当前分包的 widget 配置 + const widgetsObj = manifest?.router?.widgets + if (widgetsObj) { + const trimWidgetObj = Object.keys(widgetsObj) + .filter((widgetKey) => pkg.subMatch.test(widgetKey + '/')) + .reduce((result, key) => { + result[key] = widgetsObj[key] + return result + }, {}) + manifest.router.widgets = trimWidgetObj + } + const manifestString = JSON.stringify(manifest) + const trimBuffer = Buffer.from(manifestString) + const trimDigest = calcDataDigest(trimBuffer) + + return [fileBuildPath, trimBuffer, trimDigest] +} + /** * 将各资源分派给各个要打出来的包,包括digest, hashList, 以及实际的文件内容fileContentBuffer * @param {String[]} files 文件列表 @@ -91,7 +135,7 @@ function allocateResourceToPackages( const fileContentBuffer = fs.readFileSync(fileAbsPath) const fileContentDigest = calcDataDigest(fileContentBuffer) // 资源基本信息 - const resourceInfo = [fileBuildPath, fileContentBuffer, fileContentDigest] + let resourceInfo = [fileBuildPath, fileContentBuffer, fileContentDigest] // 整包需要所有文件,不包括分包的独立page-chunks.json文件 if (!belongTofSubPkgReg.test(fileBuildPath)) { @@ -113,6 +157,11 @@ function allocateResourceToPackages( // 遍历除主包整包外的分包,判断此文件是否属于某个分包的 for (let i = 1; i < subPackages.length; i++) { const pkg = subPackages[i] + // 精简卡片的 manifest.json 文件,只保留本卡片的配置 + if (pkg.standalone && fileBuildPath === 'manifest.json') { + resourceInfo = trimSubPkgManifest(pkg, fileBuildPath, fileAbsPath) + } + // 如果此分包是个独立包,则需要加入manifest || sitemap.json || i18n || icon || banner || lottie 文件,每个包都需要 if ( pkg.standalone && From b24b663dbbd026bde9e9d7dfefb8e16a366001d5 Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Wed, 4 Dec 2024 14:53:11 +0800 Subject: [PATCH 04/10] feat: modify expression results Signed-off-by: lileirjyb --- packages/hap-compiler/src/template/exp.js | 1 + .../hap-compiler/src/template/validator.js | 25 +- .../hap-packager/src/post-handler/index.js | 226 ++++++++++++------ 3 files changed, 179 insertions(+), 73 deletions(-) diff --git a/packages/hap-compiler/src/template/exp.js b/packages/hap-compiler/src/template/exp.js index 98a269b4..ee5ac312 100644 --- a/packages/hap-compiler/src/template/exp.js +++ b/packages/hap-compiler/src/template/exp.js @@ -78,6 +78,7 @@ function transExpr(expContent, toFunc, isLite) { } transExpr.isExpr = textParser.isExpr +transExpr.parseText = textParser.parseText transExpr.singleExpr = textParser.singleExpr transExpr.removeExprffix = textParser.removeExprffix transExpr.addExprffix = textParser.addExprffix diff --git a/packages/hap-compiler/src/template/validator.js b/packages/hap-compiler/src/template/validator.js index c167ffe4..70a55fcc 100644 --- a/packages/hap-compiler/src/template/validator.js +++ b/packages/hap-compiler/src/template/validator.js @@ -1494,6 +1494,13 @@ function checkClass(className, output) { classList = classList.filter((klass) => klass.trim()) if (isLite) { + if (!isValidClassArray(segs)) { + const err = new Error('轻卡 class 样式不支持动态数据绑定 {{}} 和静态样式混用') + err.isExpressionError = true + err.expression = className + throw err + } + output.result.class = className output.result.classList = classList } else if (hasBinding) { const code = '(function () {return [' + classList.join(', ') + ']})' @@ -1979,6 +1986,21 @@ function hasIfOrFor(nodes) { return flag } +function isValidClassArray(arr) { + const filterArr = arr.filter((clazz) => clazz.length > 0) + + let hasTemplateString = false + + for (let i = 0; i < filterArr.length; i++) { + if (exp.isExpr(filterArr[i])) { + hasTemplateString = true + break + } + } + + return !hasTemplateString || filterArr.length === 1 // 如果全都为常量 className 或者只有一个变量的className,则返回true +} + export default { checkTagName, checkId, @@ -2001,5 +2023,6 @@ export default { isSupportedSelfClosing, isEmptyElement, isNotTextContentAtomic, - isExpr: exp.isExpr + isExpr: exp.isExpr, + parseText: exp.parseText } diff --git a/packages/hap-packager/src/post-handler/index.js b/packages/hap-packager/src/post-handler/index.js index 2ab029f4..2df5a17e 100644 --- a/packages/hap-packager/src/post-handler/index.js +++ b/packages/hap-packager/src/post-handler/index.js @@ -7,6 +7,7 @@ const TYPE_IMPORT = 'import' // 需要进行后处理的模块key const TEMPLATE_KEY = 'template' const ACTIONS_KEY = 'actions' +const SIMPLE_EXPR_MODIFIERS = ['$', '.', '[]', '~', '{}'] // 节点标记,标记优先级依次提升 const ENUM_KIND_TYPE = { @@ -25,28 +26,55 @@ function postHandleActions(actions) { } function markType(actions) { - // 如果有表达式,则用前缀方式优化 if (isExpr(actions.type)) { - const prefixExpr = getPrefixExpr(actions.type) + let { rawExpr, prefixExpr } = getPrefixExpr(actions.type) delete actions.type - actions['$type'] = prefixExpr + actions['$type'] = rawExpr + actions['#type'] = prefixExpr } } function markUrl(actions) { - // 如果有表达式,则用前缀方式优化 - if (isExpr(actions.url)) { - const prefixExpr = getPrefixExpr(actions.url) - delete actions.url - actions['$url'] = prefixExpr + if (typeof actions.url === 'string') { + if (isExpr(actions.url)) { + let { rawExpr, prefixExpr } = getPrefixExpr(actions.url) + delete actions.url + actions['$url'] = rawExpr + actions['#url'] = prefixExpr + } + } else if (Array.isArray(actions.url)) { + let hasBinding = false + const rawUrlList = actions.url.map((url) => { + if (isExpr(url)) { + hasBinding = true + let { rawExpr } = getPrefixExpr(url) + return `{{${rawExpr}}}` + } + return url + }) + + const prefixUrlList = actions.url.map((url) => { + if (isExpr(url)) { + hasBinding = true + let { prefixExpr } = getPrefixExpr(url) + return prefixExpr + } + return url + }) + + if (hasBinding) { + delete actions.url + actions['$url'] = rawUrlList + actions['#url'] = prefixUrlList + } } } function markMethod(actions) { - // 如果有表达式,则用前缀方式优化 if (isExpr(actions.method)) { - const prefixExpr = getPrefixExpr(actions.method) + let { rawExpr, prefixExpr } = getPrefixExpr(actions.method) delete actions.method - actions['$method'] = prefixExpr + actions['$method'] = rawExpr + actions['#method'] = prefixExpr } } @@ -57,19 +85,22 @@ function markParams(actions) { Object.keys(actions.params).forEach((key) => { const value = actions.params[key] if (isExpr(value)) { - const prefixExpr = getPrefixExpr(value) + let { rawExpr, prefixExpr } = getPrefixExpr(value) delete actions.params[key] - actions.params['$' + key] = prefixExpr + actions.params['$' + key] = rawExpr + actions.params['#' + key] = prefixExpr } }) } +// 处理 template 中的字段,增加标记和处理表达式 function postHandleTemplate(template, liteCardRes) { if (!isObject(template)) return markStyle(template) + markClass(template) markClassList(template) - markAttrs(template) + markAttr(template) markEvents(template) markId(template) markIs(template) @@ -102,21 +133,25 @@ function markCustomComp(template, liteCardRes) { } function markIf(template) { - // 如果有表达式,则用前缀方式优化 + if (!template.shown) return + if (isExpr(template.shown)) { - const prefixExpr = getPrefixExpr(template.shown) + let { rawExpr, prefixExpr } = getPrefixExpr(template.shown) delete template.shown - template['$shown'] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) + template['$shown'] = rawExpr + template['#shown'] = prefixExpr } + template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) } function markIs(template) { - // 如果有表达式,则用前缀方式优化 + if (!template.is) return + if (isExpr(template.is)) { - const prefixExpr = getPrefixExpr(template.is) + let { rawExpr, prefixExpr } = getPrefixExpr(template.is) delete template.is - template['$is'] = prefixExpr + template['$is'] = rawExpr + template['#is'] = prefixExpr template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) } } @@ -124,47 +159,56 @@ function markIs(template) { function markId(template) { if (!template.id) return - // 如果有表达式,则用前缀方式优化 if (isExpr(template.id)) { - const prefixExpr = getPrefixExpr(template.id) + let { rawExpr, prefixExpr } = getPrefixExpr(template.id) delete template.id - template['$id'] = prefixExpr + template['$id'] = rawExpr + template['#id'] = prefixExpr } // 节点有id属性,标记为kind=1 template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) } function markFor(template) { - if (isObject(template.repeat) && isExpr(template.repeat.exp)) { - /** -
-> - "repeat": { - "$exp": "{{ItemList}}", - "key": "index", - "value": "item" - }, - -
-> - "repeat": { - "$exp": "[\"~\",1,2,3]", - "key": "index", - "value": "item" - }, - */ - const prefixExpr = getPrefixExpr(template.repeat.exp) - delete template.repeat.exp - template.repeat['$exp'] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) + if (!template.repeat) return + + if (isObject(template.repeat)) { + if (isExpr(template.repeat.exp)) { + /** + * example 1: +
-> + "repeat": { + "$exp": "ItemList", + "#exp": ["$", "ItemList"], + "key": "index", + "value": "item" + }, + + example 2: +
-> + "repeat": { + "$exp": "[1, 2, 3]", + "#exp": "[\"~\",1,2,3]", + "key": "index", + "value": "item" + }, + */ + let { rawExpr, prefixExpr } = getPrefixExpr(template.repeat.exp) + delete template.repeat.exp + template.repeat['$exp'] = rawExpr + template.repeat['#exp'] = prefixExpr + } } else if (isExpr(template.repeat)) { /**
-> "$repeat": "{{ItemList}}", */ - const prefixExpr = getPrefixExpr(template.repeat) + let { rawExpr, prefixExpr } = getPrefixExpr(template.repeat) delete template.repeat - template['$repeat'] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) + template['$repeat'] = rawExpr + template['#repeat'] = prefixExpr } + template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) } function markStyle(template) { @@ -174,41 +218,54 @@ function markStyle(template) { if (typeof style === 'object') { Object.keys(style).forEach((key) => { const value = style[key] - // 如果有表达式,则用前缀方式优化 if (isExpr(value)) { - const prefixExpr = getPrefixExpr(value) + let { rawExpr, prefixExpr } = getPrefixExpr(value) delete template.style[key] - template.style['$' + key] = prefixExpr + template.style['$' + key] = rawExpr + template.style['#' + key] = prefixExpr template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) } }) } else { - // 如果有表达式,则用前缀方式优化 if (isExpr(style)) { - const prefixExpr = getPrefixExpr(style) + let { rawExpr, prefixExpr } = getPrefixExpr(style) delete template.style - template['$style'] = prefixExpr + template['$style'] = rawExpr + template['#style'] = prefixExpr template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) } } } +function markClass(template) { + if (!template.class || template.class.length === 0) return + + if (isExpr(template.class)) { + let { rawExpr, prefixExpr } = getPrefixExpr(template.class) + delete template.class + template['$class'] = rawExpr + template['#class'] = prefixExpr + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + } +} + function markClassList(template) { if (!template.classList || template.classList.length === 0) return let hasBinding = false - const cList = template.classList.map((classEle) => { - // 如果有表达式,则用前缀方式优化 + const prefixExprList = template.classList.map((classEle) => { if (isExpr(classEle)) { hasBinding = true - return getPrefixExpr(classEle) + let { prefixExpr } = getPrefixExpr(classEle) + return prefixExpr } return classEle }) + if (hasBinding) { // 如果 classList 元素有表达式 delete template.classList - template['$classList'] = cList + template['#classList'] = prefixExprList template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) } } @@ -219,17 +276,19 @@ function markEvents(template) { } } -function markAttrs(template) { - const attrs = template.attr - if (isObject(attrs)) { - Object.keys(attrs).forEach((attrKey) => { - const attrValue = attrs[attrKey] - // 如果有表达式,则用前缀方式优化 +function markAttr(template) { + if (!template.attr) return + + const attr = template.attr + if (isObject(attr)) { + Object.keys(attr).forEach((attrKey) => { + const attrValue = attr[attrKey] if (isExpr(attrValue)) { - const prefixExpr = getPrefixExpr(attrValue) - delete attrs[attrKey] - attrs['$' + attrKey] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + let { rawExpr, prefixExpr } = getPrefixExpr(attrValue) + delete attr[attrKey] + attr['$' + attrKey] = rawExpr + attr['#' + attrKey] = prefixExpr + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } }) } @@ -248,16 +307,39 @@ function getPrefixExpr(expr) { const res = templateValueToCardCode(expr) const parsed = JSON.parse(res) if (isSimpleExpr(parsed)) { - // 表达式是简单标识符,直接返回模板字符串。如: {{ name }} -> {{ name }} - return expr + // 简单表达式 + // 目前只有 {{name}}、{{title.name}}、{{title[0]}}、{{[1,2,3]}}、{{ {a: 1} }} 算作简单表达式 + return { + rawExpr: validator.parseText(expr)[0].value, // {{ name }} -> name + prefixExpr: parsed // {{ name }} -> ['$', 'name'] + } } else { - // 表达式为复杂表达式,返回前缀表达式字符串。如: {{ $item.name }} -> [".",["$","$item"],"name"] - return parsed + // 复杂表达式 + return { + rawExpr: expr, // {{ a + b }} -> {{ a + b }} + prefixExpr: parsed // {{ a + b }} -> ["+",["$","a"],["$","b"]] + } } } +// 根据操作符来判断是否为简单表达式 function isSimpleExpr(expr) { - return Array.isArray(expr) && expr.length === 2 && expr[0] === '$' + if (!expr || !Array.isArray(expr)) return false + + const modifierList = [] + getAllModifiers(expr, modifierList) + return modifierList.every((modifier) => SIMPLE_EXPR_MODIFIERS.includes(modifier)) +} + +function getAllModifiers(exprList, modifierList) { + modifierList.push(exprList[0]) + for (let i = 1; i < exprList.length; i++) { + if (Array.isArray(exprList[i])) { + // 如果当前元素是数组,递归调用,找出所有的操作符 + getAllModifiers(exprList[i], modifierList) + } + } + return modifierList } function recordKeys(liteCardRes, templateKeys) { From dbe8b1132fd5d9009b401d261bf10fc493384854 Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Wed, 4 Dec 2024 20:36:27 +0800 Subject: [PATCH 05/10] feat: upgrade expression lib to 1.0.13 Signed-off-by: lileirjyb --- packages/hap-packager/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/hap-packager/package.json b/packages/hap-packager/package.json index 85dd63ee..f6a0e49f 100644 --- a/packages/hap-packager/package.json +++ b/packages/hap-packager/package.json @@ -29,7 +29,7 @@ "babel.tree.config.js" ], "dependencies": { - "@aiot-toolkit/card-expression": "^1.0.12", + "@aiot-toolkit/card-expression": "^1.0.13", "@babel/core": "^7.9.6", "@babel/generator": "^7.9.6", "@babel/parser": "^7.9.6", diff --git a/yarn.lock b/yarn.lock index 9fae7844..39c2a931 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@aiot-toolkit/card-expression@^1.0.12": - version "1.0.12" - resolved "https://registry.npmmirror.com/@aiot-toolkit/card-expression/-/card-expression-1.0.12.tgz#6e734d372fd8dd1fae5ff643fe590cdca9a5d97a" - integrity sha512-fN/2L4JuStIvW30z5joCvhN+qtcDlGfkMdXGx6o3gMl2lmqqQVKmcnJq9vbe2uL8E1AMTm6f3/YhZ5AYmOk2pA== +"@aiot-toolkit/card-expression@^1.0.13": + version "1.0.13" + resolved "https://registry.npmmirror.com/@aiot-toolkit/card-expression/-/card-expression-1.0.13.tgz#6649204e181fc46d21e8a7afef8ab82fff1bf2ab" + integrity sha512-5FhFSgh598fHRFMcF4g20V0PnGh0GhEzbGeK89DOSbe/2f4PPs75N4l1TmiwIBbT2zEDXe/1oFBIgIruoFqFUQ== dependencies: "@babel/generator" "^7.25.6" "@babel/parser" "^7.25.6" From b7cef80fd2c7adb15764f77f7a3bb04c551cdb4f Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Wed, 4 Dec 2024 20:37:06 +0800 Subject: [PATCH 06/10] fix: modify package size limit Signed-off-by: lileirjyb --- packages/hap-packager/src/common/constant.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hap-packager/src/common/constant.js b/packages/hap-packager/src/common/constant.js index ce1af87e..c1a305a2 100644 --- a/packages/hap-packager/src/common/constant.js +++ b/packages/hap-packager/src/common/constant.js @@ -14,9 +14,9 @@ const BUILD_INFO_FILE = DIGEST_ZIP_DIR + '/build.txt' // 文件列表摘要的名称 const DIGEST_HASH_JSON = 'hash.json' // 分包的大小上限 1MB -const SINGLE_PKG_SIZE = 1024 * 1024 +const SINGLE_PKG_SIZE = 2048 * 1024 // 整包的大小上限 4MB -const FULL_PKG_SIZE = SINGLE_PKG_SIZE * 4 +const FULL_PKG_SIZE = SINGLE_PKG_SIZE * 10 // 压缩参数,设置输出 buffer,以便对 buffer 进行操作 const COMPRESS_OPTS = { From e7694b2d0f31d6cc49e2b4441ff14790e42f60f4 Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Thu, 5 Dec 2024 11:26:39 +0800 Subject: [PATCH 07/10] fix: modify kind priority Signed-off-by: lileirjyb --- .../hap-packager/src/post-handler/index.js | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/hap-packager/src/post-handler/index.js b/packages/hap-packager/src/post-handler/index.js index 2df5a17e..37483e77 100644 --- a/packages/hap-packager/src/post-handler/index.js +++ b/packages/hap-packager/src/post-handler/index.js @@ -9,13 +9,26 @@ const TEMPLATE_KEY = 'template' const ACTIONS_KEY = 'actions' const SIMPLE_EXPR_MODIFIERS = ['$', '.', '[]', '~', '{}'] -// 节点标记,标记优先级依次提升 +// 节点标记,同一节点可能同时符合多个kind定义,按priority高的进行标记 const ENUM_KIND_TYPE = { - ELEMENT: 1, // 普通动态节点、事件节点、带id属性的节点 - FRAGMENT: 2, // if/for 动态节点 - COMPONENT: 3 // 自定义组件节点 + ELEMENT: { + // 普通动态节点、事件节点、带id属性的节点 + kind: 1, + priority: 1 + }, + COMPONENT: { + // 自定义组件节点 + kind: 3, + priority: 2 + }, + FRAGMENT: { + // if/for 动态节点 + kind: 2, + priority: 3 + } } +// 处理 actions 中的字段,增加标记和处理表达式 function postHandleActions(actions) { if (!isObject(actions)) return @@ -35,6 +48,8 @@ function markType(actions) { } function markUrl(actions) { + // url 可能为字符串,也可能为数组 + // 如为数组,则遍历数组进行表达式处理 if (typeof actions.url === 'string') { if (isExpr(actions.url)) { let { rawExpr, prefixExpr } = getPrefixExpr(actions.url) @@ -117,8 +132,27 @@ function postHandleTemplate(template, liteCardRes) { } } +// 获取kind值对应的优先级 +function getPriority(kind) { + let prioity = kind + Object.keys(ENUM_KIND_TYPE).some((key) => { + const item = ENUM_KIND_TYPE[key] + if (item.kind === kind) { + prioity = item.priority + return true + } + }) + return prioity +} + +// 根据优先级标记节点的 kind 值 function markKind(oldKind, newKind) { - if (!oldKind || oldKind < newKind) return newKind + if (!oldKind) return newKind + + const oldPriority = getPriority(oldKind) + const newPriority = getPriority(newKind) + if (oldPriority < newPriority) return newKind + return oldKind } @@ -128,7 +162,7 @@ function markCustomComp(template, liteCardRes) { const importList = Object.keys(liteCardRes[CARD_ENTRY][TYPE_IMPORT]) if (importList.includes(template.type)) { - template.kind = markKind(template.kind, ENUM_KIND_TYPE.COMPONENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.COMPONENT.kind) } } @@ -141,7 +175,7 @@ function markIf(template) { template['$shown'] = rawExpr template['#shown'] = prefixExpr } - template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT.kind) } function markIs(template) { @@ -152,7 +186,7 @@ function markIs(template) { delete template.is template['$is'] = rawExpr template['#is'] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } } @@ -165,8 +199,8 @@ function markId(template) { template['$id'] = rawExpr template['#id'] = prefixExpr } - // 节点有id属性,标记为kind=1 - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + // 节点有id属性,标记为kind 为 1 + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } function markFor(template) { @@ -201,14 +235,15 @@ function markFor(template) { } else if (isExpr(template.repeat)) { /**
-> - "$repeat": "{{ItemList}}", + "$repeat": "ItemList", + "#repeat": ["$", "ItemList"], */ let { rawExpr, prefixExpr } = getPrefixExpr(template.repeat) delete template.repeat template['$repeat'] = rawExpr template['#repeat'] = prefixExpr } - template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.FRAGMENT.kind) } function markStyle(template) { @@ -223,7 +258,7 @@ function markStyle(template) { delete template.style[key] template.style['$' + key] = rawExpr template.style['#' + key] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } }) } else { @@ -232,7 +267,7 @@ function markStyle(template) { delete template.style template['$style'] = rawExpr template['#style'] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } } } @@ -245,7 +280,7 @@ function markClass(template) { delete template.class template['$class'] = rawExpr template['#class'] = prefixExpr - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } } @@ -272,7 +307,7 @@ function markClassList(template) { function markEvents(template) { if (template.events) { - template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT) + template.kind = markKind(template.kind, ENUM_KIND_TYPE.ELEMENT.kind) } } From 11e8464738299cfd51320745471d52df35517c41 Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Thu, 12 Dec 2024 10:48:15 +0800 Subject: [PATCH 08/10] fix: add judgement when subpackage is null Signed-off-by: lileirjyb --- packages/hap-packager/src/process/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hap-packager/src/process/index.js b/packages/hap-packager/src/process/index.js index f7338009..fe062756 100644 --- a/packages/hap-packager/src/process/index.js +++ b/packages/hap-packager/src/process/index.js @@ -130,7 +130,7 @@ async function buildProjectAndOutput( // 如果不是快应用分包,则移除第一个 base 包 // 只有快应用分包才需要base包,卡片分包不需要 - if (!isAppSubpackage) { + if (!isAppSubpackage && subPackages) { subPackages.shift() } From edd83c3a6f97f05956cbe4fdd024c50be80b378f Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Fri, 20 Dec 2024 16:54:29 +0800 Subject: [PATCH 09/10] fix: fix quickapp subpackages bug and fix ci Signed-off-by: lileirjyb --- packages/hap-dsl-xvm/test/unit/ux/card.test.js | 2 +- packages/hap-packager/src/subpackages/service.js | 2 +- .../hap-toolkit/__tests__/__snapshots__/validate.test.js.snap | 2 +- packages/hap-toolkit/__tests__/init.test.js | 2 +- readme.md | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/hap-dsl-xvm/test/unit/ux/card.test.js b/packages/hap-dsl-xvm/test/unit/ux/card.test.js index 0d1d29a0..e05c3bd8 100644 --- a/packages/hap-dsl-xvm/test/unit/ux/card.test.js +++ b/packages/hap-dsl-xvm/test/unit/ux/card.test.js @@ -21,5 +21,5 @@ describe('Card 编译测试', () => { json.modules.forEach(module => { expect(wipeDynamic(module.source)).toMatchSnapshot(module.id) }) - }) + }, 50 * 60 * 1000) }) diff --git a/packages/hap-packager/src/subpackages/service.js b/packages/hap-packager/src/subpackages/service.js index 129885be..250772bd 100644 --- a/packages/hap-packager/src/subpackages/service.js +++ b/packages/hap-packager/src/subpackages/service.js @@ -158,7 +158,7 @@ function allocateResourceToPackages( for (let i = 1; i < subPackages.length; i++) { const pkg = subPackages[i] // 精简卡片的 manifest.json 文件,只保留本卡片的配置 - if (pkg.standalone && fileBuildPath === 'manifest.json') { + if (pkg._widget && fileBuildPath === 'manifest.json') { resourceInfo = trimSubPkgManifest(pkg, fileBuildPath, fileAbsPath) } diff --git a/packages/hap-toolkit/__tests__/__snapshots__/validate.test.js.snap b/packages/hap-toolkit/__tests__/__snapshots__/validate.test.js.snap index 62bd3ddc..b72eb21c 100644 --- a/packages/hap-toolkit/__tests__/__snapshots__/validate.test.js.snap +++ b/packages/hap-toolkit/__tests__/__snapshots__/validate.test.js.snap @@ -60,6 +60,6 @@ deviceTypeList.1 字段类型必须为 'string' 参考: https://doc.quickapp.cn/framework/manifest.html 校验 manifest.json 错误 -必须包含 'package'、'name'、'versionName'、'versionCode'、'minPlatformVersion'、'icon'、'pages' 字段 +必须包含 'package'、'name'、'icon'、'versionCode'、'config'、'router' 字段 参考: https://doc.quickapp.cn/framework/manifest.html" `; diff --git a/packages/hap-toolkit/__tests__/init.test.js b/packages/hap-toolkit/__tests__/init.test.js index 05696ce8..94aefd3e 100644 --- a/packages/hap-toolkit/__tests__/init.test.js +++ b/packages/hap-toolkit/__tests__/init.test.js @@ -68,6 +68,6 @@ describe('initialize a project', () => { expect(pkgInfo.devDependencies['hap-toolkit']).toBe('^' + packageInfo.version) await del([TEST_NAME], { force: true }) }, - 5 * 60 * 1000 + 50 * 60 * 1000 ) }) diff --git a/readme.md b/readme.md index c2176f96..64b0f193 100644 --- a/readme.md +++ b/readme.md @@ -56,6 +56,8 @@ npm run dev # gulp watch --dev ### 单元测试 +测试工具基于[jest],使用 `npx gulp test` 命令执行测试。运行单元测时前,先执行 `npm run build` 构建最新的产物 + ```sh npx gulp test ``` From cb0865f6bfe9e415602ed8b283d95123af655d4a Mon Sep 17 00:00:00 2001 From: lileirjyb Date: Fri, 20 Dec 2024 18:52:29 +0800 Subject: [PATCH 10/10] =?UTF-8?q?chore:=20=E4=BC=98=E5=8C=96=E8=BD=BB?= =?UTF-8?q?=E5=8D=A1data=E4=B8=AD=E7=9A=84=E6=8A=A5=E9=94=99=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: lileirjyb --- packages/hap-dsl-xvm/src/loaders/action-loader.js | 2 +- packages/hap-dsl-xvm/src/loaders/data-loader.js | 2 +- packages/hap-dsl-xvm/src/loaders/props-loader.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hap-dsl-xvm/src/loaders/action-loader.js b/packages/hap-dsl-xvm/src/loaders/action-loader.js index 8932a7cd..273dc56e 100644 --- a/packages/hap-dsl-xvm/src/loaders/action-loader.js +++ b/packages/hap-dsl-xvm/src/loaders/action-loader.js @@ -12,7 +12,7 @@ export default function actionLoader(source) { const { parsed } = parseActions(jsonObj) actionStr = parsed } catch (e) { - throw new Error(`Invalid in ${this.resourcePath}\n${e}`) + throw new Error(`${this.resourcePath} 中的 解析失败,请检查是否为标准的 JSON 格式\n${e}`) } return `module.exports = ${actionStr}` } diff --git a/packages/hap-dsl-xvm/src/loaders/data-loader.js b/packages/hap-dsl-xvm/src/loaders/data-loader.js index 05a54bab..a05c09b4 100644 --- a/packages/hap-dsl-xvm/src/loaders/data-loader.js +++ b/packages/hap-dsl-xvm/src/loaders/data-loader.js @@ -9,7 +9,7 @@ export default function dataLoader(source) { const obj = JSON.parse(source) jsonObj = obj.uiData || obj.data || {} } catch (e) { - throw new Error(`Invalid in ${this.resourcePath}:: ${e}`) + throw new Error(`${this.resourcePath} 中的 解析失败,请检查是否为标准的 JSON 格式\n${e}`) } return `module.exports = ${JSON.stringify(jsonObj)}` } diff --git a/packages/hap-dsl-xvm/src/loaders/props-loader.js b/packages/hap-dsl-xvm/src/loaders/props-loader.js index 34c47c29..00c81e79 100644 --- a/packages/hap-dsl-xvm/src/loaders/props-loader.js +++ b/packages/hap-dsl-xvm/src/loaders/props-loader.js @@ -9,7 +9,7 @@ export default function propsLoader(source) { const obj = JSON.parse(source) jsonObj = obj.props || {} } catch (e) { - throw new Error(`Invalid in ${this.resourcePath}:: ${e}`) + throw new Error(`${this.resourcePath} 中的 解析失败,请检查是否为标准的 JSON 格式\n${e}`) } return `module.exports = ${JSON.stringify(jsonObj)}` }