oak-domain 5.1.7 → 5.1.9

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.
@@ -160,7 +160,7 @@ function pushStatementIntoSchemaAst(moduleName, statement, sourceFile) {
160
160
  */
161
161
  function checkActionDefNameConsistent(filename, actionDefNode) {
162
162
  const { name, type } = actionDefNode;
163
- (0, assert_1.default)(ts.isTypeReferenceNode(type));
163
+ (0, assert_1.default)(ts.isTypeReferenceNode(type), "ActionDef应该是一个类型引用");
164
164
  const { typeArguments } = type;
165
165
  (0, assert_1.default)(typeArguments.length === 2);
166
166
  const [actionNode, stateNode] = typeArguments;
@@ -173,7 +173,8 @@ function checkActionDefNameConsistent(filename, actionDefNode) {
173
173
  const adfName = name.text.slice(0, name.text.length - 9);
174
174
  const aName = actionNode.typeName.text.slice(0, actionNode.typeName.text.length - 6);
175
175
  const sName = stateNode.typeName.text.slice(0, stateNode.typeName.text.length - 5);
176
- (0, assert_1.default)(adfName === aName && aName === sName, `文件${filename}中的ActionDef${name.text}中ActionDef, Action和State的命名规则不一致`);
176
+ (0, assert_1.default)(adfName === aName && aName === sName, `文件${filename}中的ActionDef${name.text}中ActionDef, Action和State的命名规则不一致, 需要
177
+ ${adfName}ActionDef, ${adfName}Action, ${adfName}State`);
177
178
  }
178
179
  function checkStringLiteralLegal(filename, obj, text, ele) {
179
180
  (0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal), `${filename}中引用的${obj} ${text}中存在不是stringliteral的类型`);
@@ -188,13 +189,13 @@ function addImportedFrom(moduleName, name, node) {
188
189
  let propertyName;
189
190
  if (typeof node === 'object') {
190
191
  const { moduleSpecifier, importClause } = node;
191
- (0, assert_1.default)(ts.isStringLiteral(moduleSpecifier));
192
- (0, assert_1.default)(importClause);
192
+ (0, assert_1.default)(ts.isStringLiteral(moduleSpecifier), `${moduleName}中的${name}未引用正确的moduleSpecifier`);
193
+ (0, assert_1.default)(importClause, `${moduleName}中的${name}未引用正确的importClause`);
193
194
  const { namedBindings } = importClause;
194
- (0, assert_1.default)(namedBindings);
195
+ (0, assert_1.default)(namedBindings, `${moduleName}中的${name}未引用正确的namedBindings`);
195
196
  (0, assert_1.default)(ts.isNamedImports(namedBindings));
196
197
  const importSpecifier = namedBindings.elements.find((ele) => ele.name.text === name);
197
- (0, assert_1.default)(importSpecifier);
198
+ (0, assert_1.default)(importSpecifier, `${moduleName}中的${name}未引用正确的importSpecifier`);
198
199
  propertyName = importSpecifier.propertyName && importSpecifier.propertyName.text;
199
200
  importFrom = moduleSpecifier.text;
200
201
  }
@@ -209,7 +210,7 @@ function addImportedFrom(moduleName, name, node) {
209
210
  });
210
211
  }
211
212
  else {
212
- (0, assert_1.default)(name.endsWith("State"));
213
+ (0, assert_1.default)(name.endsWith("State"), `${moduleName}中的${name}未以State结尾`);
213
214
  (0, lodash_1.assign)(ast.importStateFrom, {
214
215
  [name]: [importFrom, propertyName],
215
216
  });
@@ -225,15 +226,15 @@ function analyzeExternalAttrImport(node, program, importAttrFrom, relativePath)
225
226
  if (ts.isImportSpecifier(declaration)) {
226
227
  const name = declaration.name.text;
227
228
  const importDeclartion = declaration.parent.parent.parent;
228
- (0, assert_1.default)(ts.isImportDeclaration(importDeclartion));
229
+ (0, assert_1.default)(ts.isImportDeclaration(importDeclartion), `未找到${name}的importDeclaration`);
229
230
  const { moduleSpecifier, importClause } = importDeclartion;
230
- (0, assert_1.default)(ts.isStringLiteral(moduleSpecifier));
231
- (0, assert_1.default)(importClause);
231
+ (0, assert_1.default)(ts.isStringLiteral(moduleSpecifier), `未找到${name}的moduleSpecifier`);
232
+ (0, assert_1.default)(importClause, `未找到${name}的importClause`);
232
233
  const { namedBindings } = importClause;
233
- (0, assert_1.default)(namedBindings);
234
- (0, assert_1.default)(ts.isNamedImports(namedBindings));
234
+ (0, assert_1.default)(namedBindings, `未找到${name}的namedBindings`);
235
+ (0, assert_1.default)(ts.isNamedImports(namedBindings), `未找到${name}的namedImports`);
235
236
  const importSpecifier = namedBindings.elements.find((ele) => ele.name.text === name);
236
- (0, assert_1.default)(importSpecifier);
237
+ (0, assert_1.default)(importSpecifier, `未找到${name}的importSpecifier`);
237
238
  const propertyName = importSpecifier.propertyName && importSpecifier.propertyName.text;
238
239
  const importFrom = moduleSpecifier.text;
239
240
  const importFromRelatively = importFrom.startsWith('.') ? (relativePath
@@ -279,9 +280,9 @@ function tryGetStringLiteralValues(moduleName, filename, obj, node, program) {
279
280
  }).filter(ele => !!ele));
280
281
  }
281
282
  if (['state', 'action'].includes(obj)) {
282
- (0, assert_1.default)(values.length > 0);
283
+ (0, assert_1.default)(values.length > 0, `${filename}中的${obj} ${node.typeName.getText()}未定义`);
283
284
  const importDeclartion = declaration.parent.parent.parent;
284
- (0, assert_1.default)(ts.isImportDeclaration(importDeclartion));
285
+ (0, assert_1.default)(ts.isImportDeclaration(importDeclartion), '未找到importDeclaration');
285
286
  addImportedFrom(moduleName, declaration.name.text, importDeclartion);
286
287
  }
287
288
  }
@@ -306,7 +307,7 @@ function tryGetStringLiteralValues(moduleName, filename, obj, node, program) {
306
307
  values.push(action);
307
308
  }
308
309
  if (['state', 'action'].includes(obj)) {
309
- (0, assert_1.default)(values.length > 0);
310
+ (0, assert_1.default)(values.length > 0, `${filename}中的${obj} ${node.typeName.getText()}未定义`);
310
311
  const ast = ActionAsts[moduleName];
311
312
  addImportedFrom(moduleName, declaration.name.text, './');
312
313
  }
@@ -339,8 +340,9 @@ function dealWithActionTypeNode(moduleName, filename, actionTypeNode, program, s
339
340
  (0, assert_1.default)((0, lodash_1.intersection)(actionNames, RESERVED_ACTION_NAMES).length === 0, `${filename}中的Action命名不能是「${RESERVED_ACTION_NAMES.join(',')}」之一`);
340
341
  actionTypeNode.types.forEach(ele => {
341
342
  if (ts.isTypeReferenceNode(ele)) {
343
+ // 这里递归了类型定义,去查找所有的action字符串
342
344
  const actionStrings = tryGetStringLiteralValues(moduleName, filename, 'action', ele, program);
343
- (0, assert_1.default)(actionStrings.length > 0);
345
+ (0, assert_1.default)(actionStrings.length > 0, `${filename}中的Action所引用的Type定义为空`);
344
346
  actionTexts.push(...actionStrings);
345
347
  }
346
348
  else {
@@ -354,7 +356,7 @@ function dealWithActionTypeNode(moduleName, filename, actionTypeNode, program, s
354
356
  (0, assert_1.default)(!RESERVED_ACTION_NAMES.includes(actionTypeNode.typeName.text), `${filename}中的Action命名不能是「${RESERVED_ACTION_NAMES.join(',')}」之一`);
355
357
  }
356
358
  const actionStrings = tryGetStringLiteralValues(moduleName, filename, 'action', actionTypeNode, program);
357
- (0, assert_1.default)(actionStrings.length > 0);
359
+ (0, assert_1.default)(actionStrings.length > 0, `${filename}中的Action定义为空`);
358
360
  actionTexts.push(...actionStrings);
359
361
  }
360
362
  else {
@@ -382,10 +384,10 @@ function dealWithActionDefInitializer(moduleName, initializer, program) {
382
384
  // 是从别处的引用,注入到mportActionDefFrom
383
385
  const checker = program.getTypeChecker();
384
386
  const identifier = ts.isIdentifier(initializer) ? initializer : initializer.expression;
385
- (0, assert_1.default)(ts.isIdentifier(identifier));
387
+ (0, assert_1.default)(ts.isIdentifier(identifier), "ActionDef的initializer不是一个Identifier");
386
388
  const symbol = checker.getSymbolAtLocation(identifier);
387
389
  const declaration = symbol?.getDeclarations()[0];
388
- (0, assert_1.default)(ts.isImportSpecifier(declaration));
390
+ (0, assert_1.default)(ts.isImportSpecifier(declaration), "ActionDef的initializer不是一个ImportSpecifier");
389
391
  const importDeclartion = declaration.parent.parent.parent;
390
392
  addImportedFrom(moduleName, identifier.text, importDeclartion);
391
393
  }
@@ -418,7 +420,7 @@ function getEntityImported(declaration) {
418
420
  function checkLocaleEnumAttrs(node, attrs, filename) {
419
421
  const { members } = node;
420
422
  const memberKeys = members.map((ele) => {
421
- (0, assert_1.default)(ts.isPropertySignature(ele) && ts.isIdentifier(ele.name));
423
+ (0, assert_1.default)(ts.isPropertySignature(ele) && ts.isIdentifier(ele.name), 'locale定义中的属性必须是identifier');
422
424
  return ele.name.text;
423
425
  });
424
426
  const lack = (0, lodash_1.difference)(attrs, memberKeys);
@@ -432,7 +434,7 @@ function checkLocaleExpressionPropertyExists(root, attr, exists, filename) {
432
434
  (0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)) && ts.isObjectLiteralExpression(ele.initializer));
433
435
  const { properties: p2 } = ele.initializer;
434
436
  const pp = p2.find((ele2) => {
435
- (0, assert_1.default)(ts.isPropertyAssignment(ele2) && ts.isIdentifier(ele2.name));
437
+ (0, assert_1.default)(ts.isPropertyAssignment(ele2) && ts.isIdentifier(ele2.name), 'locale定义中的属性必须是identifier');
436
438
  return ele2.name.text === attr;
437
439
  });
438
440
  if (exists && !pp) {
@@ -565,14 +567,9 @@ function analyzeImportDeclaration(node, referencedSchemas, additionalImports, fi
565
567
  }
566
568
  }
567
569
  /**
568
- * 在path下的filename文件中import了fileSpecifierPath,要找到其对应的引用路径
569
- * 这里关键是要处理形如file:的依赖声明
570
- * @param path
571
- * @param fileSpecifierPath
572
- * @param filename
573
- * @returns
570
+ * 处理模块的导入,得到导入文件的sourcefile
574
571
  */
575
- function getImportedFilePath(path, fileSpecifierPath, filename) {
572
+ function dealImportedFile(path, fileSpecifierPath, filename, program) {
576
573
  let importedFilepath = '';
577
574
  const getExistedFileName = () => {
578
575
  if ((0, fs_1.existsSync)(`${importedFilepath}.ts`)) {
@@ -587,39 +584,76 @@ function getImportedFilePath(path, fileSpecifierPath, filename) {
587
584
  importedFilepath = path_1.default.join(path, fileSpecifierPath);
588
585
  const importedFilename = getExistedFileName();
589
586
  (0, assert_1.default)(importedFilename, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
590
- return importedFilename;
591
- }
592
- else {
593
- const cwd = process.cwd();
594
- const fileSpecifierPaths = fileSpecifierPath.split('/');
595
- const moduleName = fileSpecifierPaths[0] || fileSpecifierPaths[1];
596
- (0, assert_1.default)(moduleName);
597
- // 从path向外找package.json -> node_modules直至找到fileSpecifier
598
- const paths = path.split('/');
599
- for (let iter = paths.length; iter >= 0; iter--) {
600
- const paths2 = paths.slice(0, iter);
601
- const pkgJsonPath = path_1.default.join(cwd, ...paths2, 'package.json');
602
- if ((0, fs_1.existsSync)(pkgJsonPath)) {
603
- const pkgJson = require(pkgJsonPath);
604
- if (pkgJson.dependencies?.hasOwnProperty(moduleName)) {
605
- const dependentPath = pkgJson.dependencies[moduleName];
606
- if (dependentPath.trimStart().startsWith('file:')) {
607
- const dependentFilePath = dependentPath.trimStart().slice(5);
608
- importedFilepath = path_1.default.join(pkgJsonPath, '..', dependentFilePath, ...(fileSpecifierPaths[0] ? fileSpecifierPaths.slice(1) : (fileSpecifierPaths.slice(2))));
609
- }
610
- else {
611
- importedFilepath = path_1.default.join(pkgJsonPath, '..', 'node_modules', fileSpecifierPath);
612
- }
613
- const importedFilename = getExistedFileName();
614
- if (importedFilename) {
615
- return importedFilename;
616
- }
617
- }
618
- }
619
- }
587
+ const sourceFile = program.getSourceFile(importedFilename);
588
+ (0, assert_1.default)(sourceFile, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
589
+ return [sourceFile, importedFilename];
620
590
  }
621
- (0, assert_1.default)(false, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
591
+ // 创建编译器主机
592
+ const compilerHost = ts.createCompilerHost(program.getCompilerOptions());
593
+ // 解析模块
594
+ const resolvedModule = ts.resolveModuleName(fileSpecifierPath, filename, program.getCompilerOptions(), compilerHost);
595
+ (0, assert_1.default)(resolvedModule.resolvedModule, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
596
+ const pathName = resolvedModule.resolvedModule.resolvedFileName;
597
+ const sourceFile = program.getSourceFile(pathName);
598
+ (0, assert_1.default)(sourceFile, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
599
+ return [sourceFile, pathName];
622
600
  }
601
+ /**
602
+ * 在path下的filename文件中import了fileSpecifierPath,要找到其对应的引用路径
603
+ * 这里关键是要处理形如file:的依赖声明
604
+ * @param path
605
+ * @param fileSpecifierPath
606
+ * @param filename
607
+ * @returns
608
+ */
609
+ // function getImportedFilePath(path: string, fileSpecifierPath: string, filename: string) {
610
+ // let importedFilepath = '';
611
+ // const getExistedFileName = () => {
612
+ // if (existsSync(`${importedFilepath}.ts`)) {
613
+ // return `${importedFilepath}.ts`;
614
+ // }
615
+ // else if (existsSync(`${importedFilepath}.d.ts`)) {
616
+ // return `${importedFilepath}.d.ts`;
617
+ // }
618
+ // return '';
619
+ // };
620
+ // if (fileSpecifierPath.startsWith('.')) {
621
+ // importedFilepath = PathLib.join(path, fileSpecifierPath);
622
+ // const importedFilename = getExistedFileName();
623
+ // assert(importedFilename, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
624
+ // return importedFilename;
625
+ // }
626
+ // else {
627
+ // const cwd = process.cwd();
628
+ // const fileSpecifierPaths = fileSpecifierPath.split('/');
629
+ // const moduleName = fileSpecifierPaths[0] || fileSpecifierPaths[1];
630
+ // assert(moduleName, '「${filename}」中import路径不合法');
631
+ // // 从path向外找package.json -> node_modules直至找到fileSpecifier
632
+ // const paths = path.split('/');
633
+ // for (let iter = paths.length; iter >= 0; iter--) {
634
+ // const paths2 = paths.slice(0, iter);
635
+ // const pkgJsonPath = PathLib.join(cwd, ...paths2, 'package.json');
636
+ // if (existsSync(pkgJsonPath)) {
637
+ // const pkgJson = require(pkgJsonPath);
638
+ // if (pkgJson.dependencies?.hasOwnProperty(moduleName)) {
639
+ // const dependentPath = pkgJson.dependencies[moduleName] as string;
640
+ // if (dependentPath.trimStart().startsWith('file:')) {
641
+ // const dependentFilePath = dependentPath.trimStart().slice(5);
642
+ // importedFilepath = PathLib.join(pkgJsonPath, '..', dependentFilePath, ...(fileSpecifierPaths[0] ? fileSpecifierPaths.slice(1) : (fileSpecifierPaths.slice(2))));
643
+ // }
644
+ // else {
645
+ // importedFilepath = PathLib.join(pkgJsonPath, '..', 'node_modules', fileSpecifierPath);
646
+ // }
647
+ // const importedFilename = getExistedFileName();
648
+ // if (importedFilename) {
649
+ // return importedFilename;
650
+ // }
651
+ // }
652
+ // }
653
+ // }
654
+ // }
655
+ // assert(false, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
656
+ // }
623
657
  function analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, relativePath) {
624
658
  let hasEntityAttr = false;
625
659
  let hasEntityIdAttr = false;
@@ -627,30 +661,28 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
627
661
  let toLog = false;
628
662
  const extendsFrom = [];
629
663
  const { members, heritageClauses } = node;
630
- (0, assert_1.default)(heritageClauses);
664
+ (0, assert_1.default)(heritageClauses, `「${filename}」中的Schema定义需要继承EntityShape或者其他Entity`);
631
665
  const heritagedResult = heritageClauses.map((clause) => {
632
666
  const { expression } = clause.types[0];
633
- (0, assert_1.default)(ts.isIdentifier(expression));
667
+ (0, assert_1.default)(ts.isIdentifier(expression), `${expression}不是一个合法的继承类型`);
634
668
  if (expression.text === 'EntityShape') {
635
669
  // import { EntityShape } from 'oak-domain/lib/types/Entities; 所有schema的公共祖先类型,不用处理
636
670
  return;
637
671
  }
638
672
  // 从其它文件的Schema类继承,这里需要将所继承的对象的属性进行访问并展开
639
- (0, assert_1.default)(referencedSchemas.includes(expression.text));
673
+ (0, assert_1.default)(referencedSchemas.includes(expression.text), `「${filename}」中的Schema继承了未定义的实体「${expression.text}」`);
640
674
  const checker = program.getTypeChecker();
641
675
  const symbol = checker.getSymbolAtLocation(expression);
642
676
  let declaration = symbol?.getDeclarations()[0];
643
- (0, assert_1.default)(ts.isImportSpecifier(declaration));
677
+ (0, assert_1.default)(ts.isImportSpecifier(declaration), `${declaration.getText()}应该是导入的类型`);
644
678
  const importDeclaration = declaration.parent.parent.parent;
645
- (0, assert_1.default)(ts.isImportDeclaration(importDeclaration));
679
+ (0, assert_1.default)(ts.isImportDeclaration(importDeclaration), `${declaration.getText()}应该是导入的类型`);
646
680
  const { moduleSpecifier } = importDeclaration;
647
- (0, assert_1.default)(ts.isStringLiteral(moduleSpecifier));
681
+ (0, assert_1.default)(ts.isStringLiteral(moduleSpecifier), `${declaration.getText()}应该是导入的类型`);
648
682
  const { text: from } = moduleSpecifier;
649
683
  extendsFrom.push(from);
650
- const importedFilename = getImportedFilePath(path, from, filename);
651
- const sourceFile = program.getSourceFile(importedFilename);
652
- (0, assert_1.default)(sourceFile, `「${filename}」找不到相应的sourceFile:${importedFilename}`);
653
- const relativeFilename = path_1.default.relative(process.cwd(), importedFilename);
684
+ const [sourceFile, pathName] = dealImportedFile(path, from, filename, program);
685
+ const relativeFilename = path_1.default.relative(process.cwd(), pathName);
654
686
  const result = analyzeReferenceSchemaFile(moduleName, path_1.default.basename(relativeFilename), path_1.default.dirname(relativeFilename), sourceFile, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, path_1.default.join(from, '..'));
655
687
  return result;
656
688
  }).filter(ele => !!ele);
@@ -730,7 +762,7 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
730
762
  else {
731
763
  schemaAttrs.push(attrNode);
732
764
  if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) && ts.isStringLiteral(type.types[0].literal)) {
733
- (0, assert_1.default)(ts.isIdentifier(name));
765
+ (0, assert_1.default)(ts.isIdentifier(name), `「${filename}」中的属性定义不是String类型`);
734
766
  const { types } = type;
735
767
  const enumValues = types.map((ele) => checkStringLiteralLegal(filename, '属性', name.text, ele));
736
768
  enumAttributes[name.text] = enumValues;
@@ -825,13 +857,13 @@ function analyzeReferenceSchemaFile(moduleName, filename, path, sourceFile, prog
825
857
  }
826
858
  }
827
859
  });
828
- (0, assert_1.default)(result);
860
+ (0, assert_1.default)(result, `「${filename}」中没有找到Schema定义`);
829
861
  return result;
830
862
  }
831
863
  function analyzeEntity(filename, path, program, relativePath) {
832
864
  const fullPath = `${path}/${filename}`;
833
865
  const sourceFile = program.getSourceFile(fullPath);
834
- (0, assert_1.default)(sourceFile);
866
+ (0, assert_1.default)(sourceFile, `「${filename}」文件不存在`);
835
867
  const moduleName = filename.split('.')[0];
836
868
  if (Schema.hasOwnProperty(moduleName)) {
837
869
  delete ActionAsts[moduleName];
@@ -918,13 +950,13 @@ function analyzeEntity(filename, path, program, relativePath) {
918
950
  (0, assert_1.default)(!localeDef, `【${filename}】locale定义须在Relation之后`);
919
951
  const relationValues = [];
920
952
  if (ts.isLiteralTypeNode(node.type)) {
921
- (0, assert_1.default)(ts.isStringLiteral(node.type.literal));
953
+ (0, assert_1.default)(ts.isStringLiteral(node.type.literal), `${filename}中的Relation的定义只能是string类型`);
922
954
  (0, assert_1.default)(node.type.literal.text.length < env_1.STRING_LITERAL_MAX_LENGTH, `Relation定义的字符串长度不长于${env_1.STRING_LITERAL_MAX_LENGTH}(${filename},${node.type.literal.text})`);
923
955
  relationValues.push(node.type.literal.text);
924
956
  }
925
957
  else if (ts.isTypeReferenceNode(node.type)) {
926
958
  const relationStrings = tryGetStringLiteralValues(moduleName, filename, 'relation', node.type, program);
927
- (0, assert_1.default)(relationStrings.length > 0);
959
+ (0, assert_1.default)(relationStrings.length > 0, `文件${filename}中的relation${node.type.typeName.text}定义未找到字符串类型`);
928
960
  relationValues.push(...relationStrings);
929
961
  }
930
962
  else {
@@ -938,7 +970,7 @@ function analyzeEntity(filename, path, program, relativePath) {
938
970
  else {
939
971
  (0, assert_1.default)(ts.isTypeReferenceNode(ele), `Relation的定义只能是string类型,或者string union类型,或者两者的union(${filename})`);
940
972
  const relationStrings = tryGetStringLiteralValues(moduleName, filename, 'relation', ele, program);
941
- (0, assert_1.default)(relationStrings.length > 0);
973
+ (0, assert_1.default)(relationStrings.length > 0, `文件${filename}中的relation${ele.typeName.text}定义未找到字符串类型`);
942
974
  relationValues.push(...relationStrings);
943
975
  }
944
976
  });
@@ -990,7 +1022,7 @@ function analyzeEntity(filename, path, program, relativePath) {
990
1022
  ]) : type), sourceFile);
991
1023
  }
992
1024
  else {
993
- (0, assert_1.default)(ts.isLiteralTypeNode(type) || ts.isTypeReferenceNode(type), `${moduleName} - ${node.name}`);
1025
+ (0, assert_1.default)(ts.isLiteralTypeNode(type) || ts.isTypeReferenceNode(type), `文件${filename}中的${type.getText()}应该是字面量或引用类型`);
994
1026
  pushStatementIntoActionAst(moduleName, factory.updateTypeAliasDeclaration(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], node.name, node.typeParameters, process.env.COMPLING_AS_LIB ? factory.createUnionTypeNode([
995
1027
  type,
996
1028
  factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
@@ -1007,12 +1039,12 @@ function analyzeEntity(filename, path, program, relativePath) {
1007
1039
  const dealWithActionDef = (declaration) => {
1008
1040
  checkActionDefNameConsistent(filename, declaration);
1009
1041
  const { typeArguments } = declaration.type;
1010
- (0, assert_1.default)(typeArguments.length === 2);
1042
+ (0, assert_1.default)(typeArguments.length === 2, `文件${filename}中的action定义不是两个泛型参数`);
1011
1043
  const [actionNode, stateNode] = typeArguments;
1012
- (0, assert_1.default)(ts.isTypeReferenceNode(actionNode));
1044
+ (0, assert_1.default)(ts.isTypeReferenceNode(actionNode), `文件${filename}中的action定义不是TypeReferenceNode`);
1013
1045
  // 这里有可能引用的Action不是本文件的定义,要调用这个函数加到importFrom中
1014
1046
  tryGetStringLiteralValues(moduleName, filename, 'action', actionNode, program);
1015
- (0, assert_1.default)(ts.isTypeReferenceNode(stateNode));
1047
+ (0, assert_1.default)(ts.isTypeReferenceNode(stateNode), `文件${filename}中的action定义不是TypeReferenceNode`);
1016
1048
  const enumStateValues = tryGetStringLiteralValues(moduleName, filename, 'state', stateNode, program);
1017
1049
  (0, assert_1.default)(enumStateValues.length > 0, `文件${filename}中的state${stateNode.typeName.text}定义不是字符串类型`);
1018
1050
  pushStatementIntoActionAst(moduleName, node, sourceFile);
@@ -1029,18 +1061,18 @@ function analyzeEntity(filename, path, program, relativePath) {
1029
1061
  const { elements } = declaration;
1030
1062
  elements.forEach((ele) => {
1031
1063
  let isFulltextIndex = false;
1032
- (0, assert_1.default)(ts.isObjectLiteralExpression(ele));
1064
+ (0, assert_1.default)(ts.isObjectLiteralExpression(ele), `「${filename}」中索引定义应该是对象字面量`);
1033
1065
  const { properties } = ele;
1034
1066
  const attrProperty = properties.find((ele2) => {
1035
- (0, assert_1.default)(ts.isPropertyAssignment(ele2));
1067
+ (0, assert_1.default)(ts.isPropertyAssignment(ele2), `「${filename}」中索引的属性不为PropertyAssignment`);
1036
1068
  return ele2.name.getText() === 'attributes';
1037
1069
  });
1038
- (0, assert_1.default)(ts.isArrayLiteralExpression(attrProperty.initializer));
1070
+ (0, assert_1.default)(ts.isArrayLiteralExpression(attrProperty.initializer), `「${filename}」中索引的attributes属性应该是数组字面量`);
1039
1071
  const nameProperty = properties.find((ele2) => {
1040
1072
  (0, assert_1.default)(ts.isPropertyAssignment(ele2));
1041
1073
  return ele2.name.getText() === 'name';
1042
1074
  });
1043
- (0, assert_1.default)(ts.isStringLiteral(nameProperty.initializer));
1075
+ (0, assert_1.default)(ts.isStringLiteral(nameProperty.initializer), '「${filename}」中索引的name属性应该是字符串字面量');
1044
1076
  const nameText = nameProperty.initializer.text;
1045
1077
  if (indexNameDict[nameText]) {
1046
1078
  throw new Error(`「${filename}」索引定义重名「${nameText}」`);
@@ -1049,14 +1081,14 @@ function analyzeEntity(filename, path, program, relativePath) {
1049
1081
  [nameText]: true,
1050
1082
  });
1051
1083
  const configProperty = properties.find((ele2) => {
1052
- (0, assert_1.default)(ts.isPropertyAssignment(ele2));
1084
+ (0, assert_1.default)(ts.isPropertyAssignment(ele2), `「${filename}」中索引的属性不为PropertyAssignment`);
1053
1085
  return ele2.name.getText() === 'config';
1054
1086
  });
1055
1087
  if (configProperty) {
1056
- (0, assert_1.default)(ts.isObjectLiteralExpression(configProperty.initializer));
1088
+ (0, assert_1.default)(ts.isObjectLiteralExpression(configProperty.initializer), `「${filename}」中索引的config属性应该是对象字面量`);
1057
1089
  const { properties: properties2 } = configProperty.initializer;
1058
1090
  const typeProperty = properties2.find((ele2) => {
1059
- (0, assert_1.default)(ts.isPropertyAssignment(ele2));
1091
+ (0, assert_1.default)(ts.isPropertyAssignment(ele2), `「${filename}」中索引的属性不为PropertyAssignment`);
1060
1092
  return ele2.name.getText() === 'type';
1061
1093
  });
1062
1094
  if (typeProperty && typeProperty.initializer.text === 'fulltext') {
@@ -1171,21 +1203,21 @@ function analyzeEntity(filename, path, program, relativePath) {
1171
1203
  if (ts.isObjectLiteralExpression(declaration)) {
1172
1204
  const { properties } = declaration;
1173
1205
  const localesProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'locales');
1174
- (0, assert_1.default)(ts.isPropertyAssignment(localesProperty));
1206
+ (0, assert_1.default)(ts.isPropertyAssignment(localesProperty), `「${filename}」中entityDesc的locales应该是属性声明`);
1175
1207
  dealWithLocales(localesProperty.initializer);
1176
1208
  const indexesProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'indexes');
1177
1209
  if (indexesProperty) {
1178
- (0, assert_1.default)(ts.isPropertyAssignment(indexesProperty));
1210
+ (0, assert_1.default)(ts.isPropertyAssignment(indexesProperty), `「${filename}」中entityDesc的indexes应该是属性声明`);
1179
1211
  dealWithIndexes(indexesProperty.initializer);
1180
1212
  }
1181
1213
  const configurationProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'configuration');
1182
1214
  if (configurationProperty) {
1183
- (0, assert_1.default)(ts.isPropertyAssignment(configurationProperty));
1215
+ (0, assert_1.default)(ts.isPropertyAssignment(configurationProperty), `「${filename}」中entityDesc的configuration应该是属性声明`);
1184
1216
  dealWithConfiguration(configurationProperty.initializer);
1185
1217
  }
1186
1218
  const styleDescProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'style');
1187
1219
  if (styleDescProperty) {
1188
- (0, assert_1.default)(ts.isPropertyAssignment(styleDescProperty));
1220
+ (0, assert_1.default)(ts.isPropertyAssignment(styleDescProperty), `「${filename}」中entityDesc的style应该是属性声明`);
1189
1221
  dealWithStyleDesc(styleDescProperty.initializer);
1190
1222
  }
1191
1223
  }
@@ -1216,14 +1248,14 @@ function analyzeEntity(filename, path, program, relativePath) {
1216
1248
  && declaration.type.typeArguments[0].typeName.text === 'Index')) {
1217
1249
  // 对索引Index的定义
1218
1250
  console.log(`「${filename}」直接定义indexes的写法已经过时,请定义在entityDesc中`);
1219
- (0, assert_1.default)(ts.isArrayLiteralExpression(declaration.initializer));
1251
+ (0, assert_1.default)(ts.isArrayLiteralExpression(declaration.initializer), `「${filename}」中索引定义应该是数组字面量`);
1220
1252
  dealWithIndexes(declaration.initializer);
1221
1253
  }
1222
1254
  else if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'LocaleDef') {
1223
1255
  // locale定义
1224
1256
  console.log(`「${filename}」直接定义locales的写法已经过时,请定义在entityDesc中`);
1225
1257
  const { type, initializer } = declaration;
1226
- (0, assert_1.default)(ts.isObjectLiteralExpression(initializer));
1258
+ (0, assert_1.default)(ts.isObjectLiteralExpression(initializer), `「${filename}」中locale定义应该是对象字面量`);
1227
1259
  const { properties } = initializer;
1228
1260
  (0, assert_1.default)(properties.length > 0, `${filename}至少需要有一种locale定义`);
1229
1261
  const allEnumStringAttrs = Object.keys(enumAttributes);
@@ -1260,12 +1292,12 @@ function analyzeEntity(filename, path, program, relativePath) {
1260
1292
  }
1261
1293
  else if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'Configuration') {
1262
1294
  console.log(`「${filename}」直接定义configuration的写法已经过时,请定义在entityDesc中`);
1263
- (0, assert_1.default)(ts.isObjectLiteralExpression(declaration.initializer));
1295
+ (0, assert_1.default)(ts.isObjectLiteralExpression(declaration.initializer), `「${filename}」中configuration定义应该是对象字面量`);
1264
1296
  dealWithConfiguration(declaration.initializer);
1265
1297
  }
1266
1298
  else if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'EntityDesc') {
1267
1299
  const { initializer } = declaration;
1268
- (0, assert_1.default)(initializer);
1300
+ (0, assert_1.default)(initializer, `「${filename}」中entityDesc的定义不应该为空`);
1269
1301
  dealWithEntityDesc(initializer);
1270
1302
  }
1271
1303
  else {
@@ -1609,7 +1641,7 @@ function constructFilter(statements, entity) {
1609
1641
  }
1610
1642
  else {
1611
1643
  // 此时应当是引用本地定义的shape
1612
- (0, assert_1.default)(type);
1644
+ (0, assert_1.default)(type, `${entity}中的属性${name.toString()}有非法的属性类型定义`);
1613
1645
  members.push(factory.createPropertySignature(undefined, name, undefined, factory.createTypeReferenceNode(factory.createIdentifier('JsonFilter'), [
1614
1646
  type
1615
1647
  ])));
@@ -3110,7 +3142,7 @@ function outputSchema(outputDir, printer) {
3110
3142
  const fromLocalActionSpecifiers = ['Action', 'ParticularAction'];
3111
3143
  const fromExtenalStates = {};
3112
3144
  for (const state in importStateFrom) {
3113
- (0, assert_1.default)(state.endsWith('State'));
3145
+ (0, assert_1.default)(state.endsWith('State'), `${state} should end with State`);
3114
3146
  if (importStateFrom[state][0] === './') {
3115
3147
  // 本地定义的State从 ./Action 中获取
3116
3148
  fromLocalActionSpecifiers.push(state);
@@ -3239,7 +3271,7 @@ function outputAction(outputDir, printer) {
3239
3271
  const importStatements = [];
3240
3272
  const fromExternalImports = {};
3241
3273
  for (const state in importStateFrom) {
3242
- (0, assert_1.default)(state.endsWith('State'));
3274
+ (0, assert_1.default)(state.endsWith('State'), `${state} should end with State`);
3243
3275
  const [from, propertyName] = importStateFrom[state];
3244
3276
  if (from !== './') {
3245
3277
  if (fromExternalImports[from]) {
@@ -3251,7 +3283,7 @@ function outputAction(outputDir, printer) {
3251
3283
  }
3252
3284
  }
3253
3285
  for (const action in importActionFrom) {
3254
- (0, assert_1.default)(action.endsWith('Action'));
3286
+ (0, assert_1.default)(action.endsWith('Action'), `${action} should end with Action`);
3255
3287
  const [from, propertyName] = importActionFrom[action];
3256
3288
  if (from !== './') {
3257
3289
  if (fromExternalImports[from]) {
@@ -3263,7 +3295,7 @@ function outputAction(outputDir, printer) {
3263
3295
  }
3264
3296
  }
3265
3297
  for (const def in importActionDefFrom) {
3266
- (0, assert_1.default)(def.endsWith('ActionDef'));
3298
+ (0, assert_1.default)(def.endsWith('ActionDef'), `${def} should end with ActionDef`);
3267
3299
  const [from, propertyName] = importActionDefFrom[def];
3268
3300
  if (from !== './') {
3269
3301
  if (fromExternalImports[from]) {
@@ -3405,11 +3437,11 @@ function constructAttributes(entity) {
3405
3437
  if (ts.isUnionTypeNode(type)) {
3406
3438
  if (ts.isLiteralTypeNode(type.types[0])) {
3407
3439
  if (ts.isStringLiteral(type.types[0].literal)) {
3408
- (0, assert_1.default)(enumAttributes && enumAttributes[name.text]);
3440
+ (0, assert_1.default)(enumAttributes && enumAttributes[name.text], `${entity}对象中的${name.text}属性没有定义enumAttributes`);
3409
3441
  attrAssignments.push(factory.createPropertyAssignment('type', factory.createStringLiteral("enum")), factory.createPropertyAssignment('enumeration', factory.createArrayLiteralExpression(enumAttributes[name.text].map(ele => factory.createStringLiteral(ele)))));
3410
3442
  }
3411
3443
  else {
3412
- (0, assert_1.default)(ts.isNumericLiteral(type.types[0].literal));
3444
+ (0, assert_1.default)(ts.isNumericLiteral(type.types[0].literal), `${entity}对象中的${type.types[0].literal.getText()}属性不是数字`);
3413
3445
  attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("int")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
3414
3446
  factory.createPropertyAssignment(factory.createIdentifier("width"), factory.createNumericLiteral(env_1.INT_LITERL_DEFAULT_WIDTH))
3415
3447
  ], true)));
@@ -3426,7 +3458,7 @@ function constructAttributes(entity) {
3426
3458
  attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(env_1.STRING_LITERAL_MAX_LENGTH))], true)));
3427
3459
  }
3428
3460
  else {
3429
- (0, assert_1.default)(ts.isNumericLiteral(type.literal));
3461
+ (0, assert_1.default)(ts.isNumericLiteral(type.literal), `${entity}对象中的${name.text}属性不是数字`);
3430
3462
  attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("precision")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
3431
3463
  factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_PRECISION)),
3432
3464
  factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_SCALE))
@@ -3451,14 +3483,14 @@ function outputLocale(outputDir, printer) {
3451
3483
  if (locale) {
3452
3484
  const { properties } = locale;
3453
3485
  properties.forEach((ele) => {
3454
- (0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)) && ts.isObjectLiteralExpression(ele.initializer));
3486
+ (0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)) && ts.isObjectLiteralExpression(ele.initializer), `${entity}对象中的locale属性定义不正确`);
3455
3487
  const lng = ele.name.text;
3456
3488
  const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray([
3457
3489
  factory.createReturnStatement(ele.initializer)
3458
3490
  ]), sourceFile);
3459
3491
  const data = Function(result)();
3460
3492
  const filename = path_1.default.join(outputDir, entity, 'locales', `${lng}.json`);
3461
- (0, fs_1.writeFileSync)(filename, JSON.stringify(data), { flag: 'w' });
3493
+ (0, fs_1.writeFileSync)(filename, JSON.stringify(data, null, 2), { flag: 'w' });
3462
3494
  if (locales[lng]) {
3463
3495
  locales[lng].push(entity);
3464
3496
  }
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const entityDesc = {
5
5
  locales: {
6
6
  zh_CN: {
7
- name: '用户授权',
7
+ name: 'i18n',
8
8
  attr: {
9
9
  module: '模块',
10
10
  position: '文件位置',
@@ -269,7 +269,7 @@ function cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, restA
269
269
  * 先找到能直接更新成功的属性
270
270
  */
271
271
  const legalAttrResult = restAttrs.map((attr) => {
272
- const { filter: f } = matrix[attr];
272
+ const { filter: f } = matrix[attr] || {};
273
273
  if (!f) {
274
274
  return true;
275
275
  }
@@ -331,6 +331,7 @@ function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
331
331
  const actions = condition.map(ele => ele?.actions).filter(ele => !!ele);
332
332
  const a = actions.length > 0 && (0, lodash_1.intersection)(actions.flat());
333
333
  if (a) {
334
+ (0, assert_1.default)(action);
334
335
  if (!a.includes(action)) {
335
336
  // 找到不满足的那个attr
336
337
  const attrsIllegal = attrs.filter((attr) => matrix[attr]?.actions && !matrix[attr]?.actions?.includes(action));
@@ -253,10 +253,13 @@ class TriggerExecutor {
253
253
  cxtStr2 = data.$$triggerData$$?.cxtStr;
254
254
  }
255
255
  const record = opRecords.find(ele => ele.id === operation.id);
256
- // 目前框架在operation时,一定会将ids记录在operation当中(见CascadeStore中的doUpdateSingleRowAsync函数
257
- (0, assert_1.default)(record && record.a !== 'c');
258
- const { f } = record;
259
- ids = f.id.$in;
256
+ if (record) {
257
+ // 目前框架在operation时,一定会将ids记录在operation当中(见CascadeStore中的doUpdateSingleRowAsync函数
258
+ // 但也有一种可能,此operation没有更新任何一行。by Xc 20241022
259
+ (0, assert_1.default)(record.a !== 'c');
260
+ const { f } = record;
261
+ ids = f.id.$in;
262
+ }
260
263
  }
261
264
  // 此时项目的上下文,和执行此trigger时的上下文可能不一致(rootMode),采用当时的上下文cxtStr来执行
262
265
  this.onVolatileTrigger(entity, trigger, ids, cxtStr2, option);
@@ -348,12 +351,12 @@ class TriggerExecutor {
348
351
  async execVolatileTrigger(entity, name, ids, context, option) {
349
352
  const trigger = this.triggerNameMap[name];
350
353
  (0, assert_1.default)(trigger && trigger.when === 'commit');
351
- (0, assert_1.default)(ids.length > 0);
354
+ // assert(ids.length > 0);
352
355
  const { fn } = trigger;
353
356
  const closeRoot = trigger.asRoot && context.openRootMode();
354
357
  try {
355
358
  const callback = await fn({ ids }, context, option);
356
- if (trigger.strict === 'makeSure') {
359
+ if (trigger.strict === 'makeSure' && ids.length) {
357
360
  // 这里开root模式,否则还可能有权限问题
358
361
  const closeRoot2 = context.openRootMode();
359
362
  try {
@@ -1621,7 +1621,7 @@ function checkDeduceFilters(dfc, context) {
1621
1621
  * @returns
1622
1622
  */
1623
1623
  function checkFilterContains(entity, context, contained, filter, dataCompare, warningOnDataCompare) {
1624
- (0, assert_1.default)(filter);
1624
+ (0, assert_1.default)(filter, `对${entity}的访问必须有filter`);
1625
1625
  const schema = context.getSchema();
1626
1626
  const result = contains(entity, schema, filter, contained);
1627
1627
  if (typeof result === 'boolean') {
@@ -362,41 +362,25 @@ exports.logTriggers = [
362
362
  return (result.oper?.remove || 0) + (result2.log?.remove || 0);
363
363
  }
364
364
  },
365
- // 在删除log时,解除与此log关联的oper
365
+ // 在删除log时,删除与此log关联的oper
366
366
  {
367
- name: '当删除log时,解除与此log关联的oper',
367
+ name: '当删除log时,删除与此log关联的oper',
368
368
  entity: 'log',
369
369
  action: 'remove',
370
370
  when: 'before',
371
371
  fn: async ({ operation }, context) => {
372
372
  const { filter } = operation;
373
373
  (0, assert_1.default)(filter);
374
- // 查询这次删除操作涉及到的所有log
375
- const logs = await context.select('log', {
376
- data: {
377
- id: 1,
378
- oper$log: {
379
- $entity: 'oper',
380
- data: {
381
- id: 1,
382
- },
383
- },
384
- },
385
- filter,
374
+ // 查询这次删除操作涉及到的所有log
375
+ const result = await context.operate('oper', {
376
+ id: "dummy",
377
+ action: 'remove',
378
+ data: {},
379
+ filter: {
380
+ log: filter,
381
+ }
386
382
  }, {});
387
- const operIds = logs.flatMap(log => log.oper$log.map(oper => oper.id));
388
- let result = 0;
389
- for (const operId of operIds) {
390
- const result2 = await context.operate('oper', {
391
- id: operId,
392
- action: 'update',
393
- data: {
394
- logId: null,
395
- },
396
- }, {});
397
- result += result2.oper?.update || 0;
398
- }
399
- return result;
383
+ return result.oper?.remove || 0;
400
384
  }
401
385
  },
402
386
  ];
@@ -29,7 +29,7 @@ export type ServerConfiguration = {
29
29
  socketPath: string;
30
30
  };
31
31
  cors?: {
32
- origin: string;
32
+ origin: string | string[];
33
33
  headers?: string[];
34
34
  methods?: string[];
35
35
  };
@@ -42,10 +42,10 @@ export type AccessConfiguration = {
42
42
  routerPrefixes?: {
43
43
  aspect?: string;
44
44
  endpoint?: string;
45
- subscribe?: string;
46
45
  getSubscribePoint?: string;
47
46
  bridge?: string;
48
47
  };
48
+ socketPath?: string;
49
49
  http: {
50
50
  hostname: string;
51
51
  port?: number;
@@ -26,10 +26,11 @@ export interface Connector<ED extends EntityDict & BaseEntityDict, FrontCxt exte
26
26
  };
27
27
  headers?: Record<string, any>;
28
28
  };
29
- getSubscribeRouter: () => string;
30
- getSubscribePointRouter: () => string;
31
- getSubscribePoint: () => Promise<{
32
- url: string;
29
+ getSocketPath: () => string;
30
+ getSocketPointRouter: () => string;
31
+ getSocketPoint: () => Promise<{
32
+ socketUrl: string;
33
+ subscribeUrl: string;
33
34
  path: string;
34
35
  }>;
35
36
  getBridgeRouter: () => string;
@@ -42,4 +43,5 @@ export interface Connector<ED extends EntityDict & BaseEntityDict, FrontCxt exte
42
43
  getFullData: (keys?: (keyof ED)[]) => Promise<{
43
44
  [T in keyof ED]?: ED[T]['OpSchema'][];
44
45
  }>;
46
+ getCorsHeader: () => string[];
45
47
  }
@@ -72,6 +72,8 @@ export declare class OakNetworkException<ED extends EntityDict & BaseEntityDict>
72
72
  }
73
73
  export declare class OakServerProxyException<ED extends EntityDict & BaseEntityDict> extends OakException<ED> {
74
74
  }
75
+ export declare class OakClockDriftException<ED extends EntityDict & BaseEntityDict> extends OakException<ED> {
76
+ }
75
77
  /**
76
78
  * 数据不一致异常,系统认为现有的数据不允许相应的动作时抛此异常
77
79
  *
@@ -128,7 +130,7 @@ export declare class OakUnloggedInException<ED extends EntityDict & BaseEntityDi
128
130
  constructor(message?: string);
129
131
  }
130
132
  /**
131
- * 用户未登录抛的异常
133
+ * 行数据被锁抛的异常
132
134
  */
133
135
  export declare class OakRowLockedException<ED extends EntityDict & BaseEntityDict> extends OakUserException<ED> {
134
136
  constructor(message?: string);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeException = exports.OakSocketConnectException = exports.OakExternalException = exports.OakPreConditionUnsetException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserInvisibleException = exports.OakUserUnpermittedException = exports.OakAttrCantUpdateException = exports.OakAttrNotNullException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakServerProxyException = exports.OakNetworkException = exports.OakImportDataParseException = exports.OakUniqueViolationException = exports.OakUserException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakNoRelationDefException = exports.OakDataException = exports.OakPartialSuccess = exports.OakMakeSureByMySelfException = exports.OakException = void 0;
3
+ exports.makeException = exports.OakSocketConnectException = exports.OakExternalException = exports.OakPreConditionUnsetException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserInvisibleException = exports.OakUserUnpermittedException = exports.OakAttrCantUpdateException = exports.OakAttrNotNullException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakClockDriftException = exports.OakServerProxyException = exports.OakNetworkException = exports.OakImportDataParseException = exports.OakUniqueViolationException = exports.OakUserException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakNoRelationDefException = exports.OakDataException = exports.OakPartialSuccess = exports.OakMakeSureByMySelfException = exports.OakException = void 0;
4
4
  const relation_1 = require("../store/relation");
5
5
  const lodash_1 = require("../utils/lodash");
6
6
  class OakException extends Error {
@@ -173,10 +173,14 @@ exports.OakImportDataParseException = OakImportDataParseException;
173
173
  class OakNetworkException extends OakException {
174
174
  }
175
175
  exports.OakNetworkException = OakNetworkException;
176
- //
176
+ // 请求未到达应用服务程序
177
177
  class OakServerProxyException extends OakException {
178
178
  }
179
179
  exports.OakServerProxyException = OakServerProxyException;
180
+ // 时钟漂移过久(重放攻击)
181
+ class OakClockDriftException extends OakException {
182
+ }
183
+ exports.OakClockDriftException = OakClockDriftException;
180
184
  // 在系统更新数据时,以下三个异常应按规范依次抛出。
181
185
  /**
182
186
  * 数据不一致异常,系统认为现有的数据不允许相应的动作时抛此异常
@@ -294,7 +298,7 @@ class OakUnloggedInException extends OakUserException {
294
298
  exports.OakUnloggedInException = OakUnloggedInException;
295
299
  ;
296
300
  /**
297
- * 用户未登录抛的异常
301
+ * 行数据被锁抛的异常
298
302
  */
299
303
  class OakRowLockedException extends OakUserException {
300
304
  constructor(message) {
@@ -479,6 +483,10 @@ function makeException(data) {
479
483
  e = new OakNetworkException(data.message);
480
484
  break;
481
485
  }
486
+ case 'OakClockDriftException': {
487
+ e = new OakClockDriftException(data.message);
488
+ break;
489
+ }
482
490
  case 'OakServerProxyException': {
483
491
  e = new OakServerProxyException(data.message);
484
492
  break;
@@ -1,18 +1,21 @@
1
1
  import { RecurrenceRule, RecurrenceSpecDateRange, RecurrenceSpecObjLit } from 'node-schedule';
2
- import { EntityDict } from './Entity';
2
+ import { EntityDict, OperationResult } from './Entity';
3
3
  import { EntityDict as BaseEntityDict } from '../base-app-domain';
4
4
  import { AsyncContext } from '../store/AsyncRowStore';
5
5
  import { Watcher } from './Watcher';
6
- import { OperationResult } from '.';
7
- type FreeOperateFn<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<OperationResult<ED>>;
6
+ import { Namespace } from 'socket.io';
7
+ type FreeRoutineFn<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt, env: {
8
+ socket: Namespace;
9
+ }) => Promise<OperationResult<ED>>;
10
+ type FreeTimerFn<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<OperationResult<ED>>;
8
11
  export type FreeRoutine<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = {
9
12
  name: string;
10
- routine: FreeOperateFn<ED, Cxt>;
13
+ routine: FreeRoutineFn<ED, Cxt>;
11
14
  };
12
15
  export type FreeTimer<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = {
13
16
  name: string;
14
17
  cron: RecurrenceRule | RecurrenceSpecDateRange | RecurrenceSpecObjLit | Date | string | number;
15
- timer: FreeOperateFn<ED, Cxt>;
18
+ timer: FreeTimerFn<ED, Cxt>;
16
19
  singleton?: true;
17
20
  };
18
21
  export type Routine<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = FreeRoutine<ED, Cxt> | Watcher<ED, T, Cxt>;
@@ -17,6 +17,7 @@ export interface WBWatcher<ED extends EntityDict & BaseEntityDict, T extends key
17
17
  filter: ED[T]['Selection']['filter'] | (() => Promise<ED[T]['Selection']['filter']>);
18
18
  projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>);
19
19
  fn: (context: Cxt, data: Partial<ED[T]['Schema']>[]) => Promise<OperationResult<ED>>;
20
+ forUpdate?: true;
20
21
  singleton?: true;
21
22
  }
22
23
  export type Watcher<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = BBWatcher<ED, T> | WBWatcher<ED, T, Cxt>;
@@ -7,8 +7,9 @@ import { AccessConfiguration } from '../types/Configuration';
7
7
  export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, FrontCxt extends SyncContext<ED>> implements Connector<ED, FrontCxt> {
8
8
  static ASPECT_ROUTER: string;
9
9
  static BRIDGE_ROUTER: string;
10
- static SUBSCRIBE_ROUTER: string;
11
- static SUBSCRIBE_POINT_ROUTER: string;
10
+ static SUBSCRIBE_PATH: string;
11
+ static SOCKET_PATH: string;
12
+ static SOCKET_POINT_ROUTER: string;
12
13
  static ENDPOINT_ROUTER: string;
13
14
  private serverUrl;
14
15
  private serverAspectUrl;
@@ -17,11 +18,15 @@ export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, Fro
17
18
  private configuration;
18
19
  private makeException;
19
20
  constructor(configuration: AccessConfiguration, makeException: (exceptionData: any) => OakException<ED>);
21
+ getCorsHeader(): string[];
20
22
  protected makeHeadersAndBody(name: string, data: any, context?: FrontCxt): Promise<{
21
- headers: Record<string, string>;
23
+ headers: {
24
+ 'oak-cxt': string;
25
+ 'oak-aspect': string;
26
+ };
22
27
  body: FormData;
23
28
  } | {
24
- headers: HeadersInit;
29
+ headers: Record<string, string>;
25
30
  body: string;
26
31
  }>;
27
32
  protected parseAspectResult(response: Response): Promise<{
@@ -43,11 +48,12 @@ export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, Fro
43
48
  opRecords?: undefined;
44
49
  }>;
45
50
  getRouter(): string;
46
- getSubscribeRouter(): string;
47
- getSubscribePointRouter(): string;
48
- getSubscribePoint(): Promise<{
49
- url: any;
51
+ getSocketPath(): string;
52
+ getSocketPointRouter(): string;
53
+ getSocketPoint(): Promise<{
50
54
  path: any;
55
+ subscribeUrl: any;
56
+ socketUrl: any;
51
57
  }>;
52
58
  getEndpointRouter(): string;
53
59
  parseRequest(headers: IncomingHttpHeaders, body?: any, files?: any): {
@@ -8,8 +8,9 @@ const types_1 = require("../types");
8
8
  class SimpleConnector {
9
9
  static ASPECT_ROUTER = '/aspect';
10
10
  static BRIDGE_ROUTER = '/bridge';
11
- static SUBSCRIBE_ROUTER = process.env.OAK_SUBSCRIBE_ROUTER || '/subscribe';
12
- static SUBSCRIBE_POINT_ROUTER = '/subscribePoint';
11
+ static SUBSCRIBE_PATH = process.env.OAK_SUBSCRIBE_PATH || '/subscribe';
12
+ static SOCKET_PATH = process.env.OAK_SOCKET_PATH || '/socket';
13
+ static SOCKET_POINT_ROUTER = '/socketPoint';
13
14
  static ENDPOINT_ROUTER = '/endpoint';
14
15
  serverUrl;
15
16
  serverAspectUrl;
@@ -38,9 +39,15 @@ class SimpleConnector {
38
39
  this.serverAspectUrl = `${serverUrl}${routerPrefixes?.aspect || SimpleConnector.ASPECT_ROUTER}`;
39
40
  this.serverBridgeUrl = `${serverUrl}${routerPrefixes?.bridge || SimpleConnector.BRIDGE_ROUTER}`;
40
41
  this.serverSubscribePointUrl = `${serverUrl}${routerPrefixes?.getSubscribePoint ||
41
- SimpleConnector.SUBSCRIBE_POINT_ROUTER}`;
42
+ SimpleConnector.SOCKET_POINT_ROUTER}`;
42
43
  this.makeException = makeException;
43
44
  }
45
+ getCorsHeader() {
46
+ return [
47
+ 'oak-cxt',
48
+ 'oak-aspect'
49
+ ];
50
+ }
44
51
  async makeHeadersAndBody(name, data, context) {
45
52
  const cxtStr = context ? await context.toString() : '{}';
46
53
  const headers = {
@@ -48,6 +55,7 @@ class SimpleConnector {
48
55
  'oak-aspect': name,
49
56
  };
50
57
  if (process.env.OAK_PLATFORM !== 'wechatMp') {
58
+ // 小程序环境下没有FormData,跑到这里会挂
51
59
  if (data instanceof FormData) {
52
60
  return {
53
61
  headers,
@@ -115,13 +123,16 @@ class SimpleConnector {
115
123
  getRouter() {
116
124
  return this.configuration.routerPrefixes?.aspect || SimpleConnector.ASPECT_ROUTER;
117
125
  }
118
- getSubscribeRouter() {
119
- return this.configuration.routerPrefixes?.subscribe || SimpleConnector.SUBSCRIBE_ROUTER;
126
+ /* getSubscribePath(): string {
127
+ return this.configuration.socketPath?.subscribe || SimpleConnector.SUBSCRIBE_PATH;
128
+ } */
129
+ getSocketPath() {
130
+ return this.configuration.socketPath || SimpleConnector.SOCKET_PATH;
120
131
  }
121
- getSubscribePointRouter() {
122
- return this.configuration.routerPrefixes?.getSubscribePoint || SimpleConnector.SUBSCRIBE_POINT_ROUTER;
132
+ getSocketPointRouter() {
133
+ return this.configuration.routerPrefixes?.getSubscribePoint || SimpleConnector.SOCKET_POINT_ROUTER;
123
134
  }
124
- async getSubscribePoint() {
135
+ async getSocketPoint() {
125
136
  let response;
126
137
  try {
127
138
  response = await global.fetch(this.serverSubscribePointUrl);
@@ -137,10 +148,11 @@ class SimpleConnector {
137
148
  const responseType = response.headers.get('Content-Type') ||
138
149
  response.headers.get('content-type');
139
150
  if (responseType?.toLocaleLowerCase().match(/application\/json/i)) {
140
- const { url, path } = await response.json();
151
+ const { socketUrl, subscribeUrl, path } = await response.json();
141
152
  return {
142
- url,
143
153
  path,
154
+ subscribeUrl,
155
+ socketUrl,
144
156
  };
145
157
  }
146
158
  else {
package/lib/utils/row.js CHANGED
@@ -6,8 +6,8 @@ const lodash_1 = require("./lodash");
6
6
  const relation_1 = require("../store/relation");
7
7
  const assert_1 = tslib_1.__importDefault(require("assert"));
8
8
  function compareRow(schema, entity, row1, row2) {
9
- const attrs1 = Object.keys(row1).filter(ele => !ele.startsWith('$$'));
10
- const attrs2 = Object.keys(row2).filter(ele => !ele.startsWith('$$'));
9
+ const attrs1 = Object.keys(row1 || {}).filter(ele => !ele.startsWith('$$'));
10
+ const attrs2 = Object.keys(row2 || {}).filter(ele => !ele.startsWith('$$'));
11
11
  if ((0, lodash_1.difference)(attrs1, attrs2).length > 0) {
12
12
  return false;
13
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-domain",
3
- "version": "5.1.7",
3
+ "version": "5.1.9",
4
4
  "author": {
5
5
  "name": "XuChang"
6
6
  },
@@ -29,6 +29,7 @@
29
29
  "@types/node": "^20.6.1",
30
30
  "@types/node-schedule": "^2.1.0",
31
31
  "@types/react": "^17.0.2",
32
+ "@types/socket.io": "^3.0.2",
32
33
  "@types/uuid": "^8.3.0",
33
34
  "@types/wechat-miniprogram": "^3.4.1",
34
35
  "assert": "^2.0.0",
@@ -45,6 +46,7 @@
45
46
  "dependencies": {
46
47
  "dayjs": "^1.11.9",
47
48
  "node-schedule": "^2.1.1",
49
+ "socket.io": "^4.7.2",
48
50
  "uuid": "^9.0.0",
49
51
  "webidl-conversions": "^5.0.0"
50
52
  }
@@ -13,7 +13,7 @@ export interface Schema extends EntityShape {
13
13
  const entityDesc: EntityDesc<Schema> = {
14
14
  locales: {
15
15
  zh_CN: {
16
- name: '用户授权',
16
+ name: 'i18n',
17
17
  attr: {
18
18
  module: '模块',
19
19
  position: '文件位置',