UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

327 lines 13.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getImportedNodePaths = exports.genShareContent = exports.genSharedAppGraph = exports.genSharedAppNasl = void 0; const concepts_1 = require("../../concepts"); const asserts_1 = require("@lcap/nasl-concepts/asserts"); const nasl_language_server_core_1 = require("@lcap/nasl-language-server-core"); function getNodePathsFromModule(module) { const nodePaths = []; module.logics.forEach((logic) => { nodePaths.push(logic.nodePath); }); module.dataSources.forEach((dataSource) => { dataSource.entities.forEach((entity) => { nodePaths.push(entity.nodePath); }); }); module.structures.forEach((structure) => { nodePaths.push(structure.nodePath); }); module.enums.forEach((enumType) => { nodePaths.push(enumType.nodePath); }); module.metadataTypes.forEach((metadataType) => { nodePaths.push(metadataType.nodePath); }); return nodePaths; } function getModuleGraphOptions(app) { const nodePaths = getNodePathsFromModule(app); app.dependencies.forEach((dependency) => { nodePaths.push(dependency.nodePath); }); app.connectorDependencies.forEach((connectorDependency) => { nodePaths.push(connectorDependency.nodePath); }); app.interfaceDependencies.forEach((interfaceDependency) => { nodePaths.push(interfaceDependency.nodePath); }); app.sharedAppDependencies.forEach((sharedAppDependency) => { const modPaths = getNodePathsFromModule(sharedAppDependency); modPaths.forEach((modPath) => nodePaths.push(modPath)); }); return { ignore: { App: [ 'frontendTypes', 'processV2s', 'authLogicsForCallInterface', 'authLogics', 'backend', 'connections', 'integration', 'overriddenLogics', 'roles', ], Logic: ['body', 'playground', 'variables'], Param: ['defaultValue'], Return: ['defaultValue'], DefaultValue: ['playground'], }, moduleRoots: nodePaths, }; } /** * @param node * @param options 如果options.sharedAppName存在,则转换 TypeAnnotation 的typeNamespace, 'app.' -> 'sharedApp.${options.sharedAppName}.' * @returns */ function toJSON(node, options) { const json = options?.sharedAppName ? node._toJSON((source) => { // packages\ide-essential\src\views\head\s-share-manager\s-imported-share.vue _toJSON 的逆向调整 if (source?.concept === 'TypeAnnotation' && source.typeNamespace?.startsWith('app.')) { source.typeNamespace = source.typeNamespace.replace(/^app\./, `sharedApp.${options.sharedAppName}.`); } if (['EntityProperty', 'StructureProperty'].includes(source?.concept) && source.defaultValue?.expression?.object?.namespace === 'app.enums') { source.defaultValue.expression.object.namespace = `sharedApp.${options.sharedAppName}.enums`; } if (source?.concept === 'EntityProperty' && source.relationNamespace?.startsWith('app.')) { source.relationNamespace = source.relationNamespace.replace(/^app\./, `sharedApp.${options.sharedAppName}.`); } if (source?.concept === 'Directory') { source.definitions.forEach((def) => { def.namespace = def.namespace.replace(/^app\./, `sharedApp.${options.sharedAppName}.`); }); } return source; }) : node.toJSON(); if (node.concept === 'Directory') { json.children?.forEach((child, index) => { child.nodePath = node.children[index].nodePath; }); } if (node.concept === 'DataSource') { json.directories?.forEach((dir, index) => { dir.nodePath = node.directories[index].nodePath; }); } return Object.assign(json, { nodePath: node.nodePath }); } function genSharedAppNasl(app, nodePaths = [], transformNamespace = true) { nodePaths = Array.from(new Set(nodePaths)); const toJSONOptions = transformNamespace ? { sharedAppName: app.name } : undefined; const jsonSchema = { name: app.name, // 服务端生成 SharedApp 时会替换成主应用标识 title: app.title, provider: app.name, // app 没有 description: app.desc, // app.desc;module.description ideVersion: app.ideVersion, // module 没有 concept: 'Module', type: 'sharedApp', // app 没有 logics: [], dataSources: [], structures: [], enums: [], metadataTypes: [], configuration: { concept: 'Configuration', groups: [{ name: 'dataSource', concept: 'ConfigGroup', properties: [] }], }, dependencies: [], // module 没有 interfaceDependencies: [], // module 没有 connectorDependencies: [], // module 没有 sharedAppDependencies: [], // module 没有 directories: (app.directories || []).map((dir) => toJSON(dir, toJSONOptions)), }; nodePaths.forEach((nodePath) => { const node = app.findNodeByPath(nodePath); if (!node) return; if (nodePath.startsWith('app.dependencies')) { jsonSchema.dependencies.push(toJSON(node)); return; } if (nodePath.startsWith('app.interfaceDependencies')) { jsonSchema.interfaceDependencies.push(toJSON(node)); return; } if (nodePath.startsWith('app.connectorDependencies')) { jsonSchema.connectorDependencies.push(toJSON(node)); return; } if (nodePath.startsWith('app.sharedAppDependencies')) { const sharedApp = node.module; let sharedAppJson = jsonSchema.sharedAppDependencies.find((item) => item.name === sharedApp.name); if (!sharedAppJson) { sharedAppJson = toJSON(sharedApp); Object.assign(sharedAppJson, { logics: [], dataSources: [], structures: [], enums: [], metadataTypes: [], configuration: { concept: 'Configuration', groups: [{ name: 'dataSource', concept: 'ConfigGroup', properties: [] }], }, directories: (sharedApp.directories || []).map((dir) => toJSON(dir, toJSONOptions)), }); jsonSchema.sharedAppDependencies.push(sharedAppJson); } if (node.concept === 'Structure') { sharedAppJson.structures.push(toJSON(node)); } if (node.concept === 'Enum') { sharedAppJson.enums.push(toJSON(node)); } if (node.concept === 'MetadataType') { sharedAppJson.metadataTypes.push(toJSON(node)); } if (node.concept === 'Entity') { const dataSourceName = node.parentNode.name; let dataSource = sharedAppJson.dataSources.find((item) => item.name === dataSourceName); if (!dataSource) { dataSource = toJSON(node.parentNode); dataSource.entities = []; sharedAppJson.dataSources.push(dataSource); } const entityJson = toJSON(node); dataSource.entities.push(entityJson); // 数据源配置 const dataSourceGroup = sharedApp.configuration?.getGroup('dataSource'); if (dataSourceGroup) { const properties = sharedAppJson.configuration.groups[0].properties; const property = dataSourceGroup.getProperty(node.parentNode.name); if (!properties.find((item) => item.name === property.name)) properties.push(toJSON(property)); } } return; } if (node.concept === 'Logic') { const json = toJSON(node, toJSONOptions); json.params.forEach((param) => { delete param.defaultValue; }); json.variables = []; json.returns.forEach((ret, index) => { delete ret.defaultValue; if (!ret.typeAnnotation && node.returns[index].__TypeAnnotation) ret.typeAnnotation = toJSON(node.returns[index].__TypeAnnotation, toJSONOptions); }); json.body = []; json.playground = []; delete json.applyAnnotations; jsonSchema.logics.push(json); } if (node.concept === 'Structure') { jsonSchema.structures.push(toJSON(node, toJSONOptions)); } if (node.concept === 'Enum') { jsonSchema.enums.push(toJSON(node, toJSONOptions)); } if (node.concept === 'MetadataType') { jsonSchema.metadataTypes.push(toJSON(node, toJSONOptions)); } if (node.concept === 'Entity') { const dataSourceName = node.parentNode.name; let dataSource = jsonSchema.dataSources.find((item) => item.name === dataSourceName); if (!dataSource) { dataSource = toJSON(node.parentNode, toJSONOptions); dataSource.entities = []; jsonSchema.dataSources.push(dataSource); } const entityJson = toJSON(node, toJSONOptions); delete entityJson.applyAnnotations; dataSource.entities.push(entityJson); // 数据源配置 const dataSourceGroup = app.configuration?.getGroup('dataSource'); if (dataSourceGroup) { const properties = jsonSchema.configuration.groups[0].properties; const property = dataSourceGroup.getProperty(node.parentNode.name); if (!properties.find((item) => item.name === property.name)) properties.push(toJSON(property)); } } }); return jsonSchema; } exports.genSharedAppNasl = genSharedAppNasl; /** * 生成共享应用的依赖关系图 */ function genSharedAppGraph(app) { const graph = nasl_language_server_core_1.ModuleGraph.fromNaslData(app, getModuleGraphOptions(app)).toData(); const res = {}; Object.entries(graph.modules).forEach(([nodePath, moduleData]) => { if (moduleData.dependency.length > 0) res[nodePath] = moduleData.dependency.map((dep) => dep); }); return res; } exports.genSharedAppGraph = genSharedAppGraph; function getAllDepend(nodePath, options, vis = new Set()) { if (vis.has(nodePath)) return []; vis.add(nodePath); const { graph, app } = options; const deps = graph[nodePath] || []; const result = []; deps.forEach((dep) => { if (result.find((item) => item.nodePath === dep)) return; const node = app.findNodeByPath(dep); if (!node) return; result.push({ nodePath: dep, concept: node.concept, name: node.name }); const subDeps = getAllDepend(dep, options, vis); subDeps.forEach((subDep) => { if (!result.find((item) => item.nodePath === subDep.nodePath)) result.push(subDep); }); }); return result; } function genShareContent(__data, includeAllTypes = false) { const data = __data.__v_raw ?? __data; const app = (0, asserts_1.isStrictApp)(data) ? data : new concepts_1.App({ ...data, desc: data.desc || data.description, // 入参 data 有可能是 sharedApp Module 数据 silence: true, }); const dependOn = {}; const sharedLogics = app.logics.filter((logic) => !!logic.sharedScope); const sharedEntities = []; app.dataSources.forEach((dataSource) => { dataSource.entities.forEach((entity) => { if (entity.sharedScope) sharedEntities.push(entity); }); }); const graph = genSharedAppGraph(app); [...sharedLogics, ...sharedEntities].forEach((node) => { const nodePath = node.nodePath; dependOn[nodePath] = getAllDepend(nodePath, { graph, app }); }); const nodePathSet = new Set(); Object.entries(dependOn).forEach(([nodePath, deps]) => { nodePathSet.add(nodePath); deps.forEach((dep) => nodePathSet.add(dep.nodePath)); }); if (includeAllTypes) { app.structures.forEach((structure) => { nodePathSet.add(structure.nodePath); }); app.enums.forEach((enumType) => { nodePathSet.add(enumType.nodePath); }); app.metadataTypes.forEach((metadataType) => { nodePathSet.add(metadataType.nodePath); }); } const nodePaths = Array.from(nodePathSet); const nasl = genSharedAppNasl(app, nodePaths, false); return { shareContent: nasl, dependOn, }; } exports.genShareContent = genShareContent; function getImportedNodePaths(sharedApp) { const nodePaths = getNodePathsFromModule(sharedApp); return nodePaths.map((nodePath) => nodePath.replace(`app.sharedAppDependencies[name=${sharedApp.name}].`, 'app.')); } exports.getImportedNodePaths = getImportedNodePaths; //# sourceMappingURL=share-content.js.map