UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

706 lines 28 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.replaceAssetsPrefix = exports.genReleaseBodyForParallel = exports.genReleaseBody = exports.getFrontendBundleFiles = exports.getNaslAnnotatedJSONFile = exports.addEntityToDefaultDS = exports.__getNaslAnnotatedJSON = exports.replaceAssets = exports.replaceFrontendTypesAssets = void 0; const concepts_1 = require("../../concepts"); const genBundleFiles_1 = require("../genBundleFiles"); const is_view_logic_1 = require("../../service/instruct-ruler/rules/is-view-logic"); const utils_1 = require("./utils"); const permission_1 = require("../permission"); const validation_1 = require("./validation"); const memory_optimization_1 = require("./memory-optimization"); const utils = __importStar(require("../../utils")); const config_1 = require("../../config"); const share_content_1 = require("./share-content"); /** * 替换端类型中的资源 * @param frontendTypes * @param fn */ function replaceFrontendTypesAssets(frontendTypes, fn) { frontendTypes.forEach((frontendType) => { (0, concepts_1.fastTraverseNaslObject)(frontendType, (node) => { const meta = (0, concepts_1.getConceptMeta)(node.concept); for (const key of meta.normalProperties) { const attr = node[key]; if (typeof attr === 'string') { fn(node, key, attr); } } }); }); } exports.replaceFrontendTypesAssets = replaceFrontendTypesAssets; function replaceAssets(app, json, opt) { // 非增量发布的发布状态排除 views,导出源码不排除 if (!opt?.isIncremental && opt?.realRelease) { json.frontendTypes.forEach((frontendType) => { frontendType.frontends.forEach((frontend) => { delete frontend.views; }); }); } const assets = opt?.assets ?? []; if (opt?.isExport) { // 导出前端源码+后端源码 if (opt?.ignoreFiles && Array.isArray(assets) && assets.length) { const assetsMap = opt.assetsMap; // 正则 const regex = utils.MediaURLOrPathRegex; /** * 注意⚠️ * 如果要调整目录结构,请下面函数的逻辑 * replaceAssetsPrefix */ replaceFrontendTypesAssets(json.frontendTypes, (node, key, url) => { if (['staticStyle'].includes(key)) { node[key] = url.replace(regex, (url) => { const asset = utils.getAssetFromAssetsMap(assetsMap, url); if (asset) { const assetName = asset.fileKey || asset.name; const path = `/assets/${assetName}`; config_1.config.assets.push({ path, isDir: false, url, }); const assetNames = (assetName?.split('/') || []).map((name) => encodeURIComponent(name)); const encodeAssetName = assetNames.join('/'); const encodePath = `/assets/${encodeAssetName}`; return encodePath; } return url; }); } else { const asset = utils.getAssetFromAssetsMap(assetsMap, url); if (asset) { // 这里是用户上传的图片链接 在导出的时候变为 离线下载的 // 上边也是同样的目的 只是处理的css样式里的图片链接 const assetName = asset.fileKey || asset.name; const path = `/assets/${assetName}`; config_1.config.assets.push({ path, isDir: false, url, }); const assetNames = (assetName?.split('/') || []).map((name) => encodeURIComponent(name)); const encodeAssetName = assetNames.join('/'); const encodePath = `/assets/${encodeAssetName}`; node[key] = encodePath; } } }); } } } exports.replaceAssets = replaceAssets; /** 获取全量标注数据 */ async function __getNaslAnnotatedJSON(app, opt) { let json; try { json = await app.naslServer.fastGetNaslAnnotatedJSON(app); await opt?.logPublishFunc?.('语言', '获取全量类型标注成功'); // Memory optimization is now integrated into the annotation process // No need for separate compaction step - saves memory and time await opt?.logPublishFunc?.('优化', '内存优化已集成到标注过程'); // 打印传给服务端的 nasl,为了服务端排查问题方便 if (utils.isDebugMode) { console.dir(json, '标注后的nasl'); } } catch (err) { console.error('代码标注失败', err.stack ?? err.message ?? err.toString()); throw err; } app.curDeployEnv = opt?.env; replaceAssets(app, json, opt); await opt?.logPublishFunc?.('资源', '前端静态资源替换完成'); return json; } exports.__getNaslAnnotatedJSON = __getNaslAnnotatedJSON; // 暂时发布的时候加一个实体 // 为了服务端发布,使用文件系统,标注的nasl 强制增加一个 // 服务端承诺 2024年10月份会挪走, @钟春燕 @杨剑飞 function addEntityToDefaultDS(app, defaultDS) { const tableName = 'lcap_async_task_' + (app.id || '').slice(0, 6); defaultDS.entities.push({ "concept": "Entity", "name": "LCAPAsyncTask", "uuid": "fe2cef1efd9c4189951b1f0bb6eacf11", "tableName": tableName, "description": null, "origin": "ide", "composedBy": null, "properties": [ { "concept": "EntityProperty", "name": "id", "uuid": "af657c05c1e545769887cfd2104257bb", "columnName": "id", "label": "主键", "description": "主键", "required": true, "primaryKey": true, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": false, "inFilter": false, "inForm": false, "inDetail": false }, "rules": [], "generationRule": "auto", "sequence": "Entity11299220825", "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "Long" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "task_id", "uuid": "1ee6f95909b34416bc091775766e9733", "columnName": "task_id", "label": "任务id", "description": null, "required": true, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "task_status", "uuid": "4b11c717968d43e7a5dccb329d444cc1", "columnName": "task_status", "label": "任务状态", "description": null, "required": true, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "task_name", "uuid": "e069c6541835457483a37df8c0cdafc0", "columnName": "task_name", "label": "任务名称", "description": null, "required": true, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "result", "uuid": "6a6a3b70e5d04831a1da89e6d72b445c", "columnName": "result", "label": "任务结果", "description": null, "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [ "maxLength(16777215)" ], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "error_msg", "uuid": "7c1c143003784277882b044aa88224d9", "columnName": "error_msg", "label": "任务异常信息", "description": null, "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [ "maxLength(16777215)" ], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "job_parameters", "uuid": "82f83a95684642568701562d9d91571c", "columnName": "job_parameters", "label": "任务参数", "description": null, "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [ "maxLength(16777215)" ], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "file_plugin_code", "uuid": "f05f15779bd84edb8f358ef8483acc23", "columnName": "file_plugin_code", "label": "文件插件唯一标识", "description": "文件插件唯一标识", "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "file_type", "uuid": "79355d76950a48609b123417e08f85bc", "columnName": "file_type", "label": "需要生成的文件类型", "description": null, "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": true, "inForm": true, "inDetail": true }, "rules": [], "generationRule": "manual", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "String" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "createdTime", "uuid": "273fa6230d8b4c068b57a76f7b08bdfa", "columnName": "created_time", "label": "创建时间", "description": "创建时间", "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": false, "inForm": false, "inDetail": false }, "rules": [], "generationRule": "auto", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "DateTime" }, "databaseTypeAnnotation": null, "defaultValue": null }, { "concept": "EntityProperty", "name": "updatedTime", "uuid": "7d2ec9616309424fbd37830b1e8f1a9d", "columnName": "updated_time", "label": "更新时间", "description": "更新时间", "required": false, "primaryKey": false, "relationNamespace": null, "relationEntity": null, "relationProperty": null, "deleteRule": null, "display": { "inTable": true, "inFilter": false, "inForm": false, "inDetail": false }, "rules": [], "generationRule": "auto", "sequence": null, "composedBy": null, "typeAnnotation": { "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": "nasl.core", "typeName": "DateTime" }, "databaseTypeAnnotation": null, "defaultValue": null } ], "indexes": [ { "concept": "EntityIndex", "name": "uni_task_id", "indexName": null, "propertyNames": [ "task_id" ], "unique": true, "description": null } ], "applyAnnotations": null }); } exports.addEntityToDefaultDS = addEntityToDefaultDS; /** * 获取全量标注文件 * @description 数据将会被 stringify */ async function getNaslAnnotatedJSONFile(app, opt) { return { name: 'nasl-annotated.json', content: JSON.stringify(await __getNaslAnnotatedJSON(app, opt)), }; } exports.getNaslAnnotatedJSONFile = getNaslAnnotatedJSONFile; async function getFrontendBundleFiles(app, opt) { let files = []; const config = { ...opt.appInfo, ...opt, appid: app.id, devDnsAddr: app.devDnsAddr, miniEnable: app.miniEnable, }; if (opt.frontends && opt.frontends.length) { await opt.logPublishFunc?.('页面', '生成页面代码:开始'); app.naslServer.logger.time('生成前端页面'); files = await (0, genBundleFiles_1.genFrontendBundleFiles)(app, opt.frontends, config); if (files && files.length === 0) { throw new Error('前端代码生成失败'); } if (opt.staticUrl) { files = (0, utils_1.replaceAssetUrl)(files, opt.appInfo.USER_STATIC_URL, opt.staticUrl); } app.naslServer.logger.timeEnd('生成前端页面'); await opt.logPublishFunc?.('页面', '生成页面代码:完成'); } return files; } exports.getFrontendBundleFiles = getFrontendBundleFiles; async function mergeBodyData(app, opt) { const authReport = (0, utils_1.getAuthReport)(app, opt.frontends); await opt.logPublishFunc?.('权限', '分析权限数据成功!'); const logicPageResourceDtoList = (0, permission_1.genPermissionData)(app); // 缓存应用权限数据 await (0, is_view_logic_1.cachePermission)(logicPageResourceDtoList); // 与老板逻辑权限数据对比 // await testWithOldPermissionResult(app, logicPageResourceDtoList); const allFrontends = (0, utils_1.getFrontendByTypes)(app?.frontendTypes); const optFrontendIds = opt.frontends.map((frontend) => frontend.id); const releaseFrontends = allFrontends.map((frontend) => ({ name: frontend.name, type: frontend.type, path: frontend.path, selected: optFrontendIds.includes(frontend.id), title: frontend.title, })); await utils.delay(100); const callbackLogicsName = app.getExtensionsCallbackLogics(); const authFlags = (0, permission_1.genLogicAuthFlag)(app); const body = { ...authReport, // 如果发布需要上报权限,导出源码不需要 logicPageResourceDtoList, processFormDefinitions: (0, utils_1.getProcessFormDefinitions)(app, opt), logicAuthFlag: authFlags, reportIdList: (0, utils_1.findAllReportIdList)(app, opt.frontends), appId: app.id, env: opt.env, branchId: opt.branchId, replicas: opt.replicas, pipelineVersion: opt.isIncremental ? '2.0' : '2.1', // 2.1 版本用于前后端并行发布的版本 appSpecification: opt.appSpecification, callbackLogicsName, frontends: releaseFrontends, callLogicValidations: {}, downloadFileTasks: {}, generatorConfig: '', files: [], }; if (logicPageResourceDtoList) { Object.assign(body, { logicPageResourceDtoList }); } return body; } async function genReleaseBody(_app, opt) { // @ts-expect-error const app = _app.__v_raw ?? _app; console.time('--backend--'); console.time('mergeBodyData'); const body = await mergeBodyData(app, opt); await utils.delay(100); console.timeEnd('mergeBodyData'); let callLogicValidations; if (!opt?.isBackendValidation) { callLogicValidations = await (0, validation_1.getCallLogicData)(app, opt.validations?.validationRules); } console.timeEnd('--backend--'); console.time('getFrontendBundleFiles'); const files = (opt.ignoreFiles || opt.isIncremental) ? [] : await getFrontendBundleFiles(app, opt); await utils.delay(100); console.timeEnd('getFrontendBundleFiles'); // 增量发布需要组合生成器上下文数据 if (opt.isIncremental) { body.generatorConfig = (0, utils_1.encodeBundleFileGeneratorConfig)({ ...opt.appInfo, ...opt, appid: app.id, devDnsAddr: app.devDnsAddr, miniEnable: app.miniEnable, }); } // nodejs 环境下的极速开发模式,在某些情况下字符会发生错误,需要转译 if (utils.isNode) { files.forEach((file) => { file.name = encodeURIComponent(file.name); }); } if (!opt?.isBackendValidation) { body.callLogicValidations = callLogicValidations; } // Add memory-aware delay to allow GC await (0, memory_optimization_1.smartDelay)(50); const exportShareContent = (0, share_content_1.genShareContent)(app); Object.assign(body, { exportShareContent: Object.keys(exportShareContent.dependOn).length ? exportShareContent : null, }); return body; } exports.genReleaseBody = genReleaseBody; // 相对 genReleaseBody 函数,genReleaseBodyForParallel 需要额外返回调用参数 app/opt,以供并行发布中的前端编译使用 async function genReleaseBodyForParallel(app, opt) { const body = await genReleaseBody(app, opt); return { releaseBody: body, app, opt }; } exports.genReleaseBodyForParallel = genReleaseBodyForParallel; /** * 替换端和业务组件的资源前缀, 提供给generator-fe调用 * 放在这里是为 * 1、版本控制 * 2、避免与replaceFrontendTypesAssets分散在两个地方 */ function replaceAssetsPrefix(frontends, prefix) { const callback = (node, key, val, prefix) => { const sysPath = prefix !== '/' ? prefix : ''; if (!sysPath) return; // 增加处理两种情况 1 css 自带图片; 2 src 属性带的图片 3 用户上传的icon name 属性 if (['staticStyle'].includes(key) && /url\((['"])?\/assets\//.test(val)) { // "background: url('/assets/login-bg-1.jpg') no-repeat; background-size: cover; height: 100vh;" node[key] = val.replace(/url\((['"])?\/assets\//, `url($1${sysPath}/assets/`); } else if (/^\/assets\/(.*?)$/.test(val)) { /** * 这里会有一些极端场景,比如:用户在文本内容属性 设置了 /assets/xxx * 这种情况下,直接替换会导致路径错误,但概率很小,先不考虑吧 * 最好就是这块逻辑也有replaceAssets的匹配逻辑 */ node[key] = `${sysPath}${val}`; } }; frontends?.forEach((item) => { item.traverseStrictChildren((node) => { const meta = (0, concepts_1.getConceptMeta)(node.concept); for (const key of meta.normalProperties) { const val = node[key]; if (typeof val === 'string') { callback(node, key, val, prefix); } } }); }); } exports.replaceAssetsPrefix = replaceAssetsPrefix; //# sourceMappingURL=body.js.map