@lcap/nasl
Version:
NetEase Application Specific Language
1,197 lines • 53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkAStructure_ = exports.naslNodeTranslateMessage = exports.translateDiagnosticMessage = exports.outOriginalvalue = void 0;
const naslServer_1 = require("./naslServer");
const nasl_concepts_1 = require("@lcap/nasl-concepts");
const sortTsString_1 = require("../utils/sortTsString");
const asserts_1 = require("@lcap/nasl-concepts/asserts");
const mapAstString = new Map();
function transformType(tsType) {
tsType = tsType.replaceAll(' & { __name: "AStructure"; }', '').replaceAll('_AStructure', 'AStructure');
if (tsType === 'string' || tsType === 'String' || /StringLiteral<['"].*['"]>/.test(tsType))
return '字符串';
else if (tsType === 'number')
return '数字';
else if (tsType === 'Integer')
return '整数';
else if (tsType === 'Double')
return '小数';
else if (tsType === 'Decimal')
return '小数';
else if (tsType === 'Long')
return '整数';
else if (tsType === 'DateTime')
return '日期时间';
else if (tsType === 'Date')
return '日期';
else if (tsType === 'Time')
return '时间';
else if (tsType === 'boolean' || tsType === 'Boolean')
return '布尔值';
else if (tsType === 'unknown')
return '未知类型';
else if (tsType === 'Enums')
return '枚举';
else if (tsType === 'views')
return '页面';
else if (tsType === 'void')
return '无返回值';
else if (tsType === '__elements')
return '页面元素';
else if (tsType === '__unknown__')
return '无效';
else if (tsType === 'extensions')
return '拓展模块';
else if (tsType === 'Promise<void>')
return '未知类型';
else if ((tsType.startsWith('{') && tsType.endsWith('}')) || (tsType.startsWith('{') && tsType.endsWith('...'))) {
if (tsType.includes('__name: "AStructure_') || tsType.includes('__name: any')) {
return tsType.replace(/__name: "AStructure_\w{8}";/g, '').replace(/__name: any;/g, '');
}
return '当前节点';
}
else if (tsType.endsWith('[]')) {
return `List<${transformType(tsType.slice(0, -2))}>`;
}
else if (tsType.startsWith('<T extends ') && tsType.endsWith('>() => T')) {
const types = (0, naslServer_1.getDisplayString2Type)(tsType);
let tsStr = '';
types.forEach((item, index) => {
tsStr += index === 0 ? transformType(item) : ' | ' + transformType(item);
});
return tsStr;
}
else if (tsType.includes(' & ')) {
const types = tsType.split(' & ');
let tsStr = '';
types.forEach((item, index) => {
tsStr += index === 0 ? transformType(item) : ' & ' + transformType(item);
});
return tsStr;
}
else if (tsType.includes(' | ')) {
const types = tsType.split(' | ');
let tsStr = '';
types.forEach((item, index) => {
const newItem = item.replace(/[a-zA-Z_]+/g, (text) => transformType(text));
tsStr += index === 0 ? newItem : ' 或 ' + newItem;
});
return tsStr;
}
else {
return tsType;
}
}
const NAMESPACE_CONCEPT_MAP = {
entities: '实体',
structures: '数据结构',
enums: '枚举',
logics: '逻辑',
interfaces: '接口',
views: '页面',
elements: '元素',
processes: '流程',
processV2s: '流程',
roles: '角色',
extensions: '扩展模块',
apis: '接口应用',
components: '扩展组件',
properties: '配置参数',
};
function transformNamespace(tsNamespace) {
for (const key in NAMESPACE_CONCEPT_MAP) {
const value = NAMESPACE_CONCEPT_MAP[key];
if (tsNamespace.endsWith(key))
return value;
}
return tsNamespace;
}
function transformMethod(tsMethod) {
if (tsMethod === 'forEach')
return 'ForEach';
else
return tsMethod;
}
function transformIdentifier(identifier) {
if (NAMESPACE_CONCEPT_MAP[identifier])
return NAMESPACE_CONCEPT_MAP[identifier];
else
return ` ${transformType(identifier)} 上的`;
}
function outOriginalvalue(value) {
return value;
}
exports.outOriginalvalue = outOriginalvalue;
const TS_RULES_TYPE_INCONSISTENCY = [
/This condition will always return '(.+?)' since the types '(.+?)' and '(.+?)' have no overlap/,
/Property '(.+?)' is missing in type '(.+?)' but required in type '(.+?)'/,
/Argument of type '(.+?)' is not assignable to parameter of type '(.+?)'/,
/Type '(.+?)' is not assignable to type '(.+?)'/,
/Type '(.+?)' does not satisfy the constraint '(.+?)'/,
/Type '(.+?)' is missing the following properties from type '(.+?)'/,
];
const TS_RULES = [
{
re: /Property '(FrontEnd|BackEnd)(.+?)' is private and only accessible within/,
result: '找不到配置参数$2',
transforms: [transformType, transformType],
},
{
re: /Property '(.+?)' is private and only accessible within class '(.+?)'./,
result: '“$1”是私有的,只能在“$2”中访问。',
transforms: [transformType, transformType],
},
{
re: /Object literal may only specify known properties, and '(.+?)' does not exist in type/,
result: '当前参数$1,不可用。',
transforms: [transformType],
},
{
re: /Object literal may only specify known properties, but '(.+?)' does not exist in type/,
result: '当前参数$1,不可用。',
transforms: [transformType],
},
{
re: /Argument of type '(.+?)' is not assignable to parameter of type '(.+?)'/,
result: '参数类型不一致!传入类型:$1,接收类型:$2。',
transforms: [transformType, transformType],
},
{
re: /Type '(.+?)' is not assignable to type '(.+?)'/,
result: '左右参数类型不一致!左边类型:$2,右边类型:$1。',
transforms: [transformType, transformType],
},
{
re: /Type '(.+?)' does not satisfy the constraint '(.+?)'/,
result: '参数类型不一致!传入类型:$1,接收类型:$2。',
transforms: [transformType, transformType],
},
{
re: /This condition will always return '(.+?)' since the types '(.+?)' and '(.+?)' have no overlap/,
result: '左右参数类型不一致!左边类型:$2,右边类型:$3。',
transforms: [transformType, transformType, transformType],
},
{
re: /Type '(.+?)' is missing the following properties from type '(.+?)'/,
result: '类型不一致!左边类型:$2,右边类型:$1。',
transforms: [transformType, transformType],
},
{
re: /Property '(.+?)' is missing in type '(.+?)' but required in type '(.+?)'/,
result: '类型不一致!左边类型:$3,右边类型:$2。',
transforms: [outOriginalvalue, transformType, transformType],
},
{
re: /object literal cannot have multiple properties with the same name/,
result: '不能具有多个名称相同的属性。',
},
{
re: /Invalid character/,
result: '无效的字符',
},
{
// This expression is not callable.\n Type 'Entity1' has no call signatures.
re: /This expression is not callable.\s*Type '(.+?)' has no call signatures/,
result: '此表达式不可用。',
},
{
re: /Expression expected/,
result: '表达式不能为空!',
},
{
re: /Cannot find name '__(?:IDENTIFIER|LEFT|RIGHT)__'/,
result: '表达式不能为空!',
},
{
re: /Cannot find name '__(?:NOREFCONNECTION)__'/,
result: '文件存储配置不能为空!',
},
{
re: /Cannot find name '__(?:FRONTENDVARIABLES)__'/,
result: '前端全局变量:不可在非页面下使用。',
},
{
re: /Cannot find name '__(?:QueryFieldExpression)__'/,
result: '数据查询:实体属性不能为空。',
},
{
re: /Cannot find name '__(?:QueryFieldExpressionMissing)__'/,
result: '数据查询:所查询的实体不存在数据源中。',
},
{
re: /Cannot find name '__UnSupportedSqlFunction__'/,
result: '数据查询:当前数据库不支持该Sql函数。',
},
{
re: /Cannot find name '__UnSupportedSqlFunctionAtCurrentClause__'/,
result: '数据查询:当前使用范围不支持该Sql函数。',
},
{
re: /Cannot find name '__UnSupportedBuiltinFunctionInisdeCallQueryComponent__'/,
result: '数据查询:不支持内置函数。',
},
{
re: /Cannot find name '__UnSupportedSqlFunctionOutsideCallQueryComponent__'/,
result: 'SQL函数只能在数据查询中使用。',
},
{
re: /Cannot find name '__(?:WHERE_MULTIPLE_CONDITION)__'/,
result: '数据查询:筛选条件不能有多个表达式。',
},
{
re: /Cannot find name '__(?:HAVING_MULTIPLE_CONDITION)__'/,
result: '数据查询:聚合属性过滤不能有多个表达式。',
},
{
re: /Cannot find name '__(?:EMPTY_AGGREGATE_NAME)__'/,
result: '数据查询:聚合函数名称不能为空。',
},
{
re: /Cannot find name '__(?:EMPTY_AGGREGATE_ALIAS)__'/,
result: '数据查询:聚合函数别名不能为空。',
},
{
re: /Cannot find name '__(?:EMPTY_GROUP_BY_NAME)__'/,
result: '数据查询:分组属性不能为空。',
},
{
re: /Cannot find name '__UnSupportedBuiltinFunctionInisdeCallQueryComponent__'/,
result: '数据查询:不支持内置函数。',
},
{
re: /Cannot find name '__(?:EMPTY_GROUP_BY_ALIAS)__'/,
result: '分组属性别名不能为空。',
},
{
re: /Cannot find name '__(?:SQL_GRAMMAR_ERROR)__'/,
result: 'SQL查询:语句可能有异常。',
},
{
re: /Cannot find name '__(?:OQL_GRAMMAR_ERROR)__'/,
result: 'SQL查询:语句可能有异常。',
},
{
re: /Cannot find name '__(?:OQL_ALIAS_WARNING)__'/,
result: 'SQL查询:别名不符合规范。',
},
{
re: /Cannot find name '__(?:OQL_EMPTY_ERROR)__'/,
result: 'SQL查询:语句不能为空。',
},
{
re: /Cannot find name '__OQL_UnSupportedSqlFunction__'/,
result: 'SQL查询:当前数据库不支持该Sql函数。',
},
{
re: /Cannot find name '__OQL_UnSupportedSqlFunctionAtCurrentClause__'/,
result: 'SQL查询:当前使用范围不支持该Sql函数。',
},
{
re: /Cannot find name '__(?:NO_SELECT_TYPE)__'/,
result: '未选择返回数据类型',
},
{
re: /'_unsupported_syntax_lcap'/,
result: 'SQL查询:不支持的使用方式',
},
{
re: /Cannot find name '__UsersEmpty__'./,
result: '任务完成人为空',
},
{
re: /Cannot find name '__TaskTitleEmpty__'./,
result: '任务标题为空',
},
{
re: /Cannot find name '__UserAssigneesEmpty__'./,
result: '转派人员为空',
},
{
re: /Cannot find name '__RoleAssigneesEmpty__'./,
result: '转派角色为空',
},
{
re: /Cannot find name '__DepartmentAssigneesEmpty__'./,
result: '转派部门为空',
},
{
re: /Cannot find name '__specifiedRangeEmpty__'./,
result: '回退节点范围为空',
},
{
re: /Cannot find name '__destinationEmpty__'./,
result: '任务未关联页面',
},
{
re: /Cannot find name '__assignmentLineEmpty__'./,
result: '批量赋值没有连线',
},
{
re: /Cannot find name '__ValidationRule__'./,
result: '校验规则不能为空',
},
{
re: /Cannot find name '__UNCERTAIN__INTERMEDIATE__FIELDS__'./,
result: '来自不确定结构或实体的字段',
},
{
re: /Cannot find name '__UNSUPPORTED__ENTITY__FIELDS__'./,
result: '可能为实体属性别名,动态条件中仅支持使用变量',
},
{
re: /No value exists in scope for the shorthand property '__(?:IDENTIFIER|LEFT|RIGHT)__'. Either declare one or provide an initializer./,
result: '用户任务未关联页面',
},
{
re: /No value exists in scope for the shorthand property '__(?:outOfProcess)__'. Either declare one or provide an initializer./,
result: '节点未关联到流程图',
},
{
re: /'(.+?)' has no exported member(?: named)? '(.+?)'/,
result: '找不到接口$1 $2。',
transforms: [transformNamespace, transformType],
},
{
re: /Unreachable code detected\./,
result: '逻辑中有未使用的。',
},
// {
// re: /Property '__slice' does not exist on type '(.+?)'/,
// result: 'ForEach:循环列表:参数类型不匹配!所需类型:数组、集合等,提供类型:$1',
// transforms: [transformType],
// },
{
re: /Property '(.+?)' does not exist on type 'typeof (.+?)'/,
result: '找不到$2 $1。',
transforms: [transformMethod, transformIdentifier],
},
{
re: /Property '(.+?)' does not exist on type '(.+?)'/,
result: '找不到$2 $1。',
transforms: [transformMethod, transformIdentifier],
},
{
re: /Cannot find name '(.+?)'. Did you mean '(.+?)'\?/,
result: '找不到 $1。',
transforms: [outOriginalvalue, outOriginalvalue],
},
{
re: /Expected (.+?) type arguments, but got (.+?)/,
result: '预期 $1 个类型参数,但传入了 $2 个。',
transforms: [outOriginalvalue, outOriginalvalue],
},
{
re: /Expected (.+?) arguments, but got (.+?)./,
result: '预期 $1 个参数,但传入了 $2 个。',
transforms: [outOriginalvalue, outOriginalvalue],
},
{
re: /The (.+?)-hand side of an arithmetic operation must be of type (.+?). type./,
result: '表达式错误!',
transforms: [outOriginalvalue, outOriginalvalue],
},
{
re: /Operator '(.+?)' cannot be applied to types '(.+?)' and '(.+?)'./,
result: '符号:$1 参数类型不匹配!所需类型:基础类型>$2,提供类型:$3。',
transforms: [outOriginalvalue, transformType, transformType],
},
{
re: /Object is possibly 'undefined'./,
result: '所选择的内容未定义。',
},
{
re: /Cannot find name '(.+?)'./,
result: '所选择的内容 $1 未定义。',
transforms: [outOriginalvalue],
},
{
re: /Duplicate identifier '(.+?)'./,
result: '当前内容中有重复的 $1,可能会影响使用。',
transforms: [outOriginalvalue],
},
{
re: /'__LogicEmpty' is declared but its value is never read./,
result: '逻辑为空,请编辑内容',
},
{
re: /'__destinationEmpty__' is declared but its value is never read./,
result: '任务未关联页面',
},
{
re: /'__devConfigValueEmpty' is declared but its value is never read./,
result: '配置参数开发环境取值未设置',
},
{
re: /'__onlineConfigValueEmpty' is declared but its value is never read./,
result: '配置参数生产环境取值未设置',
},
{
re: /Variable '(.+?)' implicitly has an 'any' type./,
result: '$1推导不出类型!请连线或手动设置',
transforms: [transformType],
},
{
re: /'(.+?)' refers to a value, but is being used as a type here. Did you mean 'typeof (.+?)'?/,
result: '$1未初始化!请连线',
transforms: [transformType],
},
{
re: /Variable '(.+?)' is used before being assigned./,
result: '变量 $1 在使用前未被初始化',
transforms: [outOriginalvalue],
},
{
re: /Cannot assign to '(.+?)' because it is a read-only property./,
result: '无法赋值只读属性 $1',
transforms: [outOriginalvalue],
},
];
const POST_RULES = [
{
re: /__IDENTIFIER__/g,
result: 'undefined',
},
{
re: /Integer|"Integer"/g,
result: '整数',
},
{
re: /Long|"Long"/g,
result: '整数',
},
{
re: /Double|"Double"/g,
result: '小数',
},
{
re: /Decimal|"Decimal"/g,
result: '小数',
},
{
re: /String|"String"/g,
result: '字符串',
},
{
re: /Boolean|"Boolean"/g,
result: '布尔值',
},
{
re: /"READONLY\.[\w\.]+"/g,
result: '不可赋值类型',
},
{
re: /unknown/g,
result: '未知类型',
},
{
re: /never/g,
result: '未知类型',
},
// 匿名数据结构去掉冗余展示 __name: "AStructure_\w{8}"
{
re: /__name: "AStructure_\w{8}";/g,
result: '',
},
];
Object.keys(NAMESPACE_CONCEPT_MAP).forEach((key) => {
POST_RULES.push({
re: new RegExp(key, 'g'),
result: NAMESPACE_CONCEPT_MAP[key],
});
});
function translateDiagnosticMessage(message) {
// 业务组件先处理
const businessComponent = /Namespace 'app.frontendTypes.(.+?).businessComponents' has no exported member '(.+?)'./.exec(message);
if (businessComponent?.[1] && businessComponent?.[2]) {
return `找不到${businessComponent?.[1]}端下的业务组件${businessComponent?.[2]}`;
}
for (const rule of TS_RULES) {
const cap = rule.re.exec(message);
if (cap) {
return rule.result.replace(/\$(\d+)/g, (m, index) => rule.transforms[index - 1](cap[index]));
}
}
return message;
}
exports.translateDiagnosticMessage = translateDiagnosticMessage;
/**
* 节点和ts 报错结合,转成更精准的ts报错
* @param minRange
* @param tsErrorDetail 报错具体信息
* @returns
*/
function naslNodeTranslateMessage(minRange, tsErrorDetail, performance) {
const text = tsErrorDetail?.originalDiagnostic?.text;
let node = minRange?.node;
if (performance) {
if (node instanceof nasl_concepts_1.Destination && /Property '(.+?)' does not exist on type '(.+?)'/.exec(text)) {
let nodePath = node.viewNamespace + '.' + node.viewName;
function modifyViews(input = '') {
const parts = input.split('.');
let firstViews = true;
return parts
.map((part) => {
if (part === 'views') {
if (firstViews) {
firstViews = false;
return part;
}
else {
return 'children';
}
}
else {
return part;
}
})
.join('.');
}
nodePath = modifyViews(nodePath);
const viewNode = node.app?.findNodeByCompleteName?.(nodePath);
if (viewNode) {
return null;
}
else {
tsErrorDetail.message = `找不到页面 ${node.viewName}`;
}
}
}
// 有一些节点报错信息不向外暴露,缺失一些原生标签等等的展示
if (node instanceof nasl_concepts_1.View || node instanceof nasl_concepts_1.BusinessComponent || node instanceof nasl_concepts_1.ViewElement) {
if (text.startsWith(`'nasl.ui' has no exported member named `)) {
return null;
}
else if (text.startsWith(`Property '`) && text.includes(`does not exist on type 'typeof ui'.`)) {
return null;
}
else if (text.startsWith(`Namespace 'nasl.ui' has no exported member `)) {
return null;
}
else if (text.startsWith(`Function expression, which lacks return-type annotation, implicitly has an 'any[]' return type.`)) {
return null;
}
else if (/Property 'businessComponents' does not exist on type 'typeof (pc|h5)'./.exec(text)) {
return null;
}
}
// 处理bindevent参数没传递的报错
if (/Expected (.+?) arguments, but got (.+?)./.exec(text)) {
// bindevent本身现在就不传参数
if (node instanceof nasl_concepts_1.BindEvent) {
return null;
}
if (node instanceof nasl_concepts_1.ProcessElement && (node.isUserTask || node.type === 'AutoTask' || node.type === 'StartNoneEvent')
|| node instanceof nasl_concepts_1.ProcessElementV2 && node.isTask) {
const reg = /Expected (.+?) arguments, but got (.+?)./.exec(text);
let u;
if (node.concept === 'ProcessElementV2') {
const map = {
ServiceTask: '自动任务',
InitiateTask: '发起任务',
ApprovalTask: '审批任务',
SubmitTask: '执行任务',
CCTask: '抄送任务',
};
u = map[node.type];
}
else {
switch (node.type) {
case 'UserTask':
u = '用户任务';
break;
case 'AutoTask':
u = '自动任务';
break;
case 'ApprovalTask':
u = '审批任务';
break;
case 'MultiApprovalTask':
u = '多人审批任务';
break;
case 'InitiateTask':
u = '发起任务';
break;
case 'SubmitTask':
u = '执行任务';
break;
case 'CCTask':
u = '抄送任务';
break;
default:
u = '任务';
}
}
if (reg[2] === '0') {
tsErrorDetail.message = `${u}出口顺序流个数不能是0`;
}
else {
tsErrorDetail.message = `${u}出口顺序流个数不能大于1`;
}
if (node.type === 'StartNoneEvent') {
tsErrorDetail.message = `开始节点只能有一个出口顺序流`;
}
}
if (node instanceof nasl_concepts_1.ProcessElement && ['ExclusiveGateway', 'ParallelGateway', 'InclusiveGateway'].includes(node.type)
|| node instanceof nasl_concepts_1.ProcessElementV2 && node.isBranch) {
const reg = /Expected (.+?) arguments, but got (.+?)./.exec(text);
let u = '';
let map;
if (node.concept === 'ProcessElementV2') {
map = {
ExclusiveGateway: '唯一分支',
ParallelGateway: '并行分支'
};
}
else {
map = {
ExclusiveGateway: '排他网关',
ParallelGateway: '并行网关',
InclusiveGateway: '包容网关',
};
}
u = map[node.type];
if (reg[2] === '0') {
tsErrorDetail.message = `${u}出口顺序流和入口顺序流个数不能等于0`;
}
else {
tsErrorDetail.message = node.type === 'ExclusiveGateway' ? `${u}出口顺序流个数等于1,该${u}没有意义` : `${u}出口顺序流和入口顺序流个数同时等于1,该${u}没有意义`;
}
}
}
// 因为缺少参数时候有可能有特殊情况,因为原本少的多了就会找到 callLogic上,
// 但是只少一个的时候就会找到准确的Argument上 需要特殊处理, ui层就可以统一处理
if (/Expected (.+?) arguments, but got (.+?)./.exec(text) && node.getAncestor('CallLogic')) {
node = node.getAncestor('CallLogic');
}
// 赋值左右侧类型不一致, 把文字换一下
if (/Argument of type '(.+?)' is not assignable to parameter of type '(.+?)'/.exec(text)) {
if (node instanceof nasl_concepts_1.OqlQueryComponent) {
tsErrorDetail.message = tsErrorDetail.message
.replace('参数类型不一致!传入类型:', '类型不一致!传入类型:')
.replace('接收类型:', '期望类型:');
}
else if (node.parentNode instanceof nasl_concepts_1.Assignment) {
// OQL 的返回类型报错需要转换翻译,其内部 SQL 语句的参数类型报错不转换翻译
if (node instanceof nasl_concepts_1.OqlQueryComponent) {
// @ts-expect-error FIXME wudengke node已经never了,不知道是在干什么
if (node.getCurrentSource().currentSource.start.line + 1 === tsErrorDetail.originalDiagnostic.start.line) {
tsErrorDetail.message = tsErrorDetail.message
.replace('参数类型不一致!传入类型:', '赋值:类型不一致!右边类型:')
.replace('接收类型:', '左边类型:');
}
}
else {
// node = node.getAncestor('CallLogic');
tsErrorDetail.message = tsErrorDetail.message
.replace('参数类型不一致!传入类型:', '赋值:类型不一致!右边类型:')
.replace('接收类型:', '左边类型:');
}
}
else if (node.parentNode instanceof nasl_concepts_1.NewMap) {
if (text.includes(`is not assignable to parameter of type 'None'`)) {
const cap = /Argument of type '(.+?)' is not assignable to parameter of type '(.+?)'/.exec(text);
tsErrorDetail.message = tsErrorDetail.message = `参数类型不一致!传入类型:${transformType(cap[1])},接收类型:字符串 或 布尔值 或 整数 或 小数`;
}
else if (text.includes(`parameter of type 'never'`)) {
tsErrorDetail.message = '自动推导不出类型!newMap中有未知类型';
}
}
else if (node.parentNode instanceof nasl_concepts_1.NewList && text.includes(`parameter of type 'never'`)) {
tsErrorDetail.message = '自动推导不出类型!newList中有未知类型';
}
else if (node instanceof nasl_concepts_1.ProcessOutcome || node instanceof nasl_concepts_1.ProcessOutcomes) {
const cap = /Argument of type '(.+?)' is not assignable to parameter of type '(.+?)'/.exec(text);
const selectComes = cap[1].split(' | ');
const currentComes = cap[2].split(' | ');
if (node instanceof nasl_concepts_1.ProcessOutcome) {
tsErrorDetail.message = `流向出口不存在,${selectComes.map((item) => item).join(',')}出口流不属于[${currentComes.map((item) => item).join(',')}]当中的某个流`;
}
else {
tsErrorDetail.message = `流向出口不存在,${selectComes.map((item) => item).join(',')}有错误的出口流`;
}
}
else if (node.parentNode instanceof nasl_concepts_1.AssigneeV2) {
const cap = /Argument of type '(.+?)' is not assignable to parameter of type '(.+?)'/.exec(text);
tsErrorDetail.message = `审批人传入类型错误,传入类型:${transformType(cap[1])},接收类型:${transformType(cap[2])}`;
}
}
if (/Property '__slice' does not exist on type '(.+?)'/.exec(text)) {
const cap = /Property '__slice' does not exist on type '(.+?)'/.exec(text);
if (cap) {
if (node instanceof nasl_concepts_1.ForEachStatement) {
tsErrorDetail.message = `ForEach:循环列表:参数类型不匹配!所需类型:数组、集合等,提供类型:$1`.replace(/\$(\d+)/g, (m, index) => transformType(cap[index]));
}
else if (node instanceof nasl_concepts_1.Paginate) {
tsErrorDetail.message = `分页:分页对象类型不匹配!所需类型:数组、集合等,提供类型:$1`.replace(/\$(\d+)/g, (m, index) => transformType(cap[index]));
}
}
}
if (node instanceof nasl_concepts_1.Argument || node instanceof nasl_concepts_1.Anchor) {
// if (/Type '(.+?)' is not assignable to type '(.+?)'./.exec(text)) {
// }
// Argument在callInterface上的报错放到内部
if (node.expression) {
node = node.expression;
}
}
if (node instanceof nasl_concepts_1.AnonymousFunction) {
if (node.body)
node = node.body;
}
else if (node instanceof nasl_concepts_1.Function) {
if (node.returnExpression)
node = node.returnExpression;
}
// 处理一些复制过来的内容 Identifier或者MemberExpression内容缺失,错误要像上冒
if (node instanceof nasl_concepts_1.Identifier || node instanceof nasl_concepts_1.MemberExpression) {
if (node.parentNode instanceof nasl_concepts_1.MemberExpression) {
let parentNode = node;
while (parentNode && parentNode.parentNode instanceof nasl_concepts_1.MemberExpression) {
parentNode = parentNode.parentNode;
}
node = parentNode || node;
let str = tsErrorDetail.message;
str = node.constructor.nodeTitle + ':' + str;
tsErrorDetail.message = str;
}
}
// 类型报错的,需要放到上一级
if (/'(.+?)' has no exported member(?: named)? '(.+?)'/.exec(text) || /Property '(.+?)' does not exist on type '(.+?)'./.exec(text)) {
if (node instanceof nasl_concepts_1.TypeAnnotation) {
const { preferenceMap } = node.app;
// 元数据需要单独判断
if (String(preferenceMap.metadataTypeEnable) === 'false' &&
node.typeNamespace === 'app.metadataTypes' &&
node.typeKind === 'reference') {
tsErrorDetail.message = '未启用元数据功能,请在“偏好设置”中启用元数据。';
}
// 变量 type 的报错放到 type 本身上
else {
tsErrorDetail.message = node.parentNode.constructor.nodeTitle + ':' + tsErrorDetail.message;
}
}
}
if (text === "Cannot find namespace 'sharedApp'." || /Namespace 'sharedApp\.[^']+' has no exported member/.test(text)) {
if (node instanceof nasl_concepts_1.TypeAnnotation) {
const { typeNamespace, typeName } = node;
const segs = typeNamespace?.split('.') || [];
if (segs[0] === 'sharedApp') {
const typeMap = {
'entities': '实体',
'structures': '数据结构',
'enums': '枚举',
'metadataTypes': '元数据',
};
const type = typeMap[segs.pop()];
tsErrorDetail.message = `找不到共享数据 ${segs[1]} ${type} ${typeName}`;
}
}
}
// 实体只有只读权限 "Property 'delete' does not exist on type '{ get(id: Long): EntityShareReadOnly; }'
if (text === "Cannot find name 'sharedApp'." ||
/Property '[^']+' does not exist on type '[^']+'\./.test(text)) {
if (node instanceof nasl_concepts_1.CallLogic) {
const { calleeNamespace, calleeName } = node;
const segs = calleeNamespace?.split('.') || [];
if (segs[0] === 'sharedApp') {
// 实体逻辑
// calleeNamespace: "sharedApp.appshare.dataSources.defaultDS.entities.EntityShareSimple.logics"
// calleeName: "delete"
const match = /\.entities\.(.+?)\.logics$/.exec(calleeNamespace);
const entityName = match && match[1];
tsErrorDetail.message = entityName ?
`找不到共享数据 ${segs[1]} 实体 ${entityName} 逻辑 ${calleeName}` :
`找不到共享数据 ${segs[1]} 逻辑 ${calleeName}`;
}
}
if (node instanceof nasl_concepts_1.QueryFieldExpression) {
const entityCompleteName = node.entityCompleteName;
const segs = entityCompleteName?.split('.') || [];
const entityAsName = node.entityAsName;
if (segs[0] === 'sharedApp') {
tsErrorDetail.message = `找不到共享数据 ${segs[1]} 实体 ${entityAsName}`;
}
}
}
// 共享逻辑不用报错,共享逻辑的报错信息在逻辑签名(入参和出参)上
if (node instanceof nasl_concepts_1.Logic && node.module?.isSharedApp) {
return null;
}
if (node instanceof nasl_concepts_1.OqlQueryComponent && text === "Type instantiation is excessively deep and possibly infinite.") {
return null;
}
/**
* 所有问题的报错处理具体信息
* 转成一个最合理的文案
*/
if (/^Cannot find name '__(?:IDENTIFIER|LEFT|RIGHT)__'\.$/.exec(text)) {
if (node instanceof nasl_concepts_1.IfStatement || node instanceof nasl_concepts_1.SwitchCase || node instanceof nasl_concepts_1.WhileStatement) {
tsErrorDetail.message = node.constructor.nodeTitle + ':参数不能为空!所需类型:基础类型>布尔值';
}
else if (node instanceof nasl_concepts_1.ForEachStatement) {
tsErrorDetail.message = 'ForEach:结束值:不能为空!所需类型:基础类型>整数';
}
else if (node instanceof nasl_concepts_1.UnaryExpression) {
tsErrorDetail.message = '!:参数不能为空!';
}
else if (node instanceof nasl_concepts_1.Assignment) {
tsErrorDetail.message = '赋值:参数不能为空!';
}
else if (node instanceof nasl_concepts_1.BatchAssignment) {
tsErrorDetail.message = '批量赋值:参数不能为空';
}
else if ((node instanceof nasl_concepts_1.Argument && node.parentNode instanceof nasl_concepts_1.CallInterface) || node instanceof nasl_concepts_1.CallInterface) {
tsErrorDetail.message = '调用接口:参数不能为空!';
}
else if ((node instanceof nasl_concepts_1.Argument && node.parentNode instanceof nasl_concepts_1.CallFunction) || node instanceof nasl_concepts_1.CallFunction) {
tsErrorDetail.message = '调用函数:参数不能为空!';
}
else if ((node instanceof nasl_concepts_1.Argument && node.parentNode instanceof nasl_concepts_1.CallLogic) || node instanceof nasl_concepts_1.CallLogic) {
tsErrorDetail.message = '调用逻辑:参数不能为空!';
}
else if (node instanceof nasl_concepts_1.ProcessOutcome || node instanceof nasl_concepts_1.Function || node instanceof nasl_concepts_1.MatchCase) {
tsErrorDetail.message = node.constructor.nodeTitle + ':不能为空!';
}
else if (node instanceof nasl_concepts_1.NewMap) {
tsErrorDetail.message = 'Map推导不出类型!请手动设置!';
}
else if (node instanceof nasl_concepts_1.NewList) {
tsErrorDetail.message = 'List推导不出类型!请手动设置!';
}
else if (node instanceof nasl_concepts_1.Argument) {
let str = tsErrorDetail.message;
str = node.parentNode.constructor.nodeTitle + ':' + str;
tsErrorDetail.message = str;
}
else if (node instanceof nasl_concepts_1.TypeAnnotation) {
// 如果是TypeAnnotation 嵌套TypeAnnotation,就往上冒,多是那种T嵌套的
let str = tsErrorDetail.message;
// TypeAnnotation要冒泡到最上面
while (node.parentNode && node.parentNode instanceof nasl_concepts_1.TypeAnnotation) {
node = node.parentNode;
}
str = node.parentNode.constructor.nodeTitle + ':' + str;
tsErrorDetail.message = str;
}
else if (node instanceof nasl_concepts_1.Identifier) {
// 根据父级内容推断当前缺少啥
const identifierToString = (node) => {
let str = tsErrorDetail.message;
if (node.parentNode instanceof nasl_concepts_1.Assignment) {
str = '赋值:参数不能为空!';
}
else if (node.parentNode instanceof nasl_concepts_1.Argument && node.parentNode.parentNode instanceof nasl_concepts_1.CallLogic) {
str = '调用逻辑:参数不能为空!';
}
else if (node.parentNode instanceof nasl_concepts_1.ValidationRule) {
str = '验证逻辑:验证对象不能为空!';
}
else {
str = node.parentNode.constructor.nodeTitle + ':' + str;
tsErrorDetail.message = str;
}
return str;
};
tsErrorDetail.message = identifierToString(node);
}
}
if (/'__UpdateNoProperty__' is declared but its value is never read./.exec(text)) {
tsErrorDetail.message = '局部更新:未选择任何属性';
const callLogic = node?.parentNode?.parentNode?.parentNode;
const bodyArgument = callLogic?.arguments?.find((item) => item.keyword === 'body');
node = bodyArgument?.expression;
}
// 左右类型不一致的,把上级信息带上
if (/^Type '(.+?)' is not assignable to type '(.+?)'\./.exec(text) ||
/^This condition will always return '(.+?)' since the types '(.+?)' and '(.+?)' have no overlap./.exec(text)) {
if (node instanceof nasl_concepts_1.OqlQueryComponent) {
// SQL语句:查询字段重复:id
let cap = /^Type '(.+?)' is not assignable to type 'true'\./.exec(text);
if (cap) {
const errorMsg = 'SQL查询:查询字段重复:$1'.replace(/\$(\d+)/g, (m, index) => transformType(cap[index]));
tsErrorDetail.message = errorMsg;
}
else {
cap = /^Type '(.+?)' is not assignable to type '(.+?)'\./.exec(text);
if (cap) {
const errorMsg = 'SQL查询:返回类型不一致:选择类型:$2,返回类型:$1'.replace(/\$(\d+)/g, (m, index) => transformType(cap[index]));
tsErrorDetail.message = errorMsg;
}
}
}
else {
let str = tsErrorDetail.message;
str = node.parentNode.constructor.nodeTitle + ':' + str;
tsErrorDetail.message = str;
if (node.parentNode instanceof nasl_concepts_1.AnonymousFunction) {
// 匿名函数:左右参数类型不一致!左边类型:布尔值,右边类型:整数。
tsErrorDetail.message = tsErrorDetail.message.replace('左右参数', '返回值').replace('左边类型', '接收类型').replace('右边类型', '传入类型');
}
else if (text === `Type 'void' is not assignable to type 'never'.`) {
const callLogic = node.getAncestor('CallLogic');
const arg = node.getAncestor('Argument');
if (callLogic?.isSpecificProcessLogic && arg?.keyword === 'data') {
tsErrorDetail.message = `${node.name}不能为null`;
}
else {
tsErrorDetail.message = `${node.name}推导不出类型!请连线或手动设置`;
}
}
}
}
if (/Property '(.+?)' is missing in type '(.+?)' but required in type '(.+?)'/.exec(text)) {
if (node.parentNode instanceof nasl_concepts_1.NewComposite) {
tsErrorDetail.message = tsErrorDetail.message
.replace('类型不一致', '接收与传入类型不一致')
.replace('左边类型', '左边接收类型')
.replace('右边类型', '右边传入类型');
tsErrorDetail.message = node.name + tsErrorDetail.message;
}
}
// 参数类型不一致!
if (/^Type '(.+?)' does not satisfy the constraint '(.+?)'\./.exec(text)) {
// match
if ((node instanceof nasl_concepts_1.TypeAnnotation && node.parentNode instanceof nasl_concepts_1.MatchCase) || node instanceof nasl_concepts_1.MatchCase) {
return null;
// ide进行计算
// const reg = /^Type '(.+?)' does not satisfy the constraint '(.+?)'\./.exec(text);
// if (reg[1] && reg[2]) {
// tsErrorDetail.message = '匹配:类型不一致! 传入类型:' + transformType(reg[1]) + ',接收类型:' + transformType(reg[2]);
// if (reg[2] === 'never') {
// tsErrorDetail.message = '匹配:类型不一致! 传入类型:' + transformType(reg[1]) + ',接收类型:无可以接收的类型';
// }
// }
// tsErrorDetail.titleTip = '该类型无法满足条件';
}
}
// 左右类型不一致的,把上级信息带上
if (/^A type literal property cannot have an initializer./.exec(text)) {
if (node instanceof nasl_concepts_1.Param)
return null;
}
if (/'__LogicEmpty' is declared but its value is never read./.exec(text)) {
if (node instanceof nasl_concepts_1.Logic) {
node.isSmpty = true;
}
}
// FIXME 自定义组件库使用了slotXX(current: 自定义类型)。但是有些时候这里不会翻译出__item。因此先暂时写规则忽略。
// 缺陷:vue3日历拖入后有报错 http://projectmanage.netease-official.lcap.163yun.com/dashboard/BugDetail?id=3027550191498752
if (text?.includes("Cannot find name '__item'.")) {
return null;
}
if (/Variable '(.+?)' implicitly has an 'any' type./.exec(text) || /Variable '(.+?)' implicitly has an 'any\[\]' type./.exec(text)) {
if (node.parentNode instanceof nasl_concepts_1.NewComposite) {
//
}
else if (node.parentNode instanceof nasl_concepts_1.NewList) {
tsErrorDetail.message = tsErrorDetail.message.replace('!请连线或手动设置', '');
}
else if (node.parentNode instanceof nasl_concepts_1.NewMap) {
tsErrorDetail.message = tsErrorDetail.message.replace('!请连线或手动设置', '');
}
else {
return;
}
}
if (checkAStructure_(text)) {
return null;
}
for (const rule of POST_RULES) {
if (rule.re.test(tsErrorDetail.message)) {
tsErrorDetail.message = tsErrorDetail.message.replace(rule.re, (value, index, oldStr) => {
// 处理匹配到的值的左右的内容,是不是还是字母,要是字母就原样输出,防止展示问题
try {
const leftCode = index - 1 < 0 ? '' : oldStr[index - 1];
const rightCode = oldStr[index + value.length] || '';
if (/^[A-Za-z]+$/.test(leftCode) || /^[A-Za-z]+$/.test(rightCode)) {
return value;
}
else {
return rule.result;
}
}
catch (err) {
return value;
}
});
}
}
if (node instanceof nasl_concepts_1.BindAttribute && node.parentNode instanceof nasl_concepts_1.ViewElement) {
const reg = /左边类型:\s*(.*)[,,]\s*右边类型:\s*(.*)[.。]/;
const left = reg.exec(tsErrorDetail.message)?.[1];
const right = reg.exec(tsErrorDetail.message)?.[2];
if (left && right) {
tsErrorDetail.message = `页面组件:属性类型不一致!接收类型:${left},传入类型:${right}。`;
}
}
if (node instanceof nasl_concepts_1.MemberExpression && node.isViewElementProperty) {
// setProp的报错信息
const isAssignment = node.upperNode?.concept === 'Assignment' && node.upperNode?.left === node;
const isBatchAssignment = node.upperNode?.concept === 'SelectMembers' && node.upperNode?.upperNode?.concept === 'BatchAssignment' && node.upperNode?.upperNode?.left === node.upperNode;
if (isAssignment || isBatchAssignment) {
// 找不到 UTableViewOptions<未知类型, 未知类型, 布尔值, 布尔值> 上的 page。
const reg = /找不到\s*(.*)\s*上的\s*(.*)[.。]/;
const prop = reg.exec(tsErrorDetail.message)?.[2];
tsErrorDetail.message = `组件属性赋值:属性名${prop}不存在!`;
if (/Options$/.test(prop)) {
tsErrorDetail.message = `组件属性赋值:找不到组件${prop.replace('Options', '')}`;
}
}
else {
// getState的报错信息
}
}
if (node instanceof nasl_concepts_1.Assignment || node instanceof nasl_concepts_1.BatchAssignment) {
if (tsErrorDetail.message.indexOf('__SET_PROP_RISK__') !== -1) {
tsErrorDetail.message = '组件属性赋值:属性已开启动态绑定,不支持赋值操作';
}
}
if (node instanceof nasl_concepts_1.Identifier) {
if (tsErrorDetail.message.indexOf('__INVALID_ELEMENT_IDENTIFIER__') !== -1) {
tsErrorDetail.message = '暂不支持组件当作变量使用';
}
}
if (node instanceof nasl_concepts_1.Dependency) {
const connector = node.getAncestor('Connector');
tsErrorDetail.message = `连接器 ${connector.title} 需要依赖 版本至少为${node.version} 的 ${node.refName}`;
}
if ((0, asserts_1.isMicroserviceInterface)(node) || (0, asserts_1.isCallMicroserviceInterface)(node)) {
const reg = /Property '(.+?)' does not exist on type 'typeof connections'./.exec(text);
// 兼容当最后一个连接被删掉之后,报错信息不准确的问题
const reg2 = /Property 'connections' does not exist on type 'typeof app'./.exec(text);
if (reg) {
tsErrorDetail.message = `找不到 微服务连接器 上的 ${reg[1]}。`;
}
else if (reg2) {
tsErrorDetail.message = `找不到 相关微服务连接器。`;
}
}
// 特殊处理errorType的写入报错
if (tsErrorDetail.message && tsErrorDetail.message.includes('不可赋值类型 & 字符串')) {
tsErrorDetail.message = tsErrorDetail.message.replaceAll('不可赋值类型 & 字符串', '不可赋值类型');
}
if (node && tsErrorDetail) {
// node.tsErrorDetail = tsErrorDetail;
}
// 如果是来自于 编辑态的自定义连接器 的节点,报错信息需要特殊处理
const isFromConnector = node?.getAncestor('Connector');
const isFromIntegration = node?.getAncestor('Integration');
if (isFromConnector && isFromIntegration) {
return getConnectorErrorDetail(node, tsErrorDetail);
}
const isListSortNode = node?.getAncestor('CallFunction');
if (isListSortNode instanceof nasl_concepts_1.CallFunction && isListSortNode?.calleeName === 'ListSort') {
if (tsErrorDetail.message?.includes('by推导不出类型!')) {
tsErrorDetail.message = 'by 推导不出类型!请修改或设置内容';
}
if (tsErrorDetail.message?.includes('参数类型不一致!传入类型:')) {
const reg = /by:\s*([^;]+)/g;
const byTypes = tsErrorDetail.message.match(reg);
if (byTypes && byTypes?.length >= 2) {
const [receivedType, expectedType] = byTypes.map(type => type.split(':')[1].trim());
tsErrorDetail.message = `参数类型不一致!传入类型:${receivedType},接收类型:${expectedType}`;
}
}
}
return {
node,
...tsErrorDetail,
};
}
exports.naslNodeTranslateMessage = naslNodeTranslateMessage;
/**
* 获取自定义连接器的报错信息
* @param node
* @param tsErrorDetail
*/
function getConnectorErrorDetail(node, tsErrorDetail) {
// 如果message 为纯英文,直接返回
if (/^[A-Za-z\s]+[.,!?;:]$/.test(tsErrorDetail.message)) {
return {
node,
...tsErrorDetail,
};
}
const connector = node.getAncestor('Connector');
let targetNode = node;
let msgPrefix = '';
const authLogic = node.getAncestor('AuthLogic');
const authLogicForCallInterface = node.getAncestor('AuthLogicForCallInterface');
const connectorLogic = node.getAncestor('ConnectorLogic');
if (authLogicForCallInterface) {
targetNode = authLogicForCallInterface;
msgPrefix = `${connector.title} 连接器 ${targetNode.name} 操作鉴权方式:`;
// 连接器中的鉴权方法中,不允许调用 已经鉴权的接口
if (nasl_concepts_1.asserts.isCallAuthInterface(node)) {
tsErrorDetail.message = `不支持鉴权接口调用,但调用接口 ${node.calleeName} 为鉴权接口调用`;
}
}
else if (authLogic) {
targetNode = authLogic;
msgPrefix = `${connector.title} 连接器 ${targetNode?.name} 触发鉴权方式:`;
// 连接器中的鉴权方法中,不允许调用 已经鉴权的接口
if (nasl_concepts_1.asserts.isCallAuthInterface(node)) {
tsErrorDetail.message = `不支持鉴权接口调用,但调用接口 ${node.calleeName} 为鉴权接口调用`;
}
}
else if (connectorLogic) {
targetNode = connectorLogic;
const namespace = node.getAncestor('Namespace');
msgPrefix = `连接器(${connector.title})分组(${namespace.title}) 操作(${targetNode?.title}) 中:`;
}
else if (nasl_concepts_1.asserts.isConnectorLogic(node)) {
targetNode = node;
const namespace = node.getAncestor('Namespace');
msgPrefix = `连接器(${connector.title})分组(${namespace.title}) 操作(${targetNode?.title}) 中:`;
}
else if (targetNode.name) {
// 本身就是 AuthLogic、AuthLogicForCallInterface
msgPrefix = `${connector.title} 连接器 ${targetNode.name} 操作中:`;
}
else {
msgPrefix = `连接器(${connector.title})中:`;
}
tsErrorDetail.message = msgPrefix + tsErrorDetail.message;
return {
node,
...tsErrorDetail,
};
}
function checkAStructure_(errorText) {
const index = TS_RULES_TYPE_INCONSISTENCY.findIndex((item) => item.exec(errorText));
if (index !== -1) {
const rule = TS_RULES_TYPE_INCONSISTENCY[index];
const cap = rule.exec(errorText);
if (rule === TS_RULES_TYPE_INCONSISTENCY[0] || rule === TS_RULES_TYPE_INCONSISTENCY[1]) {
cap.splice(1, 1);
}
if (cap[1].includes('__name: "AStructure_') &&
cap[2].includes('__name: "AStructure_')) {
const x = (0, sortTsString_1.sortTsString)(transformType(cap[1]));
const y = (0, sortTsString_1.sortTsString)(transformType(cap[2]));
if (x === null || y === null) {
return;
}
if (x === y) {
return true;
}
else if (mapAstString.get(x) === y || mapAstString.get(y) === x) {
return true;
}
else {
const regex = /Type '"AStructure_(.*)' is not assignable to type '"AStructure_(.*)'/;
const nameError = regex.exec(errorText);
const length1 = x.match(/:/g) ? x.match(/:/g).length : -1;
const length2 = y.match(/:/g) ? y.match(/:/g).length : -2;
if (nameError && length1 === length2) {
mapAstString.set(x, y);
mapAstString.set(y, x);
return true;
}
}
}
}
return false;
}
exports.checkAStructure_ = checkAStructure_;
//# sourceMappingURL=translator.js.map