UNPKG

@revues/code-compiler

Version:

A code compiler for compile huya miniapp

1,731 lines (1,624 loc) 123 kB
/*! * @revues/code-compiler * (c) 2024-2025 Alex * Released under the MIT License. */ 'use strict'; var WokerThreads = require('worker_threads'); var fs$1 = require('fs-extra'); var path = require('path'); var sourceMap = require('source-map'); require('crypto'); require('minimatch'); var UglifyJS = require('uglify-js'); var codeFrame = require('@babel/code-frame'); var core = require('@babel/core'); var helperModuleImports = require('@babel/helper-module-imports'); var fs = require('fs'); var autoprefixer = require('autoprefixer'); var postcss = require('postcss'); var htmlparser2 = require('htmlparser2'); var os = require('os'); require('child_process'); require('cluster'); require('eventemitter3'); var transformModulesCommonjsPlugin = require('@babel/plugin-transform-modules-commonjs'); var DefinePlugin = require('babel-plugin-transform-define'); var less = require('less'); var sass = require('sass'); var TransformTSPlugin = require('@babel/plugin-transform-typescript'); var postcssColorHexAlpha = require('postcss-color-hex-alpha'); var valueParser = require('postcss-value-parser'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var WokerThreads__default = /*#__PURE__*/_interopDefaultLegacy(WokerThreads); var fs__default$1 = /*#__PURE__*/_interopDefaultLegacy(fs$1); var path__default = /*#__PURE__*/_interopDefaultLegacy(path); var UglifyJS__default = /*#__PURE__*/_interopDefaultLegacy(UglifyJS); var codeFrame__default = /*#__PURE__*/_interopDefaultLegacy(codeFrame); var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); var autoprefixer__default = /*#__PURE__*/_interopDefaultLegacy(autoprefixer); var postcss__default = /*#__PURE__*/_interopDefaultLegacy(postcss); var transformModulesCommonjsPlugin__default = /*#__PURE__*/_interopDefaultLegacy(transformModulesCommonjsPlugin); var DefinePlugin__default = /*#__PURE__*/_interopDefaultLegacy(DefinePlugin); var less__default = /*#__PURE__*/_interopDefaultLegacy(less); var sass__default = /*#__PURE__*/_interopDefaultLegacy(sass); var TransformTSPlugin__default = /*#__PURE__*/_interopDefaultLegacy(TransformTSPlugin); var postcssColorHexAlpha__default = /*#__PURE__*/_interopDefaultLegacy(postcssColorHexAlpha); var valueParser__default = /*#__PURE__*/_interopDefaultLegacy(valueParser); const COMMAND = { RUN_TASK: 'RUN_TASK', TASK_DONE: 'TASK_DONE', CALL_FUNC: 'CALL_FUNC', CALL_FUNC_RESULT: 'CALL_FUNC_RESULT', CHILD_PROCESS_READY: 'CHILD_PROCESS_READY', SEND_LOG: 'SEND_LOG' }; const TASK_NAME = { COMPILE_JS: 'COMPILE_JS', COMPILE_WXSS: 'COMPILE_WXSS', MINIFY_WXML: 'MINIFY_WXML', SUMMER_HOOK: 'SUMMER_HOOK' }; // 子进程 const cpprocessEnv = process.env.cpprocessEnv; const processEnv = 'childprocess' === cpprocessEnv || 'workerthread' === cpprocessEnv || 'workerprocess' === cpprocessEnv ? cpprocessEnv : 'main'; // 宿主 const env = process.env; const hostEnv = (env && env.isDevtools) || (process.__nwjs && 'wechatwebdevtools' === nw.App.manifest.appname) ? 'devtools' : 'ci'; "1" === process.env.blenderProcess; function patch(e, t = 2) { return e > 10 ** t ? String(e) : `${new Array(t).join('0')}${e}`.slice(-t) } const baseLogConf = { trace: 1, info: 2, log: 3, warn: 4, error: 5 }; // 用于 主从 进程日志打印 const logger = new (class { setOutput(e) { this.output = e; } setEnableLevel(e) { this.enableLevel = e; } setReady() { if (((this.ready = !0), this.logs.length > 0)) for (const e of this.logs) this.output(e.level, e.args); } send(e, t) { this.ready ? this.output(e, t) : this.logs.push({ level: e, args: t }); } getPrintTime() { const e = new Date(); return `${String(e.getFullYear())}-${patch(e.getMonth() + 1)}-${patch( e.getDate() )} ${patch(e.getHours())}:${patch(e.getMinutes())}:${patch( e.getSeconds() )}.${patch(e.getMilliseconds(), 3)}` } _receive(method, t, s) { const current = baseLogConf[method]; if (this.enableLevel <= current) { (s = [ (t = `[compiler][${processEnv}][${this.getPrintTime()}] ${t}`), ...s ]), this.send(method, s); } } info(e, ...t) { this._receive('info', e, t); } log(e, ...t) { this._receive('log', e, t); } error(e, ...t) { this._receive('error', e, t); } constructor(e) { (this.output = e), (this.enableLevel = baseLogConf.log), (this.ready = !1), (this.logs = []); } })((e, t) => { console.log(e); console[e](...t); }); if ('ci' === hostEnv && 'compiler' === process.env.debug) { logger.setEnableLevel(baseLogConf.log); } else { logger.setEnableLevel(baseLogConf.warn); } if ('childprocess' === processEnv) { logger.setOutput((e, t) => { process.send({ command: COMMAND.SEND_LOG, data: { level: e, args: t } }); }); } if ('workerthread' === processEnv) { const port = WokerThreads.parentPort; port && logger.setOutput((t, s) => { port.postMessage({ command: COMMAND.SEND_LOG, data: { level: t, args: s } }); }); } logger.setReady(); class FormatableString { constructor(v) { this.v = v; } format(...args) { const first = args[0]; let tamplateStr = this.v; if ('[object Array]' === Object.prototype.toString.call(first)) { first.forEach(e => { tamplateStr = tamplateStr.replace('%s', e); }); } else { args.forEach(e => { tamplateStr = tamplateStr.replace('%s', e); }); } return tamplateStr } } const template$1 = { GENERATE_LOCAL_SIGNATURE_FAIL: '生成本地签名失败。通常是key文件编码或者内容有误。错误详情: %s', PARAM_ERROR: '方法:"%s" 缺少参数:"%s"', SHOULD_NOT_BE_EMPTY: '%s 不能为空', JSON_CONTENT_SHOULD_BE: '%s 字段需为 %s', SHOULD_AT_LEAST_ONE_ITEM: '%s 需至少存在一项', SHOULD_MATCH: '%s 需与 %s 匹配', SHOULD_EQUAL: '%s 需等于 %s', EXT_SHOULD_BE_ERROR: '%s 的拓展名需为 "%s"', OR: '或', CORRESPONDING_FILE_NOT_FOUND: '未找到 %s 对应的 %s 文件', JSON_SHOULD_NOT_START_WITH: "%s 不应该以 '%s' 开头", JSON_SHOULD_NOT_CONTAIN: '%s 不应该包含 %s', NOT_FOUND: '%s 未找到', NOT_FOUND_IN_ROOT_DIR: '在项目根目录未找到 %s ', MINIPROGRAM_APP_JSON_NOT_FOUND: '根据 project.config.json 中 miniprogramRoot 指定的小程序目录 %s,%s 未找到', PLUGIN_JSON_NOT_FOUND: '根据 project.config.json 中 pluginRoot 指定的小程序本地开发插件目录 %s,%s 未找到', PLUGIN_PATH_SAME_WITH_MINIPROGRAM: 'project.config.json 中 pluginRoot 指定的小程序本地开发插件目录 %s,与小程序目录 %s 相同,请修改为不同目录', FILE_NOT_FOUND: '未找到 %s 文件,或者文件读取失败', JSON_PARSE_ERROR: '%s 文件解析错误', ENTRANCE_NOT_FOUND: '未找到入口页面\napp.json 中定义的 pages : %s', JSON_PAGE_FILE_NOT_EXISTS: '未找到 %s 中的定义的 %s "%s" 对应的 %s 文件', SHOULD_NOT_IN: '%s 不应该在 %s 中', JSON_CUSTOM_COMPILE_PATH_NOT_EXISTS_TITLE: 'app.json 或自定义编译条件错误', JSON_CUSTOM_COMPILE_PATH_NOT_EXISTS: 'app.json 中未定义自定义编译中指定的启动页面 %s', JSON_ENTRY_PAGE_PATH_NOT_FOUND: '未在 %s 中找到 %s 定义的入口页面', JSON_TABBAR_AT_LEAST: '["tabBar"]["list"] 需至少包含 %s 项', JSON_TABBAR_AT_MOST: '["tabBar"]["list"] 不能超过 %s 项', JSON_TABBAR_PATH_EMPTY: '["tabBar"]["list"][%s]["pagePath"] 不能为空', JSON_TABBAR_PATH_SAME_WITH_OTHER: '["tabBar"]["list"][%s]["pagePath"] 和 ["tabBar"]["list"][%s]["pagePath"] 相同', JSON_TABBAR_ICON_MAX_SIZE: '["tabBar"]["list"][%s]["%s"] 大小超过 %skb', JSON_TABBAR_ICON_EXT: '["tabBar"]["list"][%s]["%s"] 文件格式错误,仅支持 %s 格式', JSON_CONTENT_SHOULD_NOT_BE: '%s 不能为 %s', JSON_RESOLVE_ALIAS_ILLEGAL: 'resolveAlias 配置中 %s 或 %s 不合法,包含连续的 "//"', JSON_RESOLVE_ALIAS_INCLUDE_STAR: 'resolveAlias 配置中 %s 或 %s 需要用 "/*" 结尾', APP_JSON_SHOULD_SET_LAZYCODELOADING: '%s 中 "renderer" 设置为 "skyline",需在 app.json 添加 "lazyCodeLoading": "requiredComponents"', APP_JSON_CONTENT_ERROR: 'miniprogram_npm 目录下的 %s 包与扩展库 %s 发生冲突,请移除 %s 包或者删除 `useExtendedLib.%s` 配置', PAGE_JSON_SHOULD_SET_DISABLESCROLL_TRUE: '根据页面或 app.json 的配置,%s 页面 "renderer" 为 "skyline",需在页面配置中添加 "disableScroll": true', PAGE_JSON_SHOULD_SET_NAVIGATIONSTYLE_CUSTOM: '根据页面或 app.json 的配置,%s 页面 "renderer" 为 "skyline",需在页面配置中添加 "navigationStyle": custom', CONTENT_EXIST: '%s 已经存在', JSON_CONTENT_EXISTED: '%s 已经存在', JSON_CONTENT_NOT_FOUND: '%s 不存在', LACK_OF_FILE: '缺少文件 %s', JSON_PAGES_REPEAT: '%s 在 %s 中重复', JSON_CONTENT_REPEAT: '%s 不能同时在 %s 中声明', EXT_JSON_INVALID: '%s 不是 3rdMiniProgramAppid, ext.json 无法生效;查看文档: "%s"', GAME_EXT_JSON_INVALID: '%s 不是 3rdMiniGameAppid, ext.json 无法生效;"%s"', EXT_APPID_SHOULD_NOT_BE_EMPTY: 'extAppid 不能为空', FILE_NOT_UTF8: '%s 文件不是 UTF-8 格式', INVALID: '无效的 %s', DIRECTORY: '目录', EXCEED_LIMIT: '%s 超过限制 %s', PLEASE_CHOOSE_PLUGIN_MODE: '如果正在开发插件,请选择插件模式', TRIPLE_NUMBER_DOT: '数字.数字.数字', PAGE_PATH: '页面路径', PLUGINS_SAME_ALIAS: '%s 和 %s 的别名相同', SAME_ITEM: '%s 和 %s 的 "%s" 相同', ALREADY_EXISTS: '已存在', SAME_KEY_PAGE_PUBLICCOMPONENTS: '["pages"] 与 ["publicComponents"] 不能存在相同的 key: %s', GAME_DEV_PLUGIN_SHOULD_NOT_USE_LOCAL_PATH: '开发版插件 %s 不能使用 %s 指定本地路径', GAME_PLUGIN_SIGNATURE_MD5_NOT_MATCH_CONTENT: '插件文件 "%s" 的 MD5: "%s" 与其 signature.json 所给定的值: "%s" 不匹配, 因此编译过程已经中断。\n这表示此文件的内容可能已经被修改。\n恢复此文件的原始内容可能可以解决此问题并移除此警告。\n\n要了解更多,可以参考文档。\n', FILE: '文件', PROCESSING: '处理中: %s', DONE: '完成: %s', UPLOAD: '上传', SUCCESS: '成功', PROJECT_TYPE_ERROR: 'project.type 是 %s, 但 appid(%s) 是 %s', MINI_PROGRAM: '小程序', MINI_GAME: '小游戏', NOT_ALLOWED_REQUIRE_VAR: '不允许require变量', NOT_ALLOWED_REQUIRE_ASSIGN: '不允许将require函数赋值给其他变量', NOT_FOUND_NPM_ENTRY: '未找到npm包入口文件', NOT_FOUND_NODE_MODULES: '没有找到可以构建的 NPM 包,请确认需要参与构建的 npm 都在 `miniprogramRoot` 目录内,或配置 project.config.json 的 packNpmManually 和 packNpmRelationList 进行构建', JSON_ENTRANCE_DECLARE_PATH_ERR: '["entranceDeclare"]["locationMessage"]["path"] "%s" 需在 pages 数组或分包 pages 数组中', JSON_ENTRANCE_DECLARE_PATH_EMPTY: '["entranceDeclare"]["locationMessage"]["path"] 不能为空', COULD_NOT_USE_CODE_PROTECT: '无法使用代码保护功能', SUMMER_COMPILING_MODULE: '编译 %s', SUMMER_COMPILE_JSON: '编译 JSON 文件', SUMMER_OPTIMIZE_CODE: '优化代码', SUMMER_PACK_FILES: '打包资源文件', SUMMER_COMPRESS_PACK: '压缩代码包', SUMMER_SEAL_PACK: '封装代码包', SUMMER_APPEND_BABEL_HELPERS: '追加 babel helper 文件', SUMMER_COMPILE_PAGE_JSON: '编译 %s 个页面json文件', SUMMER_COMPILE_PLUGIN_PAGE_JSON: '编译插件 %s 个页面json文件', SUMMER_COMPILE: '编译 %s', SUMMER_COMPILE_MINIPROGRAM: '编译打包小程序', SUMMER_COMPILE_PLUGIN: '编译打包插件', SUMMER_COMPILE_ENABLE_LAZYLOAD: '开启了依赖注入,请将基础库至少升级到 3.0.38', }; const tipTemplateConfig = {}; for (const [key, v] of Object.entries(template$1)) tipTemplateConfig[key] = new FormatableString(v); function normalizePath(filePath = '') { const format = path__default["default"].posix.normalize(filePath.replace(/\\/g, '/')); const hasSlash = (!filePath.startsWith('//') && !filePath.startsWith('\\\\')) || format.startsWith('//'); return hasSlash ? format : '/' + format } const bufferToUtf8String = (e) => { const t = e.toString(); if (0 === Buffer.compare(Buffer.from(t, 'utf8'), e)) return t }; function leading(e, t, s = !1) { return s ? e.startsWith(t) ? e.slice(1) : e : e.startsWith(t) ? e : t + e } const babelHelperApiConf = { applyDecoratedDescriptor: [], arrayLikeToArray: [], arrayWithHoles: [], arrayWithoutHoles: ['arrayLikeToArray'], assertThisInitialized: [], AsyncGenerator: ['AwaitValue'], asyncGeneratorDelegate: [], asyncIterator: [], asyncToGenerator: [], awaitAsyncGenerator: ['AwaitValue'], AwaitValue: [], classCallCheck: [], classNameTDZError: [], classPrivateFieldDestructureSet: [], classPrivateFieldGet: [], classPrivateFieldLooseBase: [], classPrivateFieldLooseKey: [], classPrivateFieldSet: [], classPrivateMethodGet: [], classPrivateMethodSet: [], classStaticPrivateFieldSpecGet: [], classStaticPrivateFieldSpecSet: [], classStaticPrivateMethodGet: [], classStaticPrivateMethodSet: [], construct: ['setPrototypeOf', 'isNativeReflectConstruct'], createClass: [], createForOfIteratorHelper: ['unsupportedIterableToArray'], createForOfIteratorHelperLoose: ['unsupportedIterableToArray'], createSuper: [ 'getPrototypeOf', 'isNativeReflectConstruct', 'possibleConstructorReturn' ], decorate: ['toArray', 'toPropertyKey'], defaults: [], defineEnumerableProperties: [], defineProperty: [ 'toPropertyKey' ], extends: [], get: ['superPropBase'], getPrototypeOf: [], inherits: ['setPrototypeOf'], inheritsLoose: [], initializerDefineProperty: [], initializerWarningHelper: [], instanceof: [], interopRequireDefault: [], interopRequireWildcard: ['typeof'], isNativeFunction: [], isNativeReflectConstruct: [], iterableToArray: [], iterableToArrayLimit: [], iterableToArrayLimitLoose: [], jsx: [], maybeArrayLike: ['arrayLikeToArray'], newArrowCheck: [], nonIterableRest: [], nonIterableSpread: [], objectDestructuringEmpty: [], objectSpread: ['defineProperty'], objectSpread2: ['defineProperty'], objectWithoutProperties: ['objectWithoutPropertiesLoose'], objectWithoutPropertiesLoose: [], possibleConstructorReturn: ['typeof', 'assertThisInitialized'], readOnlyError: [], set: ['superPropBase', 'defineProperty'], setPrototypeOf: [], skipFirstGeneratorNext: [], slicedToArray: [ 'arrayWithHoles', 'iterableToArrayLimit', 'unsupportedIterableToArray', 'nonIterableRest' ], slicedToArrayLoose: [ 'arrayWithHoles', 'iterableToArrayLimitLoose', 'unsupportedIterableToArray', 'nonIterableRest' ], superPropBase: ['getPrototypeOf'], taggedTemplateLiteral: [], taggedTemplateLiteralLoose: [], tdz: [], temporalRef: ['temporalUndefined', 'tdz'], temporalUndefined: [], toArray: [ 'arrayWithHoles', 'iterableToArray', 'unsupportedIterableToArray', 'nonIterableRest' ], toConsumableArray: [ 'arrayWithoutHoles', 'iterableToArray', 'unsupportedIterableToArray', 'nonIterableSpread' ], toPrimitive: ['typeof'], toPropertyKey: ['typeof', 'toPrimitive'], typeof: [], unsupportedIterableToArray: ['arrayLikeToArray'], wrapAsyncGenerator: ['AsyncGenerator'], wrapNativeSuper: [ 'getPrototypeOf', 'setPrototypeOf', 'isNativeFunction', 'construct' ], wrapRegExp: [ 'typeof', 'wrapNativeSuper', 'getPrototypeOf', 'possibleConstructorReturn', 'inherits' ], regeneratorRuntime: [ 'typeof' ], Objectentries: [], Objectvalues: [], Arrayincludes: [], regenerator: [ 'regeneratorRuntime' ], callSuper: [ 'getPrototypeOf', 'isNativeReflectConstruct', 'possibleConstructorReturn' ] }; function isIgnore(e, t) { const s = e || [], r = t.split(path__default["default"].sep).join('/'); for (const e of s) { if (t === e) return !0 if ( !/^[./\\]+/.test(e) && /.+\/\*$/.test(e) && -1 !== r.indexOf(e.substr(0, e.length - 1)) ) return !0 } return !1 } function collectBabelHelpers(e) { const t = {}; return ( e.replace( /require\("(@babel\/runtime\/[^"]+)"\)/gi, (e, s) => ((t[s] = !0), e) ), t ) } function replaceBabelHelpers(e, t, s, r) { t || (t = {}); // 按照commonjs相对路径规范引入模块 const n = new Set(), i = s .split('/') .map((e, t) => (0 === t ? '' : '../')) .join(''); return { transformCode: e.replace( /require\("(@babel\/runtime\/[^"]+)"\)/gi, (e, s) => { const o = s .replace(/@babel\/runtime\/(helpers\/)?/, '') .replace(/\.js$/, ''), a = s.replace('@babel/runtime', r), c = Object.prototype.hasOwnProperty.call(babelHelperApiConf, o); return !t[s] && c ? (n.add(a), `require("${i + a}")`) : e } ), helpers: Array.from(n) } } function getDefaultPlugins() { const e = [ [require.resolve('@babel/plugin-proposal-function-bind'), 0], // proposal-function-bind [require.resolve('@babel/plugin-proposal-export-default-from'), 0], // proposal-export-default-from [ require.resolve('@babel/plugin-proposal-pipeline-operator'), { proposal: 'minimal' } ], // proposal-pipeline-operator [require.resolve('@babel/plugin-proposal-do-expressions'), 0], // proposal-do-expressions [require.resolve('@babel/plugin-proposal-decorators'), { legacy: !0 }], // proposal-decorators [require.resolve('@babel/plugin-proposal-function-sent'), 0], // proposal-function-sent [require.resolve('@babel/plugin-proposal-throw-expressions'), 0], // proposal-throw-expressions [require.resolve('@babel/plugin-proposal-class-properties'), { loose: !0 }], // proposal-class-properties [require.resolve('@babel/plugin-proposal-private-methods'), { loose: !0 }] // proposal-private-methods ]; return new Map(e) } function getCustomPlugins(extra = []) { const base = getDefaultPlugins(); const result = []; for (const [pluginName, options] of base) 0 === options ? result.push(pluginName) : result.push([pluginName, options]); return result } var log = { info: console.info, log: console.log, warn: console.warn, error: console.error, debug: (...e) => {}, }; function jsonParse(e) { try { return JSON.parse(e) } catch (t) { throw ( (log.info('jsonParse error, input string:'), log.info(e), t) ) } } var COMPILE_SOURCES; (function (COMPILE_SOURCES) { COMPILE_SOURCES["wx"] = "wx"; COMPILE_SOURCES["tt"] = "tt"; COMPILE_SOURCES["ali"] = "ali"; COMPILE_SOURCES["hy"] = "hy"; })(COMPILE_SOURCES || (COMPILE_SOURCES = {})); const BABEL_TRANS_JS_ERR = 10032; const UGLIFY_JS_ERR = 10033; const POST_WXSS_ERR = 10037; const MINIFY_WXML_ERR = 10038; const FILE_NOT_FOUND = 10005; const FILE_NOT_UTF8$1 = 10031; var COMPILE_TYPE; (function (COMPILE_TYPE) { COMPILE_TYPE["miniProgram"] = "miniProgram"; COMPILE_TYPE["miniProgramPlugin"] = "miniProgramPlugin"; COMPILE_TYPE["miniGame"] = "miniGame"; COMPILE_TYPE["miniGamePlugin"] = "miniGamePlugin"; })(COMPILE_TYPE || (COMPILE_TYPE = {})); const minify = e => { const { code: t, inputSourceMap: n, useTerser: a, filePath: l } = e, u = n ? { includeSources: !0, content: n, filename: l } : { includeSources: !0, content: void 0, filename: l }, c = a ? UglifyJS__default["default"].minify(t, { output: { comments: !1 }, toplevel: !0, compress: { drop_console: !1, drop_debugger: !1 }, sourceMap: u }) : UglifyJS__default["default"].minify(t, { toplevel: !0, sourceMap: u }); if (c.error) { const e = c.error; return { error: { message: `file: ${l}\n ${c.error.message}\n ${codeFrame__default["default"]( t, e.line, e.col > 0 ? e.col : 1 )}`, code: UGLIFY_JS_ERR } } } return c // { code, error } }; // 密封,生成 source map + compress js const seal = e => { const t = (e => { const { code: t, filePath: n, inputSourceMap: r } = e; if (r) { const e = new sourceMap.SourceMapConsumer(r), t = new sourceMap.SourceMapGenerator({ file: n }); return ( e.eachMapping(e => { if ( 'number' != typeof e.originalLine || 'number' != typeof e.originalColumn ) return const n = { generated: { line: e.generatedLine + 1, column: e.generatedColumn }, original: { line: 0, column: 0 }, source: '' }; e.source || ((n.source = e.source), (n.original = { line: e.originalLine, column: e.originalColumn }), e.name || (n.name = e.name)), t.addMapping(n); }), e.sources.forEach(n => { const r = n; t._sources.has(r) || t._sources.add(r); const o = e.sourceContentFor(n); null !== o && t.setSourceContent(n, o); }), t.toJSON() ) } const o = new sourceMap.SourceMapGenerator({ file: n }), s = t.split('\n').length; for (let e = 0; e < s; e++) o.addMapping({ generated: { line: e + 2, column: 0 }, original: { line: e + 1, column: 0 }, source: n }); return o._sources.add(n), o.setSourceContent(n, t), o.toJSON() })(Object.assign({}, e)), n = minify( Object.assign(Object.assign({}, e), { inputSourceMap: t, code: `(function(){\n${e.code}\n})()`, useTerser: !0 }) ); return n.error ? (console.error(n.error), minify(Object.assign(Object.assign({}, e), { useTerser: !0 }))) : n }; const transformJSByES6 = e => { const { code: t, filePath: o, inputSourceMap: a } = e; try { const e = core.transform(t, { presets: ['babel-preset-es2015', 'babel-preset-stage-0'].map(e => require.require(e) ), babelrc: !1, sourceFileName: o, filename: o, inputSourceMap: a, sourceMaps: !0 }); return { code: e.code, map: e.map } } catch (e) { return e.loc ? { error: { message: `file: ${o}\n ${e.message}\n ${codeFrame__default["default"]( t, e.loc.line, e.loc.column > 0 ? e.loc.column : 1 )}`, code: BABEL_TRANS_JS_ERR } } : { error: { message: '' + e, code: BABEL_TRANS_JS_ERR } } } }; var transfromRuntimeCustomPlugin = { name: 'transform-runtime-custom', pre(e) { const t = new Map(); this.addDefaultImport = (n, i, s) => { const a = `${n}:${i}:${helperModuleImports.isModule(e.path) || ''}`; let l = t.get(a); return ( l ? (l = core.types.cloneNode(l)) : ((l = helperModuleImports.addSideEffect(e.path, n, { importedInterop: 'uncompiled', nameHint: i, blockHoist: s })), t.set(a, l)), l ) }; }, visitor: { MemberExpression: { enter(e) { const { node: t } = e, { object: n, property: o } = t; if (!core.types.isReferenced(n, t)) return let i = n.name; const s = o.name ;(function(e, t, n, r) { try { if ('Object' === e) { if ('entries' === t || 'values' === t) return !0 } else if ('includes' === t) { if ('Identifier' === n || 'ArrayExpression' === n) return !0 if ( 'MemberExpression' === n && 'prototype' === r.property.name && 'Array' === r.object.name ) return !0 } return !1 } catch (e) { return !1 } })(i, s, n.type, n) && ('Object' !== i && (i = 'Array'), this.addDefaultImport(`@babel/runtime/helpers/${i}${s}`)); } } } }; const template = require('@babel/template').default; const generate = require('@babel/generator').default; const hash = require('string-hash-64'); const { transformSync } = require('@babel/core'); const traverse = require('@babel/traverse').default; const parse = require('@babel/parser').parse; const nodePath = require('path'); const buildBindFunc = func => template.ast(` var _${func}_ = this.${func}.bind(this); `); const buildWorkletFunc = func => template.ast(` var ${func} = this._${func}_worklet_factory_(); `); const globals = new Set([ 'this', 'console', '_setGlobalConsole', 'Date', 'Array', 'ArrayBuffer', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'Date', 'HermesInternal', 'JSON', 'Math', 'Number', 'Object', 'String', 'Symbol', 'undefined', 'null', 'UIManager', 'requestAnimationFrame', '_WORKLET', 'arguments', 'Boolean', 'parseInt', 'parseFloat', 'Map', 'Set', '_log', '_updateProps', 'RegExp', 'Error', 'global', '_measure', '_scrollTo', '_setGestureState', '_getCurrentTime', '_eventTimestamp', '_frameTimestamp', 'isNaN', 'LayoutAnimationRepository', '_stopObservingProgress', '_startObservingProgress', // For skyline 'setTimeout', 'globalThis', 'workletUIModule', ]); // leaving way to avoid deep capturing by adding 'stopCapturing' to the blacklist const blacklistedFunctions = new Set([ 'stopCapturing', 'toString', 'map', 'filter', 'forEach', 'valueOf', 'toPrecision', 'toExponential', 'constructor', 'toFixed', 'toLocaleString', 'toSource', 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'localeCompare', 'length', 'match', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toUpperCase', 'every', 'join', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'unshift', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'bind', 'apply', 'call', '__callAsync', 'includes', ]); const possibleOptFunction = new Set(['interpolate']); class ClosureGenerator { constructor() { this.trie = [{}, false]; } mergeAns(oldAns, newAns) { const [purePath, node] = oldAns; const [purePathUp, nodeUp] = newAns; if (purePathUp.length !== 0) { return [purePath.concat(purePathUp), nodeUp] } else { return [purePath, node] } } findPrefixRec(path) { const notFound = [[], null]; if (!path || path.node.type !== 'MemberExpression') { return notFound } const memberExpressionNode = path.node; if (memberExpressionNode.property.type !== 'Identifier') { return notFound } if ( memberExpressionNode.computed || memberExpressionNode.property.name === 'value' || blacklistedFunctions.has(memberExpressionNode.property.name) ) { // a.b[w] -> a.b.w in babel nodes // a.v.value // sth.map(() => ) return notFound } if (path.parent && path.parent.type === 'AssignmentExpression' && path.parent.left === path.node) { /// captured.newProp = 5; return notFound } const purePath = [memberExpressionNode.property.name]; const node = memberExpressionNode; const upAns = this.findPrefixRec(path.parentPath); return this.mergeAns([purePath, node], upAns) } findPrefix(base, babelPath) { const purePath = [base]; const node = babelPath.node; const upAns = this.findPrefixRec(babelPath.parentPath); return this.mergeAns([purePath, node], upAns) } addPath(base, babelPath) { const [purePath, node] = this.findPrefix(base, babelPath); let parent = this.trie; let index = -1; for (const current of purePath) { index++; if (parent[1]) { continue } if (!parent[0][current]) { parent[0][current] = [{}, false]; } if (index === purePath.length - 1) { parent[0][current] = [node, true]; } parent = parent[0][current]; } } generateNodeForBase(t, current, parent) { const currentNode = parent[0][current]; if (currentNode[1]) { return currentNode[0] } return t.objectExpression( Object.keys(currentNode[0]).map(propertyName => t.objectProperty( t.identifier(propertyName), this.generateNodeForBase(t, propertyName, currentNode), false, true, ), ), ) } generate(t, variables, names) { const arrayOfKeys = [...names]; return t.objectExpression( variables.map((variable, index) => t.objectProperty( t.identifier(variable.name), this.generateNodeForBase(t, arrayOfKeys[index], this.trie), false, true, ), ), ) } } function buildWorkletString(t, fun, closureVariables, name) { function prependClosureVariablesIfNecessary(closureVariables, body) { if (closureVariables.length === 0) { return body } return t.blockStatement([ t.variableDeclaration('const', [ t.variableDeclarator( t.objectPattern( closureVariables.map(variable => t.objectProperty(t.identifier(variable.name), t.identifier(variable.name), false, true), ), ), t.memberExpression(t.identifier('jsThis'), t.identifier('_closure')), ), ]), body, ]) } traverse(fun, { enter(path) { t.removeComments(path.node); }, }); const workletFunction = t.functionExpression( t.identifier(name), fun.program.body[0].expression.params, prependClosureVariablesIfNecessary(closureVariables, fun.program.body[0].expression.body), ); return generate(workletFunction, { compact: true }).code } function generateWorkletFactory(t, fun) { const map = new Map(); fun.traverse({ CallExpression: { enter(path) { if (!t.isMemberExpression(path.node.callee)) return const routes = []; let iter = path.node.callee; // find out invoke path while (t.isMemberExpression(iter)) { const route = iter.property.name; routes.unshift(route); iter = iter.object; } // start with this if (!t.isThisExpression(iter)) return // output: [this, bar] // console.log('routes: ', ['this', ...routes]) let funcName = routes[routes.length - 1]; // function in JS thread, like this.func.bind(this) if (funcName === 'bind') { funcName = routes[routes.length - 2]; map.set(funcName, 'bind'); path.replaceWith(t.identifier(`_${funcName}_`)); return } // function in UI thread, like this.func() path.get('callee').replaceWith(t.identifier(funcName)); map.set(funcName, 'worklet'); }, }, }); const statements = []; map.forEach((value, key) => { const statement = value === 'bind' ? buildBindFunc(key) : buildWorkletFunc(key); statements.push(statement); }); const funExpression = t.arrowFunctionExpression(fun.node.params, fun.node.body); const functionId = t.identifier('f'); const factoryFun = t.functionExpression( null, [], t.blockStatement([ ...statements, t.variableDeclaration('var', [t.variableDeclarator(functionId, funExpression)]), t.returnStatement(functionId), ]), ); return factoryFun } // remove worklet directive function removeWorkletDirective(fun) { let result; const copy = parse('\n(' + fun.toString() + '\n)'); traverse(copy, { DirectiveLiteral(path) { if (path.node.value === 'worklet') { path.parentPath.remove(); } }, Program: { exit(path) { result = path.get('body.0.expression').node; }, }, }); return result } function makeWorkletName(t, fun) { if (t.isObjectMethod(fun)) { return fun.node.key.name } if (t.isFunctionDeclaration(fun)) { return fun.node.id.name } if (t.isFunctionExpression(fun) && t.isIdentifier(fun.node.id)) { return fun.node.id.name } return '_f' // fallback for ArrowFunctionExpression and unnamed FunctionExpression } function makeWorklet(t, fun, fileName) { // Returns a new FunctionExpression which is a workletized version of provided // FunctionDeclaration, FunctionExpression, ArrowFunctionExpression or ObjectMethod. const functionName = makeWorkletName(t, fun); const closure = new Map(); const outputs = new Set(); const closureGenerator = new ClosureGenerator(); // remove 'worklet'; directive before calling .toString() fun.traverse({ DirectiveLiteral(path) { if (path.node.value === 'worklet' && path.getFunctionParent() === fun) { path.parentPath.remove(); } }, }); // We use copy because some of the plugins don't update bindings and // some even break them const code = '\n(' + (t.isObjectMethod(fun) ? 'function ' : '') + fun.toString() + '\n)'; const transformed = transformSync(code, { filename: fileName, presets: ['@babel/preset-typescript'], plugins: [ '@babel/plugin-transform-shorthand-properties', '@babel/plugin-transform-arrow-functions', '@babel/plugin-proposal-optional-chaining', '@babel/plugin-proposal-nullish-coalescing-operator', ['@babel/plugin-transform-template-literals', { loose: true }], ], ast: true, babelrc: false, configFile: false, }); if (fun.parent && fun.parent.callee && fun.parent.callee.name === 'createAnimatedStyle') { isPossibleOptimization(transformed.ast); } traverse(transformed.ast, { ReferencedIdentifier(path) { const name = path.node.name; if (globals.has(name) || (fun.node.id && fun.node.id.name === name)) { return } const parentNode = path.parent; if (parentNode.type === 'MemberExpression' && parentNode.property === path.node && !parentNode.computed) { return } if ( parentNode.type === 'ObjectProperty' && path.parentPath.parent.type === 'ObjectExpression' && path.node !== parentNode.value ) { return } let currentScope = path.scope; while (currentScope != null) { if (currentScope.bindings[name] != null) { return } currentScope = currentScope.parent; } closure.set(name, path.node); closureGenerator.addPath(name, path); }, AssignmentExpression(path) { // test for <something>.value = <something> expressions const left = path.node.left; if ( t.isMemberExpression(left) && t.isIdentifier(left.object) && t.isIdentifier(left.property, { name: 'value' }) ) { outputs.add(left.object.name); } }, }); const variables = Array.from(closure.values()); const privateFunctionId = t.identifier('_f'); const clone = t.cloneNode(fun.node); let funExpression; if (clone.body.type === 'BlockStatement') { funExpression = t.functionExpression(null, clone.params, clone.body); } else { funExpression = clone; } const funString = buildWorkletString(t, transformed.ast, variables, functionName); const workletHash = hash(funString); const loc = fun && fun.node && fun.node.loc && fun.node.loc.start; if (loc) { const { line, column } = loc; if (typeof line === 'number' && typeof column === 'number') { fileName = `${fileName} (${line}:${column})`; } } const statements = [ t.variableDeclaration('const', [t.variableDeclarator(privateFunctionId, funExpression)]), t.expressionStatement( t.assignmentExpression( '=', t.memberExpression(privateFunctionId, t.identifier('_closure'), false), closureGenerator.generate(t, variables, closure.keys()), ), ), t.expressionStatement( t.assignmentExpression( '=', t.memberExpression(privateFunctionId, t.identifier('asString'), false), t.stringLiteral(funString), ), ), t.expressionStatement( t.assignmentExpression( '=', t.memberExpression(privateFunctionId, t.identifier('__workletHash'), false), t.numericLiteral(workletHash), ), ), t.expressionStatement( t.assignmentExpression( '=', t.memberExpression(privateFunctionId, t.identifier('__location'), false), t.stringLiteral(fileName), ), ), t.expressionStatement( t.assignmentExpression( '=', t.memberExpression(privateFunctionId, t.identifier('__worklet'), false), t.booleanLiteral(true), ), ), ]; statements.push(t.returnStatement(privateFunctionId)); const newFun = t.functionExpression(fun.id, [], t.blockStatement(statements)); return newFun } function processWorkletFunction(t, fun, fileName) { // Replaces FunctionDeclaration, FunctionExpression or ArrowFunctionExpression // with a workletized version of itself. if (!t.isFunctionParent(fun)) { return } // "var option = { methods: { func() {'worklet';} } } in Component" // or "var option = { func() {'worklet;'} } in Page" // if (fun.parentPath.isObjectProperty()) { // const parentNodePath = fun.parentPath.parentPath; // if ( // parentNodePath.isObjectExpression() && // parentNodePath.parentPath.isObjectProperty() // ) { // const parentPropName = parentNodePath.parent.key.name; // if (parentPropName == "methods") {} // } // } if (fun.parentPath.isObjectProperty()) { const name = fun.parent.key.name; const copyNode = removeWorkletDirective(fun); const factoryFun = generateWorkletFactory(t, fun); const factoryFunName = `_${name}_worklet_factory_`; fun.parentPath.replaceWithMultiple([ t.objectProperty(t.identifier(name), copyNode, false, false), t.objectProperty(t.identifier(factoryFunName), factoryFun, false, false), ]); return } const newFun = makeWorklet(t, fun, fileName); const replacement = t.callExpression(newFun, []); // we check if function needs to be assigned to variable declaration. // This is needed if function definition directly in a scope. Some other ways // where function definition can be used is for example with variable declaration: // const ggg = function foo() { } // ^ in such a case we don't need to define variable for the function const needDeclaration = t.isScopable(fun.parent) || t.isExportNamedDeclaration(fun.parent); fun.replaceWith( fun.node.id && needDeclaration ? t.variableDeclaration('const', [t.variableDeclarator(fun.node.id, replacement)]) : replacement, ); } function processIfWorkletNode(t, fun, fileName) { fun.traverse({ DirectiveLiteral(path) { const value = path.node.value; if (value === 'worklet' && path.getFunctionParent() === fun) { // make sure "worklet" is listed among directives for the fun // this is necessary as because of some bug, babel will attempt to // process replaced function if it is nested inside another function const directives = fun.node.body.directives; if ( directives && directives.length > 0 && directives.some(directive => t.isDirectiveLiteral(directive.value) && directive.value.value === 'worklet') ) { processWorkletFunction(t, fun, fileName); } } }, }); } const FUNCTIONLESS_FLAG = 0b00000001; const STATEMENTLESS_FLAG = 0b00000010; function isPossibleOptimization(fun) { let isFunctionCall = false; let isStatement = false; traverse(fun, { CallExpression(path) { if (!possibleOptFunction.has(path.node.callee.name)) { isFunctionCall = true; } }, IfStatement() { isStatement = true; }, }); let flags = 0; if (!isFunctionCall) { flags = flags | FUNCTIONLESS_FLAG; } if (!isStatement) { flags = flags | STATEMENTLESS_FLAG; } return flags } function workletPlugin ({ types: t }) { return { pre() { // allows adding custom globals such as host-functions if (this.opts != null && Array.isArray(this.opts.globals)) { this.opts.globals.forEach(name => { globals.add(name); }); } }, visitor: { 'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression': { enter(path, state) { let fileName = state.file.opts.filename; fileName = nodePath.relative(__dirname, fileName); processIfWorkletNode(t, path, fileName); }, }, }, } } function getPlugins$2(e) { const plugins = [ [transfromRuntimeCustomPlugin], [ require.resolve('@babel/plugin-transform-runtime'), { corejs: false, helpers: true, regenerator: !e.hasRegenerator, version: '7.12.1' } ] ].concat(getCustomPlugins([])); plugins.push([ require.resolve('@babel/plugin-transform-modules-commonjs'), { allowTopLevelThis: e.disableUseStrict, importInterop: e => e.startsWith('@babel/runtime/helpers/') ? 'node' : 'babel' } ]); e.supportWorklet && plugins.push([workletPlugin]); return plugins } const transformJSByES7 = options => { const { code, babelRoot, filePath, inputSourceMap } = options, hasRegenerator = /regeneratorRuntime\.mark/.test(code), disableUseStrict = options.disableUseStrict || /^\s*\/\/\s?use strict disable;/i.test(code), supportWorklet = code.includes('"worklet"') || code.includes("'worklet'"); let result = null; try { result = core.transform(code, { presets: [ [ require.resolve('@babel/preset-env'), { targets: { chrome: 53, ios: 8 }, include: ['@babel/plugin-transform-computed-properties'] } ] ], babelrc: false, plugins: getPlugins$2({ hasRegenerator, disableUseStrict, supportWorklet }), sourceFileName: filePath, inputSourceMap, sourceMaps: false, configFile: false }); } catch (e) { return { error: { message: `file: ${filePath}\n ${e.message}`, code: BABEL_TRANS_JS_ERR } } } let compiledCode = (result && result.code) || code; const sourceMap = (result && result.map) || inputSourceMap; disableUseStrict && (compiledCode = compiledCode.replace(/^"use strict";/, '')); const rawHelpers = collectBabelHelpers(code); const { transformCode, helpers } = replaceBabelHelpers(compiledCode, rawHelpers, filePath, babelRoot); return { code: transformCode, map: sourceMap, helpers: helpers|| [] } }; function readFileAsync(filePath, options) { return new Promise((resolve, reject) => { fs__default["default"].readFile(filePath, options, (err, buff) => { if (err) return reject(e) resolve(buff); }); }) } var readFile = { readFileAsync }; function createCallChildThreadAPIFn() { if (WokerThreads__default["default"].isMainThread) return () => {} let hash = 0; const promiseMap = {}; return ( WokerThreads__default["default"].parentPort && WokerThreads__default["default"].parentPort.on('message', e => { const { command: n, data: r } = e; if (n !== COMMAND.CALL_FUNC_RESULT) return const { id: o, result: s, error: a } = r, l = promiseMap[o]; return delete promiseMap[o], l ? (a ? l.reject(a) : void l.resolve(s)) : void 0 }), (funcName, args) => new Promise((o, a) => { const id = hash++ ;(promiseMap[id] = { resolve: o, reject: a }), WokerThreads__default["default"].parentPort && WokerThreads__default["default"].parentPort.postMessage({ command: COMMAND.CALL_FUNC, data: { id, funcName, args } }); }) ) } const callChildThreadAPI = createCallChildThreadAPIFn(); function call(e, ...t) { return WokerThreads__default["default"].isMainThread ? readFile[e].apply(null, t) : callChildThreadAPI(e, t) } const addSourcesContent$1 = async (e, t) => { if (Array.isArray(e.sources) && !Array.isArray(e.sourcesContent)) { const n = e.sourcesContent; try { const n = path__default["default"].posix.dirname(t), r = [], i = e.sources; for (const e of i) { const t = await call( 'readFileAsync', path__default["default"].posix.join(n, e), 'utf-8' ); r.push(t); } e.sourcesContent = r; } catch (t) { e.sourcesContent = n; } } }; async function compileJS(e) { const { code: t, filePath: n, projectPath: g, setting: y, babelRoot: _ = '@babel/runtime', root: b = '', babelIgnore: E = [] } = e, { es7: S, es6: O, disableUseStrict: w } = y, A = 'string' == typeof t ? t : bufferToUtf8String(Buffer.from(t)), P = path__default["default"].posix.join(b, n), M = y.minify || y.minifyJS; if (void 0 === A) return { error: { code: FILE_NOT_UTF8, path: P, message: tipTemplateConfig.FILE_NOT_UTF8.format(P) } } const N = A.length >= 512e3; let C = !1; S && (C = isIgnore(E, n)); const x = await (async function(e, t) { try { const n = /\/\/[#|@] sourceMappingURL=[\s]*(\S*)[\s]*$/m.exec(e), i = path__default["default"].posix.dirname(t), s = path__default["default"].posix.basename(t); let l; if (n && n[1]) if (/\.js\.map$/.test(n[1])) l = await call('readFileAsync', path__default["default"].posix.join(i, n[1]), 'utf-8'); else { const e = n[1].split('base64,')[1]; l = Buffer.from(e, 'base64').toString(); } else { const e = path__default["default"].posix.join(i, s + '.map'); fs__default$1["default"].existsSync(e) && (l = await call('readFileAsync', e, 'utf-8')); } if (l) { const e = jsonParse(l); return new sourceMap.SourceMapConsumer(e), await addSourcesContent$1(e, t), e } } catch (e) { log.log(`try to get input sourcemap of ${t} catch error ${e}`); } })(A, path__default["default"].posix.join(g, b, n)); if (N || C) return { error: null, isLargeFile: N, isBabelIgnore: C, map: 'object' == typeof x ? JSON.stringify(x) : x, code: A, helpers: [] } let I = A, j = x, R = []; if (S) { const e = await transformJSByES7({ code: A, babelRoot: _, filePath: n, disableUseStrict: w, inputSourceMap: x }); if (e.error) return { error: Object.assign(Object.assign({}, e.error), { path: P }) } ;(I = e.code || ''), (j = e.map), (R = e.helpers || []); } else if (O) { const e = transformJSByES6({ code: A, filePath: n, inputSourceMap: x }); if (e.error) return { error: Object.assign(Object.assign({}, e.error), { path: P }) } ;(I = e.code || ''), (j = e.map); } if (M) if (O || S) { const e = minify({ filePath: n, code: I, useTerser: !!S, inputSourceMap: j }); if (e.error) return { error: Object.assign(Object.assign({}, e.error), { path: P }) } ;(I = e.code), (j = e.map); } else { const e = seal({ filePath: n, code: I, inputSourceMap: j }); if (e.error) return { error: Object.assign(Object.assign({}, e.error), { path: P }) } ;(I = e.code), (j = e.map); } if ('string' != typeof j) try { j && j.sourcesContent && (j.sourcesContent = j.sourcesContent.map(e => e.replace(/\r\n/g, '\n') )), (j = JSON.stringify(j)); } catch (e) { j = ''; } else j = j.replace(/\\r\\n/g, '\\n'); return { error: null, isLargeFile: N, isBabelIgnore: C, map: j, code: I.replace(/\r\n/g, '\n'), helpers: R || [] } } const browserslist = ['iOS >= 8', 'Chrome >= 37']; async function compileWXSS(e) { const { code: t, filePath: n, setting: l = {}, root: u = '' } = e, p = Buffer.from(t), h = bufferToUtf8String(p), { minify: m, minifyWXSS: T, autoPrefixWXSS: g } = l, y = path__default["default"].posix.join(u, n), _ = (m && !1 !== T) || T; if (void 0 === h) return { error: { code: FILE_NOT_UTF8$1, path: y, message: tipTemplateConfig.FILE_NOT_UTF8.format(y) } } if (_ || g) try { const plugins = []; return ( g && plugins.push(autoprefixer__default["default"]({ overrideBrowserslist: browserslist, remove: !1 })), { error: null, code: ( await postcss__default["default"](plugins).process(h, { from: leading(n, '/') }) ).css.replace(/\r\n/g, '\n') } ) } catch (e) { return ( log.error('postcss error @ ' + y), log.error(e), { error: { code: POST_WXSS_ERR, path: y, message: e.message } } ) } return { error: null, code: h.replace(/\r\n/g, '\n') } } process.env.BROWSERSLIST = process.env.BROWSERSLIST || 'iOS >= 8, Chrome >= 37'; function c$1(e) { return e.charCodeAt(0) >= 256 ? 256 : e.charCodeAt(0) } var f$1, d$1, p$1; !(function(e) { (e[(e.ATTR = 0)] = 'ATTR'), (e[(e.STRING1 = 1)] = 'STRING1'), (e[(e.STRING2 = 2)] = 'STRING2'), (e[(e.OTHERS = 3)] = 'OTHERS'); })(f$1 || (f$1 = {})), (function(e) { (e[(e.ERROR = -1)] = 'ERROR'), (e[(e.NOT_SET = 0)] = 'NOT_SET'), (e[(e.SIMPLE = 1)] = 'SIMPLE'), (e[(e.TAG_START = 2)] = 'TAG_START'), (e[(e.IN_TAG = 3)] = 'IN_TAG'), (e[(e.IN_TAG_WORD = 4)] = 'IN_TAG_WORD'), (e[(e.IN_STRING = 5)] = 'IN_STRING'), (e[(e.IN_STRING_ESCAPE = 6)] = 'IN_STRING_ESCAPE'), (e[(e.TAG_EQ = 7)] = 'TAG_EQ'), (e[(e.IN_STRING2 = 9)] = 'IN_STRING2'), (e[(e.IN_STRING2_ESCAPE = 10)] = 'IN_STRING2_ESCAPE'), (e[(e.IN_TEMPLATE_STRING = 11)] = 'IN_TEMPLATE_STRING'), (e[(e.IN_TEMPLATE_STRING_ESCAPE = 12)] = 'IN_TEMPLATE_STRING_ESCAPE'), (e[(e.IN_TEMPLATE_STRING2 = 13)] = 'IN_TEMPLATE_STRING2'), (e[(e.IN_TEMPLATE_STRING2_ESCAPE = 14)] = 'IN_TEMPLATE_STRING2_ESCAPE'), (e[(e.WAIT_TEMPLATE_START = 15)] = 'WAIT_TEMPLATE_START'), (e[(e.IN_TEMPLATE = 16)] = 'IN_TEMPLATE'), (e[(e.WAIT_TEMPLATE_END = 17)] = 'WAIT_TEMPLATE_END'), (e[(e.WAIT_FOR_RIGHT_BRACKET = 18)] = 'WAIT_FOR_RIGHT_BRACKET'), (e[(e.IN_COMMENT = 19)] = 'IN_COMMEN