@lcap/nasl
Version:
NetEase Application Specific Language
327 lines • 13.5 kB
JavaScript
;
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