vivo-hap-toolkit
Version:
A command line toolkit for developing Quick Apps.
150 lines (138 loc) • 5.85 kB
JavaScript
const fs = require('fs')
const path = require('path')
const { colorconsole, KnownError } = require('@vivo-hap-toolkit/shared-utils')
const { compileOptionsMeta } = require('@vivo-hap-toolkit/shared-utils/compilation-config')
// 主包保留名
const MAIN_PKG_NAME = compileOptionsMeta.MAIN_PKG_NAME
// 能使用rpks能力的调试器最低版本
const RPKS_SUPPORT_VERSION_FROM = 1040
/**
* 验证项目配置正确
*/
exports.validateProject = function validateProject(manifestFile, sourceRoot) {
if (!fs.existsSync(manifestFile)) {
colorconsole.throw(
`请确认项目%projectDir%/${sourceRoot}/下存在manifest.json文件:${manifestFile}`
)
throw new KnownError(`找不到 ${sourceRoot}/manifest.json`)
}
}
/**
* 验证项目的应用全局配置
* @param {String} src - 项目src
* @param {Object} manifest - manifest 对象
* @param {Object} options - compileOptionsObject
*/
exports.validateManifest = function validateManifest(src, manifest, options) {
const { subpackages } = manifest
// 验证分包规则
if (!options.disableSubpackages && subpackages && subpackages.length > 0) {
validateManifestSubpackages(src, subpackages)
}
}
/**
* 检查subpackages字段配置。
* 除subpackages字段指定的文件是打进非主包外,剩余文件都打进主包
* 主包与是独立包的非主包,都需要manifest文件
* @param {object[]} subpackages 分包列表: [{ name, resource, standalone, icon }]
* @param {string} subpackages[].name 分包名字,必填,不能重复,且不能是"base"(这是主包保留名),只能是 数字字母_ 组成
* @param {string} subpackages[].resource 分包资源路径,必须为src下文件目录,不能重复,分包间不能有包含关系,只能是 数字字母_ 开头,数字字母_-/ 组成
* @param {boolean} subpackages[].standalone 是否独立包标识,是独立包则需要manifest文件,缺省为false;
* @param {boolean} subpackages[].icon 分包icon,是独立包则需要icon,缺省则为应用的icon;
*/
function validateManifestSubpackages(src, subpackages) {
// 分包名的校验规则
const nameReg = /^\w+$/
// 资源名的校验规则
const resourceReg = /^\w[\w-/]*$/
// 用以检测分包名是否重复
const nameList = []
// 用以检测分包资源路径是否重复
const resList = []
// i18n文件目录地址,不能作为分包
const i18nPath = path.join(src, 'i18n')
let name = ''
let resource = ''
// 资源路径的具体文件路径
let resPath = ''
let index = 0
/**
* 检查当前资源路径与已校验过的资源路径是否有包含关系。
*
* @param {string} resource - 当前要校验的资源
* @param {number} index - 当前要校验资源的序号
* @return {boolean} true/false - 存在/不存在
*/
function checkPathInclusion(resource, currentIndex) {
for (let i = 0, l = resList.length; i < l; i++) {
const _res = resList[i]
if (resource.startsWith(_res) || _res.startsWith(resource)) {
colorconsole.throw(
`第${currentIndex}分包的资源'${resource}'与第${i +
1}分包的资源'${_res}'有包含关系,请修改`
)
return true
}
}
return false
}
subpackages.forEach((subpkg, i) => {
name = subpkg.name
resource = subpkg.resource
resPath = resource && path.join(src, resource)
index = i + 1
if (!name) {
colorconsole.throw(`第${index}分包的名字不能为空,请添加`)
} else if (!nameReg.test(name)) {
colorconsole.throw(`第${index}分包的名字'${name}'不合法,只能是数字字母下划线组成,请修改`)
} else if (name === MAIN_PKG_NAME) {
colorconsole.throw(`第${index}分包的名字'${name}'是主包保留名,请修改`)
} else if (nameList.indexOf(name) > -1) {
colorconsole.throw(`第${index}分包的名字'${name}'已存在,请修改`)
} else {
nameList.push(name)
}
if (!resource) {
colorconsole.throw(`第${index}分包的资源名不能为空,请添加`)
} else if (!resourceReg.test(resource)) {
colorconsole.throw(
`第${index}分包的资源名'${resource}'不合法,只能是 数字字母_ 开头,数字字母_-/ 组成,请修改`
)
} else if (resList.indexOf(resource) > -1) {
colorconsole.throw(`第${index}分包的资源'${resource}'已被使用,请修改`)
} else if (!fs.existsSync(resPath)) {
colorconsole.throw(`第${index}分包的资源'${resource}',文件目录'${resPath}'不存在,请修改`)
} else if (resPath === i18nPath) {
colorconsole.throw(
`第${index}分包的资源'${resource}',文件目录'${resPath}',i18n文件目录不能作为分包,请修改`
)
} else if (!checkPathInclusion(resource, index)) {
resList.push(resource)
}
if (subpkg.standalone && subpkg.icon && !fs.existsSync(path.join(src, subpkg.icon))) {
colorconsole.throw(`第${index}分包配置的icon不存在,请修改`)
}
})
colorconsole.warn(
`项目已配置分包,若想使用分包功能,请确保平台版本 >= ${RPKS_SUPPORT_VERSION_FROM}`
)
}
/**
* sitemap校验。
* @param {String} src - 项目src路径
* @param {Object} manifest - manifest内容
*/
exports.valiedateSitemap = function valiedateSitemap(src, manifest) {
const sitemap = path.join(src, 'sitemap.json')
if (fs.existsSync(sitemap)) {
const rules = require(sitemap).rules
const pages = Object.keys(manifest.router.pages || {})
rules.forEach((i, idx) => {
const page = i.page
if (page !== '*' && !pages.includes(page)) {
colorconsole.throw(`sitemap rules第${idx + 1}项配置错误,该page不存在:${page}`)
}
return page
})
}
}