将分析entity的处理移动至Worker中,降低主线程负载,同时修改了esbuild配置,保证打包结果的正确

This commit is contained in:
Pan Qiancheng 2024-10-21 20:55:39 +08:00
parent 2ace262e93
commit 35795e68a7
5 changed files with 527 additions and 403 deletions

View File

@ -71,14 +71,15 @@ const esbuildProblemMatcherPlugin = {
async function main() {
const ctx = await esbuild.context({
entryPoints: ["src/extension.ts"],
entryPoints: ["src/extension.ts", "src/utils/analyzeWorker.ts"],
bundle: true,
format: "cjs",
minify: production,
sourcemap: !production,
sourcesContent: false,
platform: "node",
outfile: "dist/extension.js",
outdir: "dist",
entryNames: "[dir]/[name]",
external: ["vscode"],
logLevel: "silent",
plugins: [

View File

@ -14,6 +14,7 @@ import oakPathCompletion from './plugins/oakPathCompletion';
import oakPathHighlighter from './plugins/oakPathDecoration';
import entityProviders from './plugins/entityJump';
import { activateOakLocale, deactivateOakLocale } from './plugins/oakLocale';
import { startWorker, stopWorker, waitWorkerReady } from './utils/workers';
// 初始化配置
// 查找工作区的根目录中的oak.config.json文件排除src和node_modules目录
@ -35,6 +36,14 @@ const afterPathSet = async () => {
description: string;
function: () => Promise<void>;
}[] = [
{
name: '启动worker',
description: '启动worker线程',
function: async () => {
startWorker();
await waitWorkerReady();
},
},
{
name: '解析 Entity',
description: '解析项目中的 Entity 结构',
@ -127,7 +136,7 @@ export async function activate(context: vscode.ExtensionContext) {
// 弹出提示消息,询问是否以根目录为工作区
const value = await vscode.window.showInformationMessage(
'未找到oak.config.json文件是否以当前工作区根目录为项目主目录',
'未找到oak.config.json文件是否以当前工作区根目录为项目主目录创建配置并启用Oak-Assistant插件',
'是',
'否'
);
@ -175,4 +184,5 @@ export function deactivate() {
entityProviders.dispose();
oakPathCompletion.dispose();
deactivateOakLocale();
stopWorker();
}

427
src/utils/analyzeWorker.ts Normal file
View File

@ -0,0 +1,427 @@
import { parentPort, workerData } from 'worker_threads';
import * as ts from 'typescript';
import * as fs from 'fs';
import { dirname, join } from 'path';
import { EntityDesc, LanguageValue, LocalesDef } from '../types';
import { EntityShape } from 'oak-domain/lib/types';
import { EntityDict } from './entities';
import assert from 'assert';
assert(parentPort, 'parentPort is not defined');
console.log('AnalyzeEntity Worker started...');
// 将 parseDescFile, parseSchemaFile, readLocales 等辅助函数复制到这里
function resolveImportPath(importPath: string, currentDir: string): string {
if (importPath.startsWith('.')) {
return join(currentDir, `${importPath}.ts`);
}
// 处理非相对路径的导入(如 node_modules
return importPath;
}
function parseSchemaFile(filePath: string, program: ts.Program): string[] {
const sourceFile = program.getSourceFile(filePath);
if (!sourceFile) {
// vscode.window.showWarningMessage(`无法解析文件: ${filePath}`);
return [];
}
let projectionList: string[] = [];
ts.forEachChild(sourceFile, (node) => {
if (
ts.isTypeAliasDeclaration(node) &&
node.name.text === 'Projection'
) {
if (ts.isIntersectionTypeNode(node.type)) {
// 我们只关心交叉类型的第一个成员
const firstMember = node.type.types[0];
if (ts.isTypeLiteralNode(firstMember)) {
projectionList = firstMember.members
.map((member) => {
if (ts.isPropertySignature(member) && member.name) {
return member.name
.getText(sourceFile)
.replace(/[?:]$/, '');
}
return '';
})
.filter(Boolean);
}
}
}
});
return projectionList;
}
parentPort.on('message', (message) => {
if (message.type === 'analyze') {
const { oakAppDomainPath } = message;
const result = analyzeOakAppDomain(oakAppDomainPath);
assert(parentPort, 'parentPort is not defined');
parentPort.postMessage({
type: 'result',
data: result,
});
}
});
function getEvaluateNodeForShorthandProperty(
program: ts.Program,
node: ts.ShorthandPropertyAssignment,
typeChecker: ts.TypeChecker
): any {
const symbol = typeChecker.getSymbolAtLocation(node.name);
if (!symbol) {
return undefined;
}
// 获取符号的声明
const declarations = symbol.declarations;
if (!declarations || declarations.length === 0) {
return undefined;
}
const declaration = declarations[0];
// 从当前文件的所有导入中找到对应的导入
const sourceFile = declaration.getSourceFile();
let propertyName = '';
const importDeclaration = sourceFile.statements.find((statement) => {
// 在这里找到import { actions } from "./Actions" 这样的形式
if (ts.isImportDeclaration(statement)) {
const moduleSpecifier = statement.moduleSpecifier;
if (ts.isStringLiteral(moduleSpecifier)) {
const imports = statement.importClause?.namedBindings;
// 如果导入了node.name
if (imports && ts.isNamedImports(imports)) {
// 这里需要注意如果是import { generalActions as actions } from "./Actions" 这样的形式要拿到as的内容和node.name进行比较
return imports.elements.some((element) => {
if (ts.isImportSpecifier(element)) {
if (element.propertyName) {
propertyName = element.propertyName.getText();
// 这里要确保是as actions里的actions和node.name进行比较
return element
.getText()
.endsWith(` as ${node.getText()}`);
}
// 这里是import { actions } from "./Actions" 这样的形式
propertyName = element.name.getText();
return element.name.getText() === node.getText();
}
return false;
});
}
}
}
return false;
}) as ts.ImportDeclaration | undefined;
// 这里对包内的genericActions做特殊处理
if (propertyName === 'genericActions') {
return [
'count',
'stat',
'download',
'select',
'aggregate',
'create',
'remove',
'update',
];
}
if (importDeclaration) {
// 得到导入的路径
const importPath = (
importDeclaration.moduleSpecifier as ts.StringLiteral
).text;
const currentSourceFile = node.getSourceFile();
const resolvedPath = resolveImportPath(
importPath,
dirname(currentSourceFile.fileName)
);
// 创建新的程序来解析导入的文件
const importProgram = ts.createProgram(
[resolvedPath],
program.getCompilerOptions()
);
const importSourceFile = importProgram.getSourceFile(resolvedPath);
if (importSourceFile) {
let foundDeclaration: ts.Node | undefined;
ts.forEachChild(importSourceFile, (child) => {
if (ts.isVariableStatement(child)) {
const declaration = child.declarationList.declarations[0];
if (
ts.isIdentifier(declaration.name) &&
declaration.name.text === propertyName
) {
foundDeclaration = declaration;
}
} else if (
ts.isFunctionDeclaration(child) &&
child.name &&
child.name.text === propertyName
) {
foundDeclaration = child;
} else if (
ts.isExportAssignment(child) &&
ts.isIdentifier(child.expression) &&
child.expression.text === propertyName
) {
foundDeclaration = child;
}
});
if (foundDeclaration) {
return evaluateNode(
importProgram,
foundDeclaration,
importProgram.getTypeChecker()
);
}
}
}
// 如果没有找到导入声明,则假设它是当前文件中的定义
return evaluateNode(program, declaration, typeChecker);
}
function evaluateNode(
program: ts.Program,
node: ts.Node,
typeChecker: ts.TypeChecker
): any {
if (ts.isObjectLiteralExpression(node)) {
return node.properties.reduce((obj: any, prop) => {
if (ts.isShorthandPropertyAssignment(prop)) {
// 得到标识符的名称
const name = prop.name.getText();
const evaluated = getEvaluateNodeForShorthandProperty(
program,
prop,
typeChecker
);
obj[name] = evaluated;
} else if (ts.isPropertyAssignment(prop)) {
const name = prop.name.getText();
obj[name] = evaluateNode(
program,
prop.initializer,
typeChecker
);
}
return obj;
}, {});
} else if (ts.isArrayLiteralExpression(node)) {
return node.elements.map((element) =>
evaluateNode(program, element, typeChecker)
);
} else if (ts.isStringLiteral(node)) {
return node.text;
} else if (ts.isNumericLiteral(node)) {
return Number(node.text);
} else if (node.kind === ts.SyntaxKind.TrueKeyword) {
return true;
} else if (node.kind === ts.SyntaxKind.FalseKeyword) {
return false;
} else if (ts.isIdentifier(node)) {
// 处理导入的标识符
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol && symbol.valueDeclaration) {
return evaluateNode(program, symbol.valueDeclaration, typeChecker);
}
} else if (ts.isVariableDeclaration(node) && node.initializer) {
// 处理变量声明
return evaluateNode(program, node.initializer, typeChecker);
}
// 对于其他类型的节点,可能需要进一步处理
return undefined;
}
const language = ['zh_CN', 'en_US'] as const;
function readLocales(localesDir: string): LocalesDef {
// 是否为文件夹并存在
if (!fs.existsSync(localesDir)) {
return {};
}
const locales: LocalesDef = {};
language.forEach((lang) => {
const localeFile = join(localesDir, `${lang}.json`);
if (fs.existsSync(localeFile)) {
locales[lang] = JSON.parse(
fs.readFileSync(localeFile, 'utf-8')
) as LanguageValue;
}
});
return locales;
}
function parseDescFile(
filePath: string,
program: ts.Program
): EntityDesc<EntityShape> | null {
const sourceFile = program.getSourceFile(filePath);
if (!sourceFile) {
// vscode.window.showWarningMessage(`无法解析文件: ${filePath}`);
return null;
}
const typeChecker = program.getTypeChecker();
let descObject: EntityDesc<EntityShape> | null = null;
ts.forEachChild(sourceFile, (node) => {
if (ts.isVariableStatement(node)) {
const declaration = node.declarationList.declarations[0];
if (
ts.isIdentifier(declaration.name) &&
declaration.name.text === 'desc'
) {
if (
declaration.initializer &&
ts.isObjectLiteralExpression(declaration.initializer)
) {
descObject = evaluateNode(
program,
declaration.initializer,
typeChecker
);
}
}
}
});
return descObject;
}
let isAnalyzing = false;
function analyzeOakAppDomain(path: string) {
// 将原 analyzeOakAppDomain 函数的主要逻辑移到这里
// 注意:这里不能使用 vscode API因为 Worker 中无法访问
if (isAnalyzing) {
return { error: 'Analyzing in progress' };
}
isAnalyzing = true;
console.log('Analyzing OakAppDomain:', path);
const entityDict: EntityDict = {};
const storageFile = join(path, 'Storage.ts');
if (!fs.existsSync(storageFile)) {
return { error: 'Storage.ts file does not exist' };
}
const program = ts.createProgram([storageFile], {});
const sourceFile = program.getSourceFile(storageFile);
if (!sourceFile) {
return { error: 'Unable to parse Storage.ts file' };
}
let storageSchemaNode: ts.Node | undefined;
ts.forEachChild(sourceFile, (node) => {
if (ts.isVariableStatement(node)) {
const declaration = node.declarationList.declarations[0];
if (
ts.isIdentifier(declaration.name) &&
declaration.name.text === 'storageSchema'
) {
storageSchemaNode = declaration.initializer;
}
}
});
if (
!storageSchemaNode ||
!ts.isObjectLiteralExpression(storageSchemaNode)
) {
return {
error: 'Unable to find storageSchema or the format is incorrect',
};
}
const importMap: { [key: string]: string } = {};
ts.forEachChild(sourceFile, (node) => {
if (ts.isImportDeclaration(node)) {
const moduleSpecifier = node.moduleSpecifier;
if (ts.isStringLiteral(moduleSpecifier)) {
const importPath = moduleSpecifier.text;
const importClause = node.importClause;
if (
importClause &&
importClause.namedBindings &&
ts.isNamedImports(importClause.namedBindings)
) {
importClause.namedBindings.elements.forEach((element) => {
if (
element.propertyName &&
element.propertyName.text === 'desc'
) {
importMap[element.name.text] = importPath;
}
});
}
}
}
});
storageSchemaNode.properties.forEach((prop) => {
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
const entityName = prop.name.text;
if (ts.isIdentifier(prop.initializer)) {
const descName = prop.initializer.text;
const importPath = importMap[descName];
if (importPath) {
const resolvedPath = resolveImportPath(
importPath,
dirname(storageFile)
);
const descObject = parseDescFile(resolvedPath, program);
if (descObject) {
const schemaFile = join(resolvedPath, '../Schema.ts');
const projectionList = parseSchemaFile(
schemaFile,
program
);
const locales = readLocales(
join(resolvedPath, '../locales')
);
entityDict[entityName] = {
...descObject,
projectionList,
locales,
};
}
} else {
// vscode.window.showWarningMessage(
// `未找到 ${descName} 的导入路径`
// );
return null;
}
} else {
// vscode.window.showWarningMessage(
// `${entityName} 的值不是预期的标识符`
// );
return null;
}
}
});
console.log('entityDictSize:', Object.keys(entityDict).length);
isAnalyzing = false;
return { entityDict: entityDict };
}
// send Ready message
parentPort.postMessage('ready');

View File

@ -1,14 +1,14 @@
import * as vscode from 'vscode';
import { EntityShape } from 'oak-domain/lib/types';
import path, { join, dirname } from 'path';
import path, { join } from 'path';
import fs from 'fs';
import * as ts from 'typescript';
import { debounce } from 'lodash';
import { random } from 'lodash';
import { glob } from 'glob';
import { pathConfig } from '../utils/paths';
import { toLowerFirst, toUpperFirst } from '../utils/stringUtils';
import { EntityDesc, LanguageValue, LocalesDef } from '../types';
import { EntityDesc } from '../types';
import { getWorker } from './workers';
const projectEntityList: string[] = [];
@ -98,7 +98,7 @@ export const subscribeEntity = (
};
};
const entityDict: EntityDict = new Proxy({} as EntityDict, {
const entityDictCache: EntityDict = new Proxy({} as EntityDict, {
set(target, key, value) {
target[key as string] = value;
updateDeounced();
@ -108,7 +108,7 @@ const entityDict: EntityDict = new Proxy({} as EntityDict, {
});
const genEntityNameList = (): string[] => {
return Object.keys(entityDict);
return Object.keys(entityDictCache);
};
export const entityConfig = {
@ -116,295 +116,25 @@ export const entityConfig = {
return genEntityNameList();
},
getEntityDesc(entityName: string) {
return entityDict[entityName];
return entityDictCache[entityName];
},
};
export const getProjectionList = (entityName: string) => {
const desc = entityDict[entityName];
const desc = entityDictCache[entityName];
if (desc) {
return desc.projectionList;
}
return [];
};
function resolveImportPath(importPath: string, currentDir: string): string {
if (importPath.startsWith('.')) {
return join(currentDir, `${importPath}.ts`);
}
// 处理非相对路径的导入(如 node_modules
return importPath;
}
function getEvaluateNodeForShorthandProperty(
program: ts.Program,
node: ts.ShorthandPropertyAssignment,
typeChecker: ts.TypeChecker
): any {
const symbol = typeChecker.getSymbolAtLocation(node.name);
if (!symbol) {
return undefined;
}
// 获取符号的声明
const declarations = symbol.declarations;
if (!declarations || declarations.length === 0) {
return undefined;
}
const declaration = declarations[0];
// 从当前文件的所有导入中找到对应的导入
const sourceFile = declaration.getSourceFile();
let propertyName = '';
const importDeclaration = sourceFile.statements.find((statement) => {
// 在这里找到import { actions } from "./Actions" 这样的形式
if (ts.isImportDeclaration(statement)) {
const moduleSpecifier = statement.moduleSpecifier;
if (ts.isStringLiteral(moduleSpecifier)) {
const imports = statement.importClause?.namedBindings;
// 如果导入了node.name
if (imports && ts.isNamedImports(imports)) {
// 这里需要注意如果是import { generalActions as actions } from "./Actions" 这样的形式要拿到as的内容和node.name进行比较
return imports.elements.some((element) => {
if (ts.isImportSpecifier(element)) {
if (element.propertyName) {
propertyName = element.propertyName.getText();
// 这里要确保是as actions里的actions和node.name进行比较
return element
.getText()
.endsWith(` as ${node.getText()}`);
}
// 这里是import { actions } from "./Actions" 这样的形式
propertyName = element.name.getText();
return element.name.getText() === node.getText();
}
return false;
});
}
}
}
return false;
}) as ts.ImportDeclaration | undefined;
// 这里对包内的genericActions做特殊处理
if (propertyName === 'genericActions') {
return [
'count',
'stat',
'download',
'select',
'aggregate',
'create',
'remove',
'update',
];
}
if (importDeclaration) {
// 得到导入的路径
const importPath = (
importDeclaration.moduleSpecifier as ts.StringLiteral
).text;
const currentSourceFile = node.getSourceFile();
const resolvedPath = resolveImportPath(
importPath,
dirname(currentSourceFile.fileName)
);
// 创建新的程序来解析导入的文件
const importProgram = ts.createProgram(
[resolvedPath],
program.getCompilerOptions()
);
const importSourceFile = importProgram.getSourceFile(resolvedPath);
if (importSourceFile) {
let foundDeclaration: ts.Node | undefined;
ts.forEachChild(importSourceFile, (child) => {
if (ts.isVariableStatement(child)) {
const declaration = child.declarationList.declarations[0];
if (
ts.isIdentifier(declaration.name) &&
declaration.name.text === propertyName
) {
foundDeclaration = declaration;
}
} else if (
ts.isFunctionDeclaration(child) &&
child.name &&
child.name.text === propertyName
) {
foundDeclaration = child;
} else if (
ts.isExportAssignment(child) &&
ts.isIdentifier(child.expression) &&
child.expression.text === propertyName
) {
foundDeclaration = child;
}
});
if (foundDeclaration) {
return evaluateNode(
importProgram,
foundDeclaration,
importProgram.getTypeChecker()
);
}
}
}
// 如果没有找到导入声明,则假设它是当前文件中的定义
return evaluateNode(program, declaration, typeChecker);
}
function evaluateNode(
program: ts.Program,
node: ts.Node,
typeChecker: ts.TypeChecker
): any {
if (ts.isObjectLiteralExpression(node)) {
return node.properties.reduce((obj: any, prop) => {
if (ts.isShorthandPropertyAssignment(prop)) {
// 得到标识符的名称
const name = prop.name.getText();
const evaluated = getEvaluateNodeForShorthandProperty(
program,
prop,
typeChecker
);
obj[name] = evaluated;
} else if (ts.isPropertyAssignment(prop)) {
const name = prop.name.getText();
obj[name] = evaluateNode(
program,
prop.initializer,
typeChecker
);
}
return obj;
}, {});
} else if (ts.isArrayLiteralExpression(node)) {
return node.elements.map((element) =>
evaluateNode(program, element, typeChecker)
);
} else if (ts.isStringLiteral(node)) {
return node.text;
} else if (ts.isNumericLiteral(node)) {
return Number(node.text);
} else if (node.kind === ts.SyntaxKind.TrueKeyword) {
return true;
} else if (node.kind === ts.SyntaxKind.FalseKeyword) {
return false;
} else if (ts.isIdentifier(node)) {
// 处理导入的标识符
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol && symbol.valueDeclaration) {
return evaluateNode(program, symbol.valueDeclaration, typeChecker);
}
} else if (ts.isVariableDeclaration(node) && node.initializer) {
// 处理变量声明
return evaluateNode(program, node.initializer, typeChecker);
}
// 对于其他类型的节点,可能需要进一步处理
return undefined;
}
function parseDescFile(
filePath: string,
program: ts.Program
): EntityDesc<EntityShape> | null {
const sourceFile = program.getSourceFile(filePath);
if (!sourceFile) {
vscode.window.showWarningMessage(`无法解析文件: ${filePath}`);
return null;
}
const typeChecker = program.getTypeChecker();
let descObject: EntityDesc<EntityShape> | null = null;
ts.forEachChild(sourceFile, (node) => {
if (ts.isVariableStatement(node)) {
const declaration = node.declarationList.declarations[0];
if (
ts.isIdentifier(declaration.name) &&
declaration.name.text === 'desc'
) {
if (
declaration.initializer &&
ts.isObjectLiteralExpression(declaration.initializer)
) {
descObject = evaluateNode(
program,
declaration.initializer,
typeChecker
);
}
}
}
});
return descObject;
}
const language = ['zh_CN', 'en_US'] as const;
function readLocales(localesDir: string): LocalesDef {
// 是否为文件夹并存在
if (!fs.existsSync(localesDir)) {
return {};
}
const locales: LocalesDef = {};
language.forEach((lang) => {
const localeFile = join(localesDir, `${lang}.json`);
if (fs.existsSync(localeFile)) {
locales[lang] = JSON.parse(
fs.readFileSync(localeFile, 'utf-8')
) as LanguageValue;
}
});
return locales;
}
function parseSchemaFile(filePath: string, program: ts.Program): string[] {
const sourceFile = program.getSourceFile(filePath);
if (!sourceFile) {
vscode.window.showWarningMessage(`无法解析文件: ${filePath}`);
return [];
}
let projectionList: string[] = [];
ts.forEachChild(sourceFile, (node) => {
if (
ts.isTypeAliasDeclaration(node) &&
node.name.text === 'Projection'
) {
if (ts.isIntersectionTypeNode(node.type)) {
// 我们只关心交叉类型的第一个成员
const firstMember = node.type.types[0];
if (ts.isTypeLiteralNode(firstMember)) {
projectionList = firstMember.members
.map((member) => {
if (ts.isPropertySignature(member) && member.name) {
return member.name
.getText(sourceFile)
.replace(/[?:]$/, '');
}
return '';
})
.filter(Boolean);
}
}
}
});
return projectionList;
}
/**
* oak-app-domain Entity
*/
let isAnalyzing = false;
export const analyzeOakAppDomain = async (path: string) => {
export const analyzeOakAppDomain = async (oakAppDomainPath: string) => {
const worker = getWorker();
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
@ -418,133 +148,38 @@ export const analyzeOakAppDomain = async (path: string) => {
return;
}
isAnalyzing = true;
// 开始分析先清空entityDict
Object.keys(entityDict).forEach((key) => {
delete entityDict[key];
});
const storageFile = join(path, 'Storage.ts');
// 发送消息开始分析
worker.removeAllListeners('message');
worker.removeAllListeners('error');
if (!fs.existsSync(storageFile)) {
vscode.window.showErrorMessage(
'Storage.ts文件不存在请先尝试make:domain'
);
return;
}
const program = ts.createProgram([storageFile], {});
const sourceFile = program.getSourceFile(storageFile);
if (!sourceFile) {
vscode.window.showErrorMessage('无法解析Storage.ts文件');
return;
}
let storageSchemaNode: ts.Node | undefined;
ts.forEachChild(sourceFile, (node) => {
if (ts.isVariableStatement(node)) {
const declaration =
node.declarationList.declarations[0];
if (
ts.isIdentifier(declaration.name) &&
declaration.name.text === 'storageSchema'
) {
storageSchemaNode = declaration.initializer;
}
}
});
if (
!storageSchemaNode ||
!ts.isObjectLiteralExpression(storageSchemaNode)
) {
vscode.window.showErrorMessage(
'无法找到storageSchema或格式不正确'
);
return;
}
const importMap: { [key: string]: string } = {};
ts.forEachChild(sourceFile, (node) => {
if (ts.isImportDeclaration(node)) {
const moduleSpecifier = node.moduleSpecifier;
if (ts.isStringLiteral(moduleSpecifier)) {
const importPath = moduleSpecifier.text;
const importClause = node.importClause;
if (
importClause &&
importClause.namedBindings &&
ts.isNamedImports(importClause.namedBindings)
) {
importClause.namedBindings.elements.forEach(
(element) => {
if (
element.propertyName &&
element.propertyName.text === 'desc'
) {
importMap[element.name.text] =
importPath;
}
}
);
}
}
}
});
storageSchemaNode.properties.forEach((prop) => {
if (
ts.isPropertyAssignment(prop) &&
ts.isIdentifier(prop.name)
) {
const entityName = prop.name.text;
if (ts.isIdentifier(prop.initializer)) {
const descName = prop.initializer.text;
const importPath = importMap[descName];
if (importPath) {
const resolvedPath = resolveImportPath(
importPath,
dirname(storageFile)
);
const descObject = parseDescFile(
resolvedPath,
program
);
if (descObject) {
const schemaFile = join(
resolvedPath,
'../Schema.ts'
);
const projectionList = parseSchemaFile(
schemaFile,
program
);
const locales = readLocales(
join(resolvedPath, '../locales')
);
entityDict[entityName] = {
...descObject,
projectionList,
locales,
};
}
} else {
vscode.window.showWarningMessage(
`未找到 ${descName} 的导入路径`
);
}
worker.on('message', (message) => {
if (message.type === 'result') {
const error = message.data.error;
const entityDict = message.data.entityDict;
if (error) {
vscode.window.showErrorMessage(error);
} else {
vscode.window.showWarningMessage(
`${entityName} 的值不是预期的标识符`
);
console.log('收到entityDict');
// 更新 entityDictCache
Object.keys(entityDict).forEach((key) => {
entityDictCache[key] = entityDict[key];
});
}
isAnalyzing = false;
resolve();
}
});
console.log('entityDict:', entityDict);
isAnalyzing = false;
resolve();
worker.on('error', (error) => {
vscode.window.showErrorMessage(
`分析过程中发生错误: ${error.message}`
);
isAnalyzing = false;
reject(error);
});
worker.postMessage({ type: 'analyze', oakAppDomainPath });
});
}
);

51
src/utils/workers.ts Normal file
View File

@ -0,0 +1,51 @@
import path from 'path';
import { Worker } from 'worker_threads';
import * as vscode from 'vscode';
let worker: Worker | null = null;
export const startWorker = () => {
if (!worker) {
worker = new Worker(path.join(__dirname, 'utils', 'analyzeWorker.js'));
worker.on('exit', (code) => {
console.log(`worker exit with code ${code}`);
if (code !== 0) {
vscode.window.showErrorMessage(
'Worker意外退出Code:' + code,
'正在尝试重新启动.....'
);
startWorker();
}
worker = null;
});
} else {
console.log('worker already started');
}
};
export const waitWorkerReady = async () => {
return new Promise<void>((resolve) => {
if (!worker) {
throw new Error('worker not started');
}
worker.once('message', (message) => {
if (message === 'ready') {
resolve();
}
});
});
};
export const getWorker = () => {
if (!worker) {
throw new Error('worker not started');
}
return worker;
};
/**
* worker
*/
export const stopWorker = () => {
worker?.terminate();
};