@lcap/nasl 3.6.2-beta.2 → 3.6.2-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lcap/nasl",
3
3
  "description": "NetEase Application Specific Language",
4
- "version": "3.6.2-beta.2",
4
+ "version": "3.6.2-beta.3",
5
5
  "author": "Forrest <rainforest92@126.com>",
6
6
  "scripts": {
7
7
  "clear": "rimraf ./out",
@@ -395,17 +395,17 @@ export class BaseNode extends EventEmitter {
395
395
  // eventStop为true后,数据不再存入eventList,就不再会将冒泡数据发送给后端
396
396
  eventStop: true,
397
397
  };
398
- this.parentNode?.emit('update', event);
398
+ this.parentNode?.emit?.('update', event);
399
399
  }
400
400
  }
401
401
 
402
402
  nodeEditing($event: EventPayload) {
403
- this.parentNode?.emit('node:Editing', $event);
403
+ this.parentNode?.emit?.('node:Editing', $event);
404
404
  }
405
405
 
406
406
  createNode({ parentNode, parentKey, index }: { parentNode: types.SyntaxNode; parentKey: string; index: number }) {
407
407
  if(!actionable) {
408
- eventBus.emit('NotActionable')
408
+ eventBus.emit?.('NotActionable')
409
409
  return;
410
410
  }
411
411
 
@@ -4043,6 +4043,8 @@ export class App extends BaseNode {
4043
4043
 
4044
4044
  /* 判断接口是否有误,需要重新导出 */
4045
4045
  getQualifiedInterface(interfaces: AbstractInterface[] = this.interfaces): MessageData[] {
4046
+ // getConceptConstructor
4047
+ const TypeAnnotationClass = getConceptConstructor('TypeAnnotation');
4046
4048
  const errorList: MessageData[] = [];
4047
4049
  (interfaces as unknown as Interface[]).forEach((item: Interface) => {
4048
4050
  const logic = this.logics.find((logic: Logic) => logic.name === item.originLogicName);
@@ -4056,7 +4058,7 @@ export class App extends BaseNode {
4056
4058
  logicParamMap[param.name] = param.typeAnnotation;
4057
4059
  });
4058
4060
  item.params.forEach((param) => {
4059
- const logicTypeAnnotation = logicParamMap[param.name]?.toJSON();
4061
+ const logicTypeAnnotation = TypeAnnotationClass.from(logicParamMap[param.name]?.toJSON());
4060
4062
  delete logicParamMap[param.name];
4061
4063
  if (!logicTypeAnnotation) {
4062
4064
  return errorList.push({
@@ -4067,14 +4069,14 @@ export class App extends BaseNode {
4067
4069
  message: `参数“${param.name}”已被删除,请确定请求类型无误后点击“重新导出”`,
4068
4070
  });
4069
4071
  }
4070
- const interfaceTypeAnnotation = param.typeAnnotation.toJSON() as TypeAnnotation;
4072
+ const interfaceTypeAnnotation = TypeAnnotationClass.from(param.typeAnnotation.toJSON());
4071
4073
  let isSame = false;
4072
4074
  if (logicTypeAnnotation?.typeNamespace === 'app.enums') {
4073
4075
  if (interfaceTypeAnnotation.typeNamespace === 'nasl.core' && interfaceTypeAnnotation.typeName === 'String') {
4074
4076
  isSame = true;
4075
4077
  }
4076
4078
  }
4077
- if (JSON.stringify(logicTypeAnnotation) === JSON.stringify(interfaceTypeAnnotation)) {
4079
+ if (logicTypeAnnotation.isSame(interfaceTypeAnnotation)) {
4078
4080
  isSame = true;
4079
4081
  }
4080
4082
  if (!isSame) {
@@ -4144,8 +4146,7 @@ export class App extends BaseNode {
4144
4146
  });
4145
4147
  }
4146
4148
  } else if (
4147
- JSON.stringify(logicReturns[0]?.typeAnnotation?.toJSON()) !==
4148
- JSON.stringify(interfaceReturns[0]?.typeAnnotation?.toJSON())
4149
+ !logicReturns[0]?.typeAnnotation.isSame(interfaceReturns[0]?.typeAnnotation)
4149
4150
  ) {
4150
4151
  errorList.push({
4151
4152
  logicName: logic.name,
@@ -985,8 +985,8 @@ export class BindEvent extends BaseNode {
985
985
  }
986
986
 
987
987
  const cap = suffixRE.exec(event?.title);
988
- if (cap) return `${event.title.replace(suffixRE, '')}${title ? `“${title}”` : ''}${parent.name}${cap[0]}`;
989
- else return `${event.title}${title ? `“${title}”` : ''}${parent.name}`;
988
+ if (cap) return `${event?.title?.replace(suffixRE, '')}${title ? `“${title}”` : ''}${parent.name}${cap[0]}`;
989
+ else return `${event?.title || ''}${title ? `“${title}”` : ''}${parent.name}`;
990
990
  }
991
991
  return `${parent.name}-${this.name}`;
992
992
  }
@@ -1180,9 +1180,19 @@ export class TypeAnnotation extends BaseNode {
1180
1180
  /* 判断2个类型是否一致 */
1181
1181
  isSame(typeAnnotation: TypeAnnotation) {
1182
1182
  typeAnnotation.typeArguments;
1183
+ // 由于 序列化 出来的 TypeAnnotation 会有很多多余的属性
1184
+ // 因此增加白名单,只有这些值才会被比较,其他均会被忽略
1185
+ const whiteList = [
1186
+ 'concept', 'typeKind', 'typeNamespace', 'typeName', 'typeArguments',
1187
+ 'returnType', 'inferred', 'ruleMap', 'properties', 'name', 'label',
1188
+ 'description', 'typeAnnotation', 'required', 'defaultValue', 'jsonName'
1189
+ ]
1183
1190
  const typeAnnotation1 = this.toJSON();
1184
1191
  const typeAnnotation2 = typeAnnotation.toJSON();
1185
1192
  const ignoreNull = (key: any, value: any) => {
1193
+ if (!whiteList.includes(key)) {
1194
+ return undefined; // 忽略此属性
1195
+ }
1186
1196
  if (value === null || value === undefined) {
1187
1197
  return undefined; // 忽略此属性
1188
1198
  }
@@ -625,8 +625,8 @@ export function genBundleFiles(app: App, frontend: Frontend, config: Config) {
625
625
  `;
626
626
  content += str;
627
627
  }
628
- const getBundleFileName =()=>{
629
- if (config.isPreviewFe && config.previewVersion){
628
+ const getBundleFileName = ()=> {
629
+ if (config.isPreviewFe && config.previewVersion) {
630
630
  return `mockBundle-${config.previewVersion}`
631
631
  }
632
632
  return 'bundle'
@@ -50,8 +50,7 @@ async function getFrontendBundleFiles(app: App, opt: InternalReleaseData) {
50
50
  await opt.logPublishFunc?.('代码', '生成页面代码:开始');
51
51
  files = await genFrontendBundleFiles(app, opt.frontends, {
52
52
  ...opt.appInfo,
53
- env: opt.env,
54
- debug: opt.debug,
53
+ ...opt,
55
54
  appid: app.id,
56
55
  devDnsAddr: (app as any).devDnsAddr,
57
56
  miniEnable: (app as any).miniEnable,
@@ -35,7 +35,7 @@ export async function getReleaseData(app: App, data: ReleaseData, naslServer: Na
35
35
  isExport: data.config.mode === ReleaseMode.ExportCode,
36
36
  isPreviewFe: data.config.mode === ReleaseMode.ExportTemplate,
37
37
  ignoreFiles: data.config.ignoreFiles ?? false,
38
- previewVersion: data.config.releaseVersion,
38
+ previewVersion: data.config.previewVersion ?? '',
39
39
  appSpecification: data.appSpecification,
40
40
  frontends: releaseFrontends,
41
41
  validations: {},
@@ -56,7 +56,7 @@ export async function getReleaseData(app: App, data: ReleaseData, naslServer: Na
56
56
 
57
57
  // 服务端验证规则
58
58
  if (app.preferenceMap.onDemandInterfaceGeneration !== 'false') {
59
- result.validations = await getValidationRules(http, version, releaseFrontends);
59
+ result.validations = await getValidationRules(http, version, app.frontendTypes);
60
60
 
61
61
  if (typeof result.validations === 'string') {
62
62
  throw new Error(result.validations);
@@ -27,8 +27,8 @@ export interface ReleaseConfig {
27
27
  mode: ReleaseMode;
28
28
  /** 忽略前端文件 */
29
29
  ignoreFiles?: boolean;
30
- /** 发布版本 */
31
- releaseVersion?: string;
30
+ /** 预览版本 */
31
+ previewVersion?: string;
32
32
  /** 调试模式 */
33
33
  debug?: boolean;
34
34
  /**
@@ -202,9 +202,9 @@ export async function getVersionDetail(axios: AxiosInstance, app: any) {
202
202
  };
203
203
  }
204
204
 
205
- export async function getValidationRules(axios: AxiosInstance, ideVersion: string, frontends: Frontend[]) {
205
+ export async function getValidationRules(axios: AxiosInstance, ideVersion: string, frontends: FrontendType[]) {
206
206
  const formData = new FormData();
207
- formData.append('file', new Blob([JSON.stringify(frontends.map((view: any) => view.toJSON()))], { type: 'application/json' }));
207
+ formData.append('file', new Blob([JSON.stringify(frontends.map((view) => view.toJSON()))], { type: 'application/json' }));
208
208
  const validations = await axios<HttpData>({
209
209
  method: 'post',
210
210
  url: `/api/v1/ide/nasl/frontend/call-logic/validations/batch`,
@@ -94,6 +94,7 @@ import {
94
94
  Paginate,
95
95
  MsgTriggerLauncher,
96
96
  ConnectorTrigger,
97
+ FrontendType,
97
98
  } from '../concepts';
98
99
 
99
100
  import * as utils from '../utils';
@@ -3021,9 +3022,9 @@ class NaslServer {
3021
3022
  const groupByLength = callQueryComponent.groupBy.filter(
3022
3023
  (item) => (item.groupElement as QueryFieldExpression)?.propertyName && (item.groupElement as QueryFieldExpression).asName
3023
3024
  ).length;
3024
- if (!groupByLength && !aggregateLength && callQueryComponentTypeAnnotation.typeKind === 'anonymousStructure') {
3025
+ if (!groupByLength && !aggregateLength && callQueryComponentTypeAnnotation.typeKind === 'generic') {
3025
3026
  // 拿到 List 的泛型(匿名数据结构)的所有属性
3026
- const {properties} = callQueryComponentTypeAnnotation.properties[0].typeAnnotation.typeArguments[0];
3027
+ const {properties} = callQueryComponentTypeAnnotation.typeArguments[0];
3027
3028
  const targetProperty = properties.find((p) => p.name === utils.firstLowerCase(node.name));
3028
3029
  if (!targetProperty) {
3029
3030
  continue;
@@ -3449,6 +3450,32 @@ class NaslServer {
3449
3450
  const newTextValue = node.parentNode.name === 'defaultDS' ? `/api/${newName}/import` : `/api/${node.parentNode.name}/${newName}/import`;
3450
3451
  minRange.setTypeMethods = 'setUrlValue';
3451
3452
  minRange.newValue = newTextValue;
3453
+ } else if (minRange.node instanceof BindAttribute && (minRange.node.name === 'valueField')) {
3454
+ // eslint-disable-next-line no-confusing-arrow
3455
+ minRange.newValue = (minRange.node.value || '').split('.').map((v, i) => i ? v : newValue.charAt(0).toLowerCase() + newValue.slice(1)).join('.')
3456
+ minRange.setTypeMethods = 'setValue';
3457
+ } else if (minRange.node instanceof BindAttribute && (minRange.node.name === 'sorting') && minRange.node.value) {
3458
+ // 现在 sorting 是不把 field 翻译出具体实体类型的,在文件系统中没有引用关系,无法处理他的改名
3459
+ try {
3460
+ // "{ field: undefined, order: 'desc' }" 格式解析成 Object
3461
+ const sortingObj = JSON.parse(
3462
+ minRange.node.value
3463
+ .replace(/([{,])\s*([A-Za-z0-9_]+)\s*:/g, '$1"$2":')
3464
+ .replace(/undefined/g, 'null')
3465
+ .replace(/'/g, '"')
3466
+ )
3467
+ if (sortingObj.field) {
3468
+ const handleValue = (value: any) => {
3469
+ return value ? `'${value}'` : undefined
3470
+ }
3471
+ // eslint-disable-next-line no-confusing-arrow
3472
+ const newField = sortingObj.field.split('.').map((v: string, i: number) => i ? v: newValue.charAt(0).toLowerCase() + newValue.slice(1)).join('.')
3473
+ minRange.newValue = `{ field: ${handleValue(newField)}, order: ${handleValue(sortingObj.order)} }`
3474
+ minRange.setTypeMethods = 'setValue';
3475
+ }
3476
+ } catch (error) {
3477
+ console.error(error)
3478
+ }
3452
3479
  } else if (minRange.node instanceof Identifier) {
3453
3480
  minRange.newValue = utils.firstLowerCase(newValue);
3454
3481
  }
@@ -3997,6 +4024,7 @@ class NaslServer {
3997
4024
  !(fileNode.parentNode instanceof DataSource) &&
3998
4025
  !(fileNode.parentNode instanceof Frontend) &&
3999
4026
  !(fileNode.parentNode instanceof Backend) &&
4027
+ !(fileNode.parentNode instanceof FrontendType) &&
4000
4028
  !isConnectorLogic &&
4001
4029
  !(fileNode instanceof View) &&
4002
4030
  !(fileNode instanceof BusinessComponent) &&
@@ -4040,7 +4068,7 @@ class NaslServer {
4040
4068
 
4041
4069
  if (['BindAttribute', 'BindDirective', 'BindStyle'].includes(node.concept)) {
4042
4070
  range.line = lsp2tspNumber(currentSource.end.line);
4043
- range.offset = 0;
4071
+ range.offset = 1;
4044
4072
  }
4045
4073
 
4046
4074
  return this._getFieldKeySelectCompletion({
@@ -4915,6 +4943,22 @@ class NaslServer {
4915
4943
  */
4916
4944
  async incidentalAction(action: string, fileNode: BaseNode, targetNode: BaseNode, oldpath?: string) {
4917
4945
  if ((action === 'create' || action === 'delete' || (action === 'update' && oldpath)) && fileNode === targetNode) {
4946
+ // 删除、新增端类型
4947
+ if (fileNode instanceof FrontendType && (fileNode.frontends?.length || fileNode.businessComponents?.length)) {
4948
+ const fileNodeChildren = [...fileNode.frontends, ...fileNode.businessComponents];
4949
+ for (let i = 0; i < fileNodeChildren.length; i++) {
4950
+ const fileNodeItem = fileNodeChildren[i];
4951
+ const result = await utils.timeSlicingWithGenerator((fileNodeItem as FileNode).toEmbeddedTSFile());
4952
+ fileNodeItem.sourceMap = result.sourceMap;
4953
+ if (action === 'create') {
4954
+ await this.handleChange(fileNodeItem, fileNodeItem, result, action);
4955
+ await this.incidentalAction(action, fileNodeItem, fileNodeItem);
4956
+ } else if (action === 'delete') {
4957
+ await this.handleDelete(fileNodeItem, fileNodeItem, result);
4958
+ await this.incidentalAction(action, fileNodeItem, fileNodeItem);
4959
+ }
4960
+ }
4961
+ }
4918
4962
  // 删除、更改、新增端
4919
4963
  if (fileNode instanceof Frontend && (fileNode.views?.length || fileNode.variables?.length)) {
4920
4964
  const fileNodeChildren = [...fileNode.views, ...fileNode.variables];
package/tmp/node-2.js CHANGED
@@ -39,6 +39,7 @@ async function projectOverLimit(files, root, limit) {
39
39
 
40
40
  result.push({
41
41
  title: data.title,
42
+ desc: data.desc,
42
43
  id: data.id,
43
44
  count: nodeCount,
44
45
  version: data.ideVersion,
@@ -57,7 +58,8 @@ async function main() {
57
58
  const largeInternalProjects = await projectOverLimit(internalProjects, internal, nodeLimit);
58
59
  const largeExternalProjects = await projectOverLimit(externalProjects, external, nodeLimit);
59
60
 
60
- 2debugger;
61
+ console.log(JSON.stringify(largeInternalProjects, null, 2));
62
+ console.log(JSON.stringify(largeExternalProjects, null, 2));
61
63
  }
62
64
 
63
65
  main();