oak-domain 5.1.31 → 5.1.33
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/lib/base-app-domain/Modi/Storage.js +1 -0
- package/lib/base-app-domain/Modi/_baseSchema.d.ts +1 -1
- package/lib/base-app-domain/Oper/Storage.js +1 -0
- package/lib/base-app-domain/Oper/_baseSchema.d.ts +1 -1
- package/lib/compiler/identifier.d.ts +9 -0
- package/lib/compiler/identifier.js +160 -0
- package/lib/compiler/schemalBuilder.d.ts +0 -1
- package/lib/compiler/schemalBuilder.js +144 -33
- package/lib/compiler/tscBuilder.d.ts +47 -0
- package/lib/compiler/tscBuilder.js +2823 -0
- package/lib/store/CascadeStore.d.ts +1 -1
- package/lib/store/CascadeStore.js +3 -1
- package/lib/store/IntrinsicCheckers.js +3 -1
- package/lib/store/RelationAuth.js +34 -8
- package/lib/store/TriggerExecutor.js +13 -0
- package/lib/store/checker.js +1 -0
- package/lib/store/diffSchema.d.ts +1 -0
- package/lib/store/diffSchema.js +2 -0
- package/lib/store/relation.d.ts +1 -1
- package/lib/types/Configuration.d.ts +1 -1
- package/lib/types/Connector.d.ts +17 -2
- package/lib/types/Demand.d.ts +1 -0
- package/lib/types/Exception.d.ts +20 -0
- package/lib/types/Exception.js +60 -1
- package/lib/types/Storage.d.ts +1 -0
- package/lib/types/Trigger.d.ts +647 -11
- package/lib/types/Trigger.js +34 -3
- package/lib/utils/SimpleConnector.d.ts +5 -5
- package/lib/utils/SimpleConnector.js +4 -2
- package/lib/utils/glob.d.ts +30 -0
- package/lib/utils/glob.js +286 -0
- package/lib/utils/money.d.ts +1 -1
- package/lib/utils/money.js +32 -21
- package/lib/utils/url/whatwg-url/lib/urlencoded.d.ts +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* 判断节点是否为 t 函数调用
|
|
4
|
+
* @param node ts.Node
|
|
5
|
+
* @param typeChecker ts.TypeChecker
|
|
6
|
+
* @returns boolean
|
|
7
|
+
* t: (key: string, params?: object | undefined) => string
|
|
8
|
+
*/
|
|
9
|
+
export declare const isTCall: (node: ts.Node, typeChecker: ts.TypeChecker, modules: string[]) => boolean;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTCall = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
6
|
+
// 缓存结构:WeakMap<Node, Map<modulesKey, boolean>>
|
|
7
|
+
const isTCallCache = new WeakMap();
|
|
8
|
+
/**
|
|
9
|
+
* 生成 modules 的缓存 key
|
|
10
|
+
*/
|
|
11
|
+
function getModulesCacheKey(modules) {
|
|
12
|
+
return modules.sort().join('|');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 判断节点是否为 t 函数调用
|
|
16
|
+
* @param node ts.Node
|
|
17
|
+
* @param typeChecker ts.TypeChecker
|
|
18
|
+
* @returns boolean
|
|
19
|
+
* t: (key: string, params?: object | undefined) => string
|
|
20
|
+
*/
|
|
21
|
+
const isTCall = (node, typeChecker, modules) => {
|
|
22
|
+
// 缓存查询
|
|
23
|
+
const modulesCacheKey = getModulesCacheKey(modules);
|
|
24
|
+
let nodeCache = isTCallCache.get(node);
|
|
25
|
+
if (nodeCache) {
|
|
26
|
+
const cachedResult = nodeCache.get(modulesCacheKey);
|
|
27
|
+
if (cachedResult !== undefined) {
|
|
28
|
+
return cachedResult;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!(ts.isCallExpression(node) && ts.isIdentifier(node.expression))) {
|
|
32
|
+
// 缓存 false 结果
|
|
33
|
+
if (!nodeCache) {
|
|
34
|
+
nodeCache = new Map();
|
|
35
|
+
isTCallCache.set(node, nodeCache);
|
|
36
|
+
}
|
|
37
|
+
nodeCache.set(modulesCacheKey, false);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const result = doIsTCallDirect(node, typeChecker, modules);
|
|
41
|
+
// 缓存结果
|
|
42
|
+
if (!nodeCache) {
|
|
43
|
+
nodeCache = new Map();
|
|
44
|
+
isTCallCache.set(node, nodeCache);
|
|
45
|
+
}
|
|
46
|
+
nodeCache.set(modulesCacheKey, result);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
exports.isTCall = isTCall;
|
|
50
|
+
const doIsTCallDirect = (node, typeChecker, modules) => {
|
|
51
|
+
if (!(ts.isCallExpression(node) && ts.isIdentifier(node.expression))) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const symbol = typeChecker.getSymbolAtLocation(node.expression);
|
|
55
|
+
if (!symbol) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const declarations = symbol.getDeclarations();
|
|
59
|
+
if (!declarations || declarations.length === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
for (const decl of declarations) {
|
|
63
|
+
const declType = typeChecker.getTypeAtLocation(decl);
|
|
64
|
+
const signatures = declType.getCallSignatures();
|
|
65
|
+
for (const sig of signatures) {
|
|
66
|
+
// 检查这个类型是否来自指定模块
|
|
67
|
+
if (!isTypeFromModules(declType, modules)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// 检查返回类型是否为 string
|
|
71
|
+
const returnType = typeChecker.getReturnTypeOfSignature(sig);
|
|
72
|
+
if ((returnType.flags & ts.TypeFlags.String) === 0) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const params = sig.getParameters();
|
|
76
|
+
if (params.length === 0) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// 检查第一个参数是否为 string
|
|
80
|
+
const firstParamType = typeChecker.getTypeOfSymbolAtLocation(params[0], decl);
|
|
81
|
+
if ((firstParamType.flags & ts.TypeFlags.String) === 0) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// 如果只有一个参数,符合 (key: string) => string
|
|
85
|
+
if (params.length === 1) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
// 检查第二个参数
|
|
89
|
+
if (params.length >= 2) {
|
|
90
|
+
const secondParam = params[1];
|
|
91
|
+
const secondParamType = typeChecker.getTypeOfSymbolAtLocation(secondParam, decl);
|
|
92
|
+
// 检查第二个参数是否为 object 或 object | undefined
|
|
93
|
+
if (isObjectOrObjectUnion(secondParamType)) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* 检查类型是否为 object 或 object | undefined
|
|
103
|
+
* @param type ts.Type
|
|
104
|
+
* @returns boolean
|
|
105
|
+
*/
|
|
106
|
+
function isObjectOrObjectUnion(type) {
|
|
107
|
+
// 如果是联合类型
|
|
108
|
+
if (type.isUnion()) {
|
|
109
|
+
// 检查联合类型中是否包含 object 类型
|
|
110
|
+
// 允许 object | undefined 的组合
|
|
111
|
+
let hasObject = false;
|
|
112
|
+
let hasOnlyObjectAndUndefined = true;
|
|
113
|
+
for (const t of type.types) {
|
|
114
|
+
if ((t.flags & ts.TypeFlags.Object) !== 0 || (t.flags & ts.TypeFlags.NonPrimitive) !== 0) {
|
|
115
|
+
hasObject = true;
|
|
116
|
+
}
|
|
117
|
+
else if ((t.flags & ts.TypeFlags.Undefined) === 0) {
|
|
118
|
+
// 如果既不是 object 也不是 undefined,则不符合
|
|
119
|
+
hasOnlyObjectAndUndefined = false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return hasObject && hasOnlyObjectAndUndefined;
|
|
123
|
+
}
|
|
124
|
+
// 如果是单一类型,检查是否为 object
|
|
125
|
+
return (type.flags & ts.TypeFlags.Object) !== 0 || (type.flags & ts.TypeFlags.NonPrimitive) !== 0;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 检查声明是否来自指定的模块
|
|
129
|
+
* @param decl ts.Declaration
|
|
130
|
+
* @param modules 模块名称列表
|
|
131
|
+
* @returns boolean
|
|
132
|
+
*/
|
|
133
|
+
function isFromModules(decl, modules) {
|
|
134
|
+
const sourceFile = decl.getSourceFile();
|
|
135
|
+
if (!sourceFile) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
const fileName = sourceFile.fileName;
|
|
139
|
+
// 检查文件路径是否包含指定的模块
|
|
140
|
+
return modules.some(moduleName => {
|
|
141
|
+
return fileName.includes(moduleName);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 检查类型是否来自指定模块
|
|
146
|
+
* @param type ts.Type
|
|
147
|
+
* @param modules 模块名称列表
|
|
148
|
+
* @returns boolean
|
|
149
|
+
*/
|
|
150
|
+
function isTypeFromModules(type, modules) {
|
|
151
|
+
const symbol = type.getSymbol();
|
|
152
|
+
if (!symbol) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const declarations = symbol.getDeclarations();
|
|
156
|
+
if (!declarations || declarations.length === 0) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return declarations.some(decl => isFromModules(decl, modules));
|
|
160
|
+
}
|
|
@@ -44,7 +44,6 @@ export declare function registerFixedDestinationPathMap(map: Record<string, stri
|
|
|
44
44
|
export declare function registerDeducedRelationMap(map: Record<string, string>): void;
|
|
45
45
|
export declare const getAnalizedSchema: () => typeof Schema;
|
|
46
46
|
export declare function analyzeEntities(inputDir: string, relativePath?: string): void;
|
|
47
|
-
export declare function buildSchemaBackup(outputDir: string): void;
|
|
48
47
|
export declare function getProjectionKeys(entity: string): string[];
|
|
49
48
|
export declare function buildSchema(outputDir: string): void;
|
|
50
49
|
export {};
|
|
@@ -9,7 +9,6 @@ exports.registerIgnoredRelationPathMap = registerIgnoredRelationPathMap;
|
|
|
9
9
|
exports.registerFixedDestinationPathMap = registerFixedDestinationPathMap;
|
|
10
10
|
exports.registerDeducedRelationMap = registerDeducedRelationMap;
|
|
11
11
|
exports.analyzeEntities = analyzeEntities;
|
|
12
|
-
exports.buildSchemaBackup = buildSchemaBackup;
|
|
13
12
|
exports.getProjectionKeys = getProjectionKeys;
|
|
14
13
|
exports.buildSchema = buildSchema;
|
|
15
14
|
const tslib_1 = require("tslib");
|
|
@@ -440,7 +439,7 @@ function dealWithActionTypeNode(moduleName, filename, actionTypeNode, program, s
|
|
|
440
439
|
}
|
|
441
440
|
function dealWithActionDefInitializer(moduleName, initializer, program) {
|
|
442
441
|
if (ts.isIdentifier(initializer) || ts.isCallExpression(initializer)) {
|
|
443
|
-
// 是从别处的引用,注入到
|
|
442
|
+
// 是从别处的引用,注入到importActionDefFrom
|
|
444
443
|
const checker = program.getTypeChecker();
|
|
445
444
|
const identifier = ts.isIdentifier(initializer) ? initializer : initializer.expression;
|
|
446
445
|
(0, assert_1.default)(ts.isIdentifier(identifier), "ActionDef的initializer不是一个Identifier");
|
|
@@ -449,12 +448,131 @@ function dealWithActionDefInitializer(moduleName, initializer, program) {
|
|
|
449
448
|
(0, assert_1.default)(ts.isImportSpecifier(declaration), "ActionDef的initializer不是一个ImportSpecifier");
|
|
450
449
|
const importDeclartion = declaration.parent.parent.parent;
|
|
451
450
|
addImportedFrom(moduleName, identifier.text, importDeclartion);
|
|
451
|
+
// 如果是函数调用(CallExpression),无法在编译时确定is,直接返回false
|
|
452
|
+
if (ts.isCallExpression(initializer)) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
// 如果是直接引用(Identifier),尝试分析外部引用的actionDef中的is
|
|
456
|
+
const aliasedSymbol = checker.getAliasedSymbol(symbol);
|
|
457
|
+
const aliasedDeclaration = aliasedSymbol?.getDeclarations()?.[0];
|
|
458
|
+
// 如果无法获取到声明,返回false(可能是第三方库)
|
|
459
|
+
if (!aliasedDeclaration || !ts.isVariableDeclaration(aliasedDeclaration)) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
const { initializer: aliDecInit } = aliasedDeclaration;
|
|
463
|
+
// 如果没有初始化器,可能是.d.ts声明文件,尝试从对应的.js文件读取
|
|
464
|
+
if (!aliDecInit) {
|
|
465
|
+
const sourceFile = aliasedDeclaration.getSourceFile();
|
|
466
|
+
const sourceFileName = sourceFile.fileName;
|
|
467
|
+
// 检查是否是.d.ts文件
|
|
468
|
+
if (sourceFileName.endsWith('.d.ts')) {
|
|
469
|
+
const jsFileName = sourceFileName.replace(/\.d\.ts$/, '.js');
|
|
470
|
+
// 尝试读取对应的.js文件
|
|
471
|
+
if ((0, fs_1.existsSync)(jsFileName)) {
|
|
472
|
+
try {
|
|
473
|
+
const jsContent = require('fs').readFileSync(jsFileName, 'utf-8');
|
|
474
|
+
// 获取原始的导出名称(处理 as 别名的情况)
|
|
475
|
+
// 如果有 propertyName,说明使用了 as,应该使用 propertyName
|
|
476
|
+
// 否则使用 name
|
|
477
|
+
const exportName = declaration.propertyName?.text || declaration.name.text;
|
|
478
|
+
// 尝试从JS文件中解析is属性
|
|
479
|
+
const hasIs = tryParseIsFromJsFile(jsContent, exportName);
|
|
480
|
+
return hasIs;
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
console.warn(`无法解析JS文件 ${jsFileName}:`, error);
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
// 如果是对象字面量,检查is属性
|
|
491
|
+
if (ts.isObjectLiteralExpression(aliDecInit)) {
|
|
492
|
+
const { properties } = aliDecInit;
|
|
493
|
+
const isProp = properties.find((ele) => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'is' && ts.isStringLiteral(ele.initializer));
|
|
494
|
+
return !!isProp;
|
|
495
|
+
}
|
|
496
|
+
// 其他情况返回false
|
|
497
|
+
return false;
|
|
452
498
|
}
|
|
453
499
|
else {
|
|
454
500
|
// 本地定义的actionDef,不用处理
|
|
455
501
|
(0, assert_1.default)(ts.isObjectLiteralExpression(initializer), moduleName);
|
|
502
|
+
if (ts.isObjectLiteralExpression(initializer)) {
|
|
503
|
+
const { properties } = initializer;
|
|
504
|
+
// 检查is属性是否存在,并且是string literal
|
|
505
|
+
const isProp = properties.find((ele) => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'is' && ts.isStringLiteral(ele.initializer));
|
|
506
|
+
return !!isProp;
|
|
507
|
+
}
|
|
508
|
+
return false;
|
|
456
509
|
}
|
|
457
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* 尝试从JavaScript文件内容中解析导出对象的is属性
|
|
513
|
+
* @param jsContent JavaScript文件内容
|
|
514
|
+
* @param exportName 导出的变量名
|
|
515
|
+
* @returns 是否包含is属性
|
|
516
|
+
*/
|
|
517
|
+
function tryParseIsFromJsFile(jsContent, exportName) {
|
|
518
|
+
// 创建一个临时的SourceFile来解析JavaScript
|
|
519
|
+
const jsSourceFile = ts.createSourceFile('temp.js', jsContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
520
|
+
let hasIs = false;
|
|
521
|
+
// 遍历AST查找导出
|
|
522
|
+
const visit = (node) => {
|
|
523
|
+
// 处理 exports.xxx = {...} 或 module.exports.xxx = {...}
|
|
524
|
+
if (ts.isExpressionStatement(node)) {
|
|
525
|
+
const expr = node.expression;
|
|
526
|
+
if (ts.isBinaryExpression(expr) && expr.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
527
|
+
const left = expr.left;
|
|
528
|
+
const right = expr.right;
|
|
529
|
+
// 检查是否是 exports.exportName 或 module.exports.exportName
|
|
530
|
+
if (ts.isPropertyAccessExpression(left)) {
|
|
531
|
+
const propertyName = left.name.text;
|
|
532
|
+
if (propertyName === exportName) {
|
|
533
|
+
// 检查右侧是否是对象字面量
|
|
534
|
+
if (ts.isObjectLiteralExpression(right)) {
|
|
535
|
+
hasIs = checkObjectHasIsProperty(right);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
// 处理 const xxx = {...}; exports.xxx = xxx;
|
|
543
|
+
if (ts.isVariableStatement(node)) {
|
|
544
|
+
const declarations = node.declarationList.declarations;
|
|
545
|
+
for (const decl of declarations) {
|
|
546
|
+
if (ts.isIdentifier(decl.name) && decl.name.text === exportName) {
|
|
547
|
+
if (decl.initializer && ts.isObjectLiteralExpression(decl.initializer)) {
|
|
548
|
+
hasIs = checkObjectHasIsProperty(decl.initializer);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
ts.forEachChild(node, visit);
|
|
555
|
+
};
|
|
556
|
+
visit(jsSourceFile);
|
|
557
|
+
return hasIs;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* 检查对象字面量是否包含is属性
|
|
561
|
+
*/
|
|
562
|
+
function checkObjectHasIsProperty(objLiteral) {
|
|
563
|
+
const { properties } = objLiteral;
|
|
564
|
+
const isProp = properties.find((ele) => {
|
|
565
|
+
if (ts.isPropertyAssignment(ele)) {
|
|
566
|
+
const name = ele.name;
|
|
567
|
+
if (ts.isIdentifier(name) && name.text === 'is') {
|
|
568
|
+
// 检查值是否是字符串字面量
|
|
569
|
+
return ts.isStringLiteral(ele.initializer);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return false;
|
|
573
|
+
});
|
|
574
|
+
return !!isProp;
|
|
575
|
+
}
|
|
458
576
|
/**
|
|
459
577
|
* entity的引用一定要以 import { Schema as XXX } from '..../XXX'这种形式
|
|
460
578
|
* @param declaration
|
|
@@ -713,7 +831,7 @@ function dealImportedFile(path, fileSpecifierPath, filename, program) {
|
|
|
713
831
|
// }
|
|
714
832
|
// assert(false, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
|
|
715
833
|
// }
|
|
716
|
-
function analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas,
|
|
834
|
+
function analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrDict, enumAttributes, importAttrFrom, relativePath) {
|
|
717
835
|
let hasEntityAttr = false;
|
|
718
836
|
let hasEntityIdAttr = false;
|
|
719
837
|
let toModi = false;
|
|
@@ -742,7 +860,7 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
|
|
|
742
860
|
extendsFrom.push(from);
|
|
743
861
|
const [sourceFile, pathName] = dealImportedFile(path, from, filename, program);
|
|
744
862
|
const relativeFilename = path_1.default.relative(process.cwd(), pathName);
|
|
745
|
-
const result = analyzeReferenceSchemaFile(moduleName, path_1.default.basename(relativeFilename), path_1.default.dirname(relativeFilename), sourceFile, program, referencedSchemas,
|
|
863
|
+
const result = analyzeReferenceSchemaFile(moduleName, path_1.default.basename(relativeFilename), path_1.default.dirname(relativeFilename), sourceFile, program, referencedSchemas, schemaAttrDict, enumAttributes, importAttrFrom, path_1.default.join(from, '..'));
|
|
746
864
|
return result;
|
|
747
865
|
}).filter(ele => !!ele);
|
|
748
866
|
// assert(['EntityShape'].includes((<ts.Identifier>heritageClauses![0].types![0].expression).text), moduleName);
|
|
@@ -754,7 +872,9 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
|
|
|
754
872
|
&& ts.isIdentifier(type.typeName)) {
|
|
755
873
|
if ((referencedSchemas.includes(type.typeName.text) || type.typeName.text === 'Schema')) {
|
|
756
874
|
addRelationship(moduleName, type.typeName.text, attrName, !!questionToken);
|
|
757
|
-
schemaAttrs.push(attrNode);
|
|
875
|
+
// schemaAttrs.push(attrNode);
|
|
876
|
+
(0, assert_1.default)(!schemaAttrDict[attrName], `「${filename}」的属性定义「${attrName}」发生了重复`);
|
|
877
|
+
schemaAttrDict[attrName] = attrNode;
|
|
758
878
|
}
|
|
759
879
|
else if (type.typeName.text === 'Array') {
|
|
760
880
|
// 这是一对多的反向指针的引用,需要特殊处理
|
|
@@ -782,7 +902,9 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
|
|
|
782
902
|
}
|
|
783
903
|
}
|
|
784
904
|
else {
|
|
785
|
-
schemaAttrs.push(attrNode);
|
|
905
|
+
// schemaAttrs.push(attrNode);
|
|
906
|
+
(0, assert_1.default)(!schemaAttrDict[attrName], `「${filename}」的属性定义「${attrName}」发生了重复`);
|
|
907
|
+
schemaAttrDict[attrName] = attrNode;
|
|
786
908
|
const enumStringValues = tryGetStringLiteralValues(moduleName, filename, `attr-${attrName}`, type, program);
|
|
787
909
|
if (enumStringValues.length > 0) {
|
|
788
910
|
enumAttributes[attrName] = enumStringValues;
|
|
@@ -813,13 +935,17 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
|
|
|
813
935
|
}
|
|
814
936
|
}
|
|
815
937
|
else {
|
|
816
|
-
schemaAttrs.push(attrNode);
|
|
938
|
+
// schemaAttrs.push(attrNode);
|
|
939
|
+
(0, assert_1.default)(!schemaAttrDict[attrName], `「${filename}」的属性定义「${attrName}」发生了重复`);
|
|
940
|
+
schemaAttrDict[attrName] = attrNode;
|
|
817
941
|
analyzeExternalAttrImport(type.elementType, program, importAttrFrom, relativePath);
|
|
818
942
|
// throw new Error(`对象${moduleName}中定义的属性${attrName}是不可识别的数组类别`);
|
|
819
943
|
}
|
|
820
944
|
}
|
|
821
945
|
else {
|
|
822
|
-
schemaAttrs.push(attrNode);
|
|
946
|
+
// schemaAttrs.push(attrNode);
|
|
947
|
+
(0, assert_1.default)(!schemaAttrDict[attrName], `「${filename}」的属性定义「${attrName}」发生了重复`);
|
|
948
|
+
schemaAttrDict[attrName] = attrNode;
|
|
823
949
|
if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) && ts.isStringLiteral(type.types[0].literal)) {
|
|
824
950
|
(0, assert_1.default)(ts.isIdentifier(name), `「${filename}」中的属性定义不是String类型`);
|
|
825
951
|
const { types } = type;
|
|
@@ -893,7 +1019,7 @@ function analyzeSchemaDefinition(node, moduleName, filename, path, program, refe
|
|
|
893
1019
|
extendsFrom,
|
|
894
1020
|
};
|
|
895
1021
|
}
|
|
896
|
-
function analyzeReferenceSchemaFile(moduleName, filename, path, sourceFile, program, referencedSchemas,
|
|
1022
|
+
function analyzeReferenceSchemaFile(moduleName, filename, path, sourceFile, program, referencedSchemas, schemaAttrDict, enumAttributes, importAttrFrom, relativePath) {
|
|
897
1023
|
let result;
|
|
898
1024
|
ts.forEachChild(sourceFile, (node) => {
|
|
899
1025
|
if (ts.isImportDeclaration(node)) {
|
|
@@ -902,7 +1028,7 @@ function analyzeReferenceSchemaFile(moduleName, filename, path, sourceFile, prog
|
|
|
902
1028
|
if (ts.isInterfaceDeclaration(node)) {
|
|
903
1029
|
// schema 定义
|
|
904
1030
|
if (node.name.text === 'Schema') {
|
|
905
|
-
result = analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas,
|
|
1031
|
+
result = analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrDict, enumAttributes, importAttrFrom, relativePath);
|
|
906
1032
|
}
|
|
907
1033
|
else if (!node.name.text.endsWith('Relation') && !node.name.text.endsWith('Action') && !node.name.text.endsWith('State')) {
|
|
908
1034
|
// 本地规定的一些形状定义,直接使用
|
|
@@ -933,7 +1059,8 @@ function analyzeEntity(filename, path, program, relativePath) {
|
|
|
933
1059
|
}
|
|
934
1060
|
checkNameLegal(filename, moduleName, true);
|
|
935
1061
|
const referencedSchemas = [];
|
|
936
|
-
const schemaAttrs = [];
|
|
1062
|
+
// const schemaAttrs: ts.TypeElement[] = [];
|
|
1063
|
+
const schemaAttrDict = {};
|
|
937
1064
|
let hasFulltextIndex = false;
|
|
938
1065
|
let indexes;
|
|
939
1066
|
let beforeSchema = true;
|
|
@@ -958,7 +1085,7 @@ function analyzeEntity(filename, path, program, relativePath) {
|
|
|
958
1085
|
// schema 定义
|
|
959
1086
|
if (node.name.text === 'Schema') {
|
|
960
1087
|
beforeSchema = false;
|
|
961
|
-
const result = analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas,
|
|
1088
|
+
const result = analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrDict, enumAttributes, importAttrFrom, relativePath);
|
|
962
1089
|
if (result.hasEntityAttr && result.hasEntityIdAttr) {
|
|
963
1090
|
(0, lodash_1.assign)(ReversePointerEntities, {
|
|
964
1091
|
[moduleName]: 1,
|
|
@@ -1112,11 +1239,12 @@ function analyzeEntity(filename, path, program, relativePath) {
|
|
|
1112
1239
|
const enumStateValues = tryGetStringLiteralValues(moduleName, filename, 'state', stateNode, program);
|
|
1113
1240
|
(0, assert_1.default)(enumStateValues.length > 0, `文件${filename}中的state${stateNode.typeName.text}定义不是字符串类型`);
|
|
1114
1241
|
pushStatementIntoActionAst(moduleName, node, sourceFile);
|
|
1115
|
-
dealWithActionDefInitializer(moduleName, declaration.initializer, program);
|
|
1242
|
+
const isDefined = dealWithActionDefInitializer(moduleName, declaration.initializer, program);
|
|
1116
1243
|
(0, assert_1.default)(ts.isIdentifier(declaration.name));
|
|
1117
1244
|
const adName = declaration.name.text.slice(0, declaration.name.text.length - 9);
|
|
1118
1245
|
const attr = adName.concat('State');
|
|
1119
|
-
|
|
1246
|
+
(0, assert_1.default)(!schemaAttrDict[attr], `文件${filename}中的${attr}有显式定义,与ActionDef需要生成的属性冲突`);
|
|
1247
|
+
schemaAttrDict[attr] = factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(attr), isDefined ? undefined : factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(attr));
|
|
1120
1248
|
enumAttributes[(0, string_1.firstLetterLowerCase)(attr)] = enumStateValues;
|
|
1121
1249
|
};
|
|
1122
1250
|
const dealWithIndexes = (declaration) => {
|
|
@@ -1175,7 +1303,7 @@ function analyzeEntity(filename, path, program, relativePath) {
|
|
|
1175
1303
|
});
|
|
1176
1304
|
const indexAttrName = nameProperty.initializer.text;
|
|
1177
1305
|
if (!Entity_1.initinctiveAttributes.includes(indexAttrName)) {
|
|
1178
|
-
const schemaNode =
|
|
1306
|
+
const schemaNode = Object.values(schemaAttrDict).find((ele3) => {
|
|
1179
1307
|
(0, assert_1.default)(ts.isPropertySignature(ele3));
|
|
1180
1308
|
return ele3.name.text === indexAttrName;
|
|
1181
1309
|
});
|
|
@@ -1390,6 +1518,7 @@ function analyzeEntity(filename, path, program, relativePath) {
|
|
|
1390
1518
|
if (hasActionDef && actionType !== 'crud') {
|
|
1391
1519
|
throw new Error(`${filename}中有Action定义,但却定义了actionType不是crud`);
|
|
1392
1520
|
}
|
|
1521
|
+
const schemaAttrs = Object.values(schemaAttrDict);
|
|
1393
1522
|
(0, assert_1.default)(schemaAttrs.length > 0, `对象${moduleName}没有任何属性定义`);
|
|
1394
1523
|
const schema = {
|
|
1395
1524
|
schemaAttrs,
|
|
@@ -4933,24 +5062,6 @@ function analyzeEntities(inputDir, relativePath) {
|
|
|
4933
5062
|
analyzeInModi();
|
|
4934
5063
|
uniqRelationships();
|
|
4935
5064
|
}
|
|
4936
|
-
function buildSchemaBackup(outputDir) {
|
|
4937
|
-
addReverseRelationship();
|
|
4938
|
-
// setRelationEntities();
|
|
4939
|
-
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
4940
|
-
resetOutputDir(outputDir);
|
|
4941
|
-
outputSchema(outputDir, printer);
|
|
4942
|
-
outputLocale(outputDir, printer);
|
|
4943
|
-
outputSubQuery(outputDir, printer);
|
|
4944
|
-
outputAction(outputDir, printer);
|
|
4945
|
-
outputEntityDict(outputDir, printer);
|
|
4946
|
-
outputStorage(outputDir, printer);
|
|
4947
|
-
outputRelation2(outputDir, printer);
|
|
4948
|
-
outputStyleDict(outputDir, printer);
|
|
4949
|
-
outputIndexTs(outputDir);
|
|
4950
|
-
if (!process.env.COMPLING_AS_LIB) {
|
|
4951
|
-
outputPackageJson(outputDir);
|
|
4952
|
-
}
|
|
4953
|
-
}
|
|
4954
5065
|
function _getAggrKey(entity, foreignKey) {
|
|
4955
5066
|
const aggrKey = `${entity}$${foreignKey}`;
|
|
4956
5067
|
if (process.env.COMPLING_AS_LIB) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
export declare const OAK_IGNORE_TAGS: string[];
|
|
3
|
+
interface OakBuildChecksConfig {
|
|
4
|
+
context?: {
|
|
5
|
+
checkAsyncContext?: boolean;
|
|
6
|
+
targetModules?: string[];
|
|
7
|
+
filePatterns?: string[];
|
|
8
|
+
};
|
|
9
|
+
locale?: {
|
|
10
|
+
checkI18nKeys?: boolean;
|
|
11
|
+
tFunctionModules?: string[];
|
|
12
|
+
checkTemplateLiterals?: boolean;
|
|
13
|
+
warnStringKeys?: boolean;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
interface CustomDiagnostic {
|
|
17
|
+
file: ts.SourceFile;
|
|
18
|
+
start: number;
|
|
19
|
+
length: number;
|
|
20
|
+
messageText: string;
|
|
21
|
+
category: ts.DiagnosticCategory;
|
|
22
|
+
code: number;
|
|
23
|
+
callChain?: string[];
|
|
24
|
+
contextCallNode?: ts.CallExpression;
|
|
25
|
+
reason?: string;
|
|
26
|
+
reasonDetails?: string[];
|
|
27
|
+
relatedInfo?: Array<{
|
|
28
|
+
file: ts.SourceFile;
|
|
29
|
+
start: number;
|
|
30
|
+
length: number;
|
|
31
|
+
message: string;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export type CompileOptions = {
|
|
35
|
+
project?: string;
|
|
36
|
+
noEmit?: boolean;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* 执行自定义检查
|
|
40
|
+
* @param program ts.Program
|
|
41
|
+
* @param typeChecker ts.TypeChecker
|
|
42
|
+
* @param customConfig 自定义配置
|
|
43
|
+
* @returns CustomDiagnostic[] 自定义诊断列表
|
|
44
|
+
*/
|
|
45
|
+
export declare function performCustomChecks(pwd: string, program: ts.Program, typeChecker: ts.TypeChecker, customConfig: OakBuildChecksConfig): CustomDiagnostic[];
|
|
46
|
+
export declare const build: (pwd: string, args: any[]) => void;
|
|
47
|
+
export {};
|