@lcap/nasl
Version:
NetEase Application Specific Language
175 lines • 8.54 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.incrementalAnnotationByCache = void 0;
const nasl_concepts_1 = require("@lcap/nasl-concepts");
const nasl_utils_1 = require("@lcap/nasl-utils");
const service_1 = require("@lcap/nasl-concepts/service");
const nasl_language_server_core_1 = require("@lcap/nasl-language-server-core");
const patch_1 = require("./patch");
const types_1 = require("./types");
const utils_1 = require("./utils");
/** 增量标注 */
async function incrementalAnnotationByCache(app, server, naslCacheData, moduleGraphCache, logger = nasl_utils_1.internalLogger) {
await logger.info(utils_1.LogEventName, '开始进行增量标注');
// 这里因为没有调用 OpenApp 所以必须要手动添加
app.naslServer = server;
const moduleGraph = nasl_language_server_core_1.ModuleGraph.fromNaslData(app);
const moduleGraphCacheMap = (0, utils_1.moduleGraphCacheToMap)(moduleGraphCache);
await logger.info(utils_1.LogEventName, '生成模块图成功');
const setAnnotationNode = async (node) => {
const fullTsFile = await (0, nasl_utils_1.runGeneratorAsync)(node.toEmbeddedTSFile());
// @ts-ignore
node.sourceMap = fullTsFile.sourceMap;
server.file2NodeMap.set(fullTsFile.filePath, node);
return {
fileContent: fullTsFile.code,
file: fullTsFile.filePath,
};
};
const getNaslNodeCache = (node) => {
const { nodePath } = node;
const cacheNode = (0, nasl_concepts_1.findNodeObjectByPath)(naslCacheData, nodePath);
if (cacheNode?.concept === node.concept) {
return cacheNode;
}
};
const getModuleCache = (nodePath) => {
return moduleGraphCacheMap.get(nodePath);
};
const isSameDependency = (dep1, dep2) => {
if (dep1.length !== dep2.length) {
return false;
}
const dep1Set = new Set(dep1);
return dep2.every((key) => dep1Set.has(key));
};
const useCacheAnnotation = (mod, currentCacheNode) => {
const { name: nodePath, node: currentNode } = mod;
if (!currentNode || !currentCacheNode) {
throw new Error(`错误的节点路径:${nodePath}`);
}
// TODO: 没有必要迭代所有节点,可以想办法按照 nodePath 记录模块的子树,然后想办法在最后拼起来
(0, service_1.traverseChildrenByModule)({ ...currentCacheNode, name: nodePath }, (cacheNode, cacheNodePath) => {
// 类型子树跳过
if (cacheNode.concept === 'TypeAnnotation') {
return true;
}
// 当前缓存的类型子树
const typeAnnotationData = cacheNode.typeAnnotation ?? cacheNode.__TypeAnnotation;
if (!typeAnnotationData && !patch_1.patchNodeSet.has(cacheNodePath)) {
return;
}
const current = app.findNodeByPath(cacheNodePath);
// 当前节点不存在,或者当前节点本来就有类型时
if (!current || current.typeAnnotation) {
return;
}
if (patch_1.patchNodeSet.has(cacheNode.concept)) {
(0, patch_1.patch)(current, cacheNode, app, naslCacheData);
}
if (typeAnnotationData) {
current.typeAnnotation = typeAnnotationData;
}
});
};
// 小于 0 时需要设置为 0
const getModifyTime = (time = 0) => {
return time < 0 ? 0 : time;
};
await logger.info(utils_1.LogEventName, '增量标注开始,进度 0%...');
/** 类型缓存 */
const typesMapCache = new Map();
/** 所有模块 */
const allModules = moduleGraph.getModules();
/** 总模块节点计数 */
const totalModuleCount = allModules.reduce((ans, item) => ans + item.count, 0);
/** 当前模块节点技术 */
let currentModuleCount = 0;
/** 写入文件等待 */
let transformAwait = Promise.resolve();
const modules = await moduleGraph.topologicalSort({
async getModulesSignature(modules, getModuleStatus) {
if (modules.length === 0) {
throw types_1.IncrementalErrorCode.CircularModule;
}
/** 待标注的节点 */
const annotationModules = [];
/** 当前的 TS 文件 */
const tsFiles = [];
for (const mod of modules) {
const { node } = mod;
const { nodePath } = node;
const nodeCache = getNaslNodeCache(node);
const moduleCache = nodeCache ? getModuleCache(nodePath) : undefined;
const modDepModules = mod.getDependencyModules().map((item) => item.dependency);
// 模块需要重新标注
if (
// 无节点缓存表示是新节点
!nodeCache ||
// 无模块缓存表示是新模块
!moduleCache ||
// 有节点缓存但最后修改时间不一致
getModifyTime(moduleCache?.lastModifyTime) !== getModifyTime(mod.lastModifyTime) ||
// 有模块缓存但是依赖变更
!isSameDependency(moduleCache.dependency ?? [], modDepModules.map((item) => item.name)) ||
// 有模块缓存,依赖也没变,但是有依赖的签名改变
modDepModules.some((dep) => getModuleStatus(dep) === nasl_language_server_core_1.ModuleStatusInTopologicalSort.VisitedWithModify)) {
const data = await setAnnotationNode(node);
tsFiles.push(data);
annotationModules.push(mod);
}
// 使用缓存
else {
const tsFile = mod.node.getEmbeddedFilePath();
const tsContent = moduleCache.signature;
tsFiles.push({ file: tsFile, fileContent: tsContent });
mod.updateSignature(tsContent);
useCacheAnnotation(mod, nodeCache);
}
}
if (annotationModules.length > 0) {
// 要等待上次写入完成
await transformAwait;
await server.writeFiles(tsFiles);
const types = await server.annotationFiles(annotationModules
.map(({ node }) => node)
.filter((node) => !(0, service_1.isIgnoreFullAnnotationFileNode)(node)));
// 合并类型缓存
for (const [node, type] of types) {
// 这里在 NaslServer 中似乎是种特别的兼容处理,暂时保留
if (type && 'typeAnnotation' in type && type.typeAnnotation) {
typesMapCache.set(node, type.typeAnnotation);
}
// type 可以是 null,不可以过滤,后续要继续处理的
else {
typesMapCache.set(node, type);
}
}
// 生成标注模块的签名
annotationModules.forEach((mod) => {
mod.updateSignature(mod.node.toEmbeddedDeclarationTSFile().code);
});
}
else {
// 并行写入文件
transformAwait = transformAwait.then(() => server.writeFiles(tsFiles));
}
currentModuleCount += modules.reduce((ans, item) => ans + item.count, 0);
await logger.info(utils_1.LogEventName, `增量标注进度:${(currentModuleCount / totalModuleCount * 100).toFixed(2)}%...`);
return annotationModules;
},
});
await logger.info(utils_1.LogEventName, '增量标注完成');
await logger.info(utils_1.LogEventName, '生成标注数据开始');
const annotationJson = (0, utils_1.getFullAnnotationData)(app, server, typesMapCache);
await logger.info(utils_1.LogEventName, '生成标注数据结束');
return {
isFull: modules.length === allModules.length,
updatedModules: modules.map((item) => item.name),
moduleGraph: moduleGraph.toData(),
annotationData: annotationJson,
isSkipFrontendGenerator: !modules.some((mod) => (0, utils_1.isFrontendNode)(mod.node)),
};
}
exports.incrementalAnnotationByCache = incrementalAnnotationByCache;
//# sourceMappingURL=incremental.js.map