@lcap/nasl 3.7.2-alpha.1 → 3.7.2-beta.1
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/out/common/BaseNode.js.map +1 -1
- package/out/concepts/ViewElement__.js +8 -8
- package/out/concepts/ViewElement__.js.map +1 -1
- package/out/generator/genBundleFiles.js +2 -1
- package/out/generator/genBundleFiles.js.map +1 -1
- package/out/generator/release-body/body.js +2 -1
- package/out/generator/release-body/body.js.map +1 -1
- package/out/natural/genNaturalTS.js +1 -0
- package/out/natural/genNaturalTS.js.map +1 -1
- package/out/natural/transformTS2UI.js +4 -2
- package/out/natural/transformTS2UI.js.map +1 -1
- package/out/server/getLogics.js +1 -1
- package/out/server/getLogics.js.map +1 -1
- package/out/server/translator.js +7 -0
- package/out/server/translator.js.map +1 -1
- package/out/service/storage/init.d.ts +1 -1
- package/out/service/storage/init.js +71 -22
- package/out/service/storage/init.js.map +1 -1
- package/out/utils/env.d.ts +2 -0
- package/out/utils/env.js +5 -4
- package/out/utils/env.js.map +1 -1
- package/out/utils/index.d.ts +1 -0
- package/out/utils/index.js +14 -1
- package/out/utils/index.js.map +1 -1
- package/out/utils/language-cache/constant.d.ts +12 -0
- package/out/utils/language-cache/constant.js +17 -0
- package/out/utils/language-cache/constant.js.map +1 -0
- package/out/utils/language-cache/index.d.ts +2 -0
- package/out/utils/language-cache/index.js +19 -0
- package/out/utils/language-cache/index.js.map +1 -0
- package/out/utils/language-cache/nasl.d.ts +10 -0
- package/out/utils/language-cache/nasl.js +94 -0
- package/out/utils/language-cache/nasl.js.map +1 -0
- package/out/utils/language-cache/types.d.ts +40 -0
- package/out/utils/language-cache/types.js +4 -0
- package/out/utils/language-cache/types.js.map +1 -0
- package/out/utils/time-slicing/controller.js.map +1 -1
- package/out/utils/types.d.ts +17 -0
- package/package.json +2 -1
- package/src/common/BaseNode.ts +0 -1
- package/src/concepts/ViewElement__.ts +6 -6
- package/src/generator/genBundleFiles.ts +2 -1
- package/src/generator/release-body/body.ts +2 -1
- package/src/natural/genNaturalTS.ts +5 -6
- package/src/natural/transformTS2UI.ts +5 -3
- package/src/server/getLogics.ts +1 -1
- package/src/server/translator.ts +7 -0
- package/src/service/storage/init.ts +96 -45
- package/src/utils/env.ts +4 -5
- package/src/utils/index.ts +2 -0
- package/src/utils/language-cache/constant.ts +14 -0
- package/src/utils/language-cache/index.ts +2 -0
- package/src/utils/language-cache/nasl.ts +77 -0
- package/src/utils/language-cache/types.ts +44 -0
- package/src/utils/time-slicing/controller.ts +0 -1
- package/src/utils/types.ts +20 -0
- package/ts-worker/bundle.js +1 -1
- package/ts-worker/src/index.js +0 -1
- package/out/utils/delay/index.d.ts +0 -0
- package/out/utils/delay/index.js +0 -1
- package/out/utils/delay/index.js.map +0 -1
- package/src/utils/delay/index.ts +0 -0
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.7.2-
|
|
4
|
+
"version": "3.7.2-beta.1",
|
|
5
5
|
"author": "Forrest <rainforest92@126.com>",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"clear": "rimraf ./out",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"decimal.js": "10.4.3",
|
|
44
44
|
"faker": "5.4.0",
|
|
45
45
|
"fs-extra": "10.1.0",
|
|
46
|
+
"idb": "8.0.0",
|
|
46
47
|
"json5": "2.2.3",
|
|
47
48
|
"lodash": "4.17.21",
|
|
48
49
|
"postcss": "8.4.14",
|
package/src/common/BaseNode.ts
CHANGED
|
@@ -3283,17 +3283,17 @@ export class ViewElement extends BaseNode {
|
|
|
3283
3283
|
if (!styleObj['--constraint-modified'] && !ops.isUpdateConstraintRule) {
|
|
3284
3284
|
if (Math.abs(staticLeft - staticRight) < threshold) {
|
|
3285
3285
|
constraintX = 'center';
|
|
3286
|
-
} else if (staticLeft
|
|
3287
|
-
constraintX = 'left';
|
|
3288
|
-
} else if (staticLeft > staticRight) {
|
|
3286
|
+
} else if (staticLeft > parentWidth/2) {
|
|
3289
3287
|
constraintX = 'right';
|
|
3288
|
+
} else if (staticRight > parentWidth/2) {
|
|
3289
|
+
constraintX = 'left';
|
|
3290
3290
|
}
|
|
3291
3291
|
if (Math.abs(staticTop - staticBottom) < threshold) {
|
|
3292
3292
|
constraintY = 'center';
|
|
3293
|
-
} else if (staticTop
|
|
3294
|
-
constraintY = 'top';
|
|
3295
|
-
} else if (staticTop > staticBottom) {
|
|
3293
|
+
} else if (staticTop > parentHeight/2) {
|
|
3296
3294
|
constraintY = 'bottom';
|
|
3295
|
+
} else if (staticBottom > parentHeight/2) {
|
|
3296
|
+
constraintY = 'top';
|
|
3297
3297
|
}
|
|
3298
3298
|
}
|
|
3299
3299
|
|
|
@@ -800,7 +800,8 @@ export function genBundleFiles(app: App, frontend: Frontend, config: Config) {
|
|
|
800
800
|
const asset = assetsMap.get(url);
|
|
801
801
|
if (asset) {
|
|
802
802
|
const basePath = frontend?.basePath;
|
|
803
|
-
const
|
|
803
|
+
const assetName = encodeURIComponent(asset.name);
|
|
804
|
+
const assetDir = basePath ? `${basePath}/assets/${assetName}` : `/assets/${assetName}`;
|
|
804
805
|
let path = assetDir;
|
|
805
806
|
const sysPrefixPath = frontend?.app?.sysPrefixPath;
|
|
806
807
|
if (sysPrefixPath) {
|
|
@@ -79,7 +79,8 @@ async function getNaslAnnotatedJSON(app: App, opt: InternalReleaseData) {
|
|
|
79
79
|
node[key] = url.replace(regex, (url) => {
|
|
80
80
|
const asset = assetsMap.get(url);
|
|
81
81
|
if (asset) {
|
|
82
|
-
const
|
|
82
|
+
const assetName = encodeURIComponent(asset.name);
|
|
83
|
+
const path = `/assets/${assetName}`;
|
|
83
84
|
globalConfig.assets.push({
|
|
84
85
|
path,
|
|
85
86
|
isDir: false,
|
|
@@ -22,12 +22,11 @@ import { createCompilerState } from '../translator';
|
|
|
22
22
|
export function genNaturalTS(app: App, currentNode?: BaseNode, focusedNodePath?: string) {
|
|
23
23
|
if (currentNode?.concept === 'Logic') {
|
|
24
24
|
const logic = currentNode as Logic;
|
|
25
|
-
const code = logic?.toNaturalTS(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
);
|
|
25
|
+
const code = logic?.toNaturalTS(createCompilerState(undefined, {
|
|
26
|
+
focusedNodePath,
|
|
27
|
+
needNamespace: true,
|
|
28
|
+
autoPrefixName: true,
|
|
29
|
+
}));
|
|
31
30
|
return code;
|
|
32
31
|
}
|
|
33
32
|
return getCurrentNodeContextForUI(currentNode).code;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable global-require */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
3
|
-
import { kebabCase } from 'lodash';
|
|
3
|
+
import { kebabCase, cloneDeep } from 'lodash';
|
|
4
4
|
import * as babel from '@babel/core';
|
|
5
5
|
import * as babelTypes from '@babel/types';
|
|
6
6
|
import generate from '@babel/generator';
|
|
@@ -1112,11 +1112,12 @@ function transformNode2ViewConstruct(node: babelTypes.Node): naslTypes.ViewEleme
|
|
|
1112
1112
|
} else if (properties?.[2].value.value === 'BindAttribute') {
|
|
1113
1113
|
newNode = transformNode2Attribute({ key: element.left, value: element.right });
|
|
1114
1114
|
}
|
|
1115
|
+
const newNodeBackup = cloneDeep(newNode);
|
|
1115
1116
|
(newNode as any).aiParams = {
|
|
1116
1117
|
action: properties?.[0].value.value,
|
|
1117
1118
|
selectedNodeName: properties?.[1].value.value,
|
|
1118
1119
|
concept: properties?.[2].value.value,
|
|
1119
|
-
object:
|
|
1120
|
+
object: newNodeBackup
|
|
1120
1121
|
};
|
|
1121
1122
|
newViewElement.push(newNode);
|
|
1122
1123
|
});
|
|
@@ -1152,7 +1153,8 @@ function transformNode2View(node: babelTypes.FunctionDeclaration, root?: babelTy
|
|
|
1152
1153
|
if (item.type === 'ReturnStatement' && item?.argument?.type === 'CallExpression') {
|
|
1153
1154
|
const action = (item.argument as any)?.callee?.name;
|
|
1154
1155
|
const selectedNodeName = (item.argument as any).arguments?.[0]?.property?.name;
|
|
1155
|
-
|
|
1156
|
+
const newNodeBackup = cloneDeep(viewItem);
|
|
1157
|
+
(viewItem as any).aiParams = { selectedNodeName, action, concept: 'ViewElement', object: newNodeBackup};
|
|
1156
1158
|
}
|
|
1157
1159
|
if (item.type === 'ReturnStatement' && item?.argument?.type === 'ArrayExpression') {
|
|
1158
1160
|
viewItem?.forEach((element: any) => {
|
package/src/server/getLogics.ts
CHANGED
|
@@ -500,7 +500,7 @@ export function getLogicsSync(node: CallLogic | BindEvent | Identifier | Logic,
|
|
|
500
500
|
],
|
|
501
501
|
expanded: false,
|
|
502
502
|
});
|
|
503
|
-
if (!app.processes
|
|
503
|
+
if (!(app.processes?.length) && !(app.processV2s?.length)) systemTree.children.shift();
|
|
504
504
|
|
|
505
505
|
systemTree.expanded = false;
|
|
506
506
|
systemTree.children.forEach((child) => (child.expanded = false));
|
package/src/server/translator.ts
CHANGED
|
@@ -914,6 +914,13 @@ export function naslNodeTranslateMessage(minRange: MinRange, tsErrorDetail: Diag
|
|
|
914
914
|
* @param tsErrorDetail
|
|
915
915
|
*/
|
|
916
916
|
function getConnectorErrorDetail(node: BaseNode, tsErrorDetail: Diagnostic) {
|
|
917
|
+
// 如果message 为纯英文,直接返回
|
|
918
|
+
if (/^[A-Za-z\s]+[.,!?;:]$/.test(tsErrorDetail.message)) {
|
|
919
|
+
return {
|
|
920
|
+
node,
|
|
921
|
+
...tsErrorDetail,
|
|
922
|
+
};
|
|
923
|
+
}
|
|
917
924
|
const connector = node.getAncestor('Connector') as Connector;
|
|
918
925
|
let targetNode = node;
|
|
919
926
|
let msgPrefix = '';
|
|
@@ -4,16 +4,16 @@ import { addBreakpointNodesFromApp } from '../../breakpoint';
|
|
|
4
4
|
import { getConceptConstructor } from '../../decorators';
|
|
5
5
|
import { config } from '../../config';
|
|
6
6
|
import storageService from './service';
|
|
7
|
+
import { LsCache, BreakpointStatus, FullResponse, isDebugMode, BatchInstructResult } from '../../utils';
|
|
7
8
|
import { v4 as uuidv4 } from 'uuid';
|
|
8
9
|
import stepRecorder from '../../manager/stepRecorder';
|
|
9
10
|
import * as jsoner from './jsoner';
|
|
10
11
|
/// #if !process.env.NODE_ENV || process.env.BUILD_TARGET === 'node'
|
|
11
12
|
import * as fs from 'fs-extra';
|
|
12
13
|
import type { NaslServer } from 'src/server/naslServer';
|
|
14
|
+
import { NaslCacheData, NaslData } from 'src/utils/language-cache';
|
|
13
15
|
/// #endif
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
17
|
export const batchQuery = storageService.batchQuery;
|
|
18
18
|
export const batchAction = storageService.batchAction;
|
|
19
19
|
export const batchInstruct = storageService.batchInstruct;
|
|
@@ -58,12 +58,12 @@ export function doOperationRecord(operation: Operation) {
|
|
|
58
58
|
transaction.oncomplete = () => {
|
|
59
59
|
db.close();
|
|
60
60
|
};
|
|
61
|
-
} catch(err) {
|
|
61
|
+
} catch (err) {
|
|
62
62
|
console.log(err);
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
request.onerror = function(event) {
|
|
66
|
+
request.onerror = function (event) {
|
|
67
67
|
console.log('Failed to open database');
|
|
68
68
|
};
|
|
69
69
|
}
|
|
@@ -228,7 +228,7 @@ export async function operationRecordPlayback(app: any, operationRecordAction: '
|
|
|
228
228
|
const pathArr = path?.split('.') || [];
|
|
229
229
|
const lastPathItem = pathArr?.pop();
|
|
230
230
|
if (lastPathItem) {
|
|
231
|
-
|
|
231
|
+
pathArr.push(lastPathItem.replace(/(name=)[^\]]+/, `$1${object?.name}`));
|
|
232
232
|
}
|
|
233
233
|
newPath = pathArr.join('.');
|
|
234
234
|
}
|
|
@@ -254,7 +254,7 @@ export async function operationRecordPlayback(app: any, operationRecordAction: '
|
|
|
254
254
|
case 'update':
|
|
255
255
|
for (const key in oldObject) {
|
|
256
256
|
if (node) {
|
|
257
|
-
|
|
257
|
+
(node as any)[key] = oldObject[key] ?? null;
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
break;
|
|
@@ -427,7 +427,7 @@ async function doAction(app: any, actionItem: any) {
|
|
|
427
427
|
let hasBackEnd = false;
|
|
428
428
|
const actionList: any[] = [];
|
|
429
429
|
const allRiskList: any[] = [];
|
|
430
|
-
const { list, actionMsg, action, extra} = actionItem || {};
|
|
430
|
+
const { list, actionMsg, action, extra } = actionItem || {};
|
|
431
431
|
handleAIPoint(app, actionItem);
|
|
432
432
|
const itemloop = (_i: LogicItem, app: any, diffArr: string[]) => {
|
|
433
433
|
const _l = getStatement(_i, app, diffArr);
|
|
@@ -543,9 +543,9 @@ async function doAction(app: any, actionItem: any) {
|
|
|
543
543
|
const isDelete = event?.originEvent?.action === 'delete';
|
|
544
544
|
const isAuthView = (emitTarget as View).auth && event?.originEvent?.object?.name;
|
|
545
545
|
const isUpdateAuth = event?.originEvent?.action === 'update' && "auth" in (event?.originEvent?.object || {});
|
|
546
|
-
const isUpdateAuthDes =
|
|
546
|
+
const isUpdateAuthDes = event?.originEvent?.action === 'update' && "authDescription" in (event?.originEvent?.object || {});
|
|
547
547
|
const isUpdateBindRoles = event?.originEvent?.action === 'update' && event?.originEvent?.object && event?.originEvent?.object?.bindRoles;
|
|
548
|
-
if (isDelete || isUpdateAuth || isUpdateBindRoles || isAuthView||isUpdateAuthDes) {
|
|
548
|
+
if (isDelete || isUpdateAuth || isUpdateBindRoles || isAuthView || isUpdateAuthDes) {
|
|
549
549
|
hasBackEnd = true;
|
|
550
550
|
// const app = emitTarget.app;
|
|
551
551
|
// const diffArr: string[] = [];
|
|
@@ -566,7 +566,7 @@ async function doAction(app: any, actionItem: any) {
|
|
|
566
566
|
hasFrontEnd = true;
|
|
567
567
|
}
|
|
568
568
|
if (emitTarget.concept === 'ViewElement') {
|
|
569
|
-
if(event?.originEvent?.action === 'update' || event?.originEvent?.action === 'delete'){
|
|
569
|
+
if (event?.originEvent?.action === 'update' || event?.originEvent?.action === 'delete') {
|
|
570
570
|
if ('authDescription' in (event?.originEvent?.object ?? {})) {
|
|
571
571
|
hasBackEnd = true;
|
|
572
572
|
}
|
|
@@ -597,7 +597,7 @@ async function doAction(app: any, actionItem: any) {
|
|
|
597
597
|
}
|
|
598
598
|
if (emitTarget.concept === 'BindAttribute' && emitTarget.name === 'url') {
|
|
599
599
|
const needUpdateBackEnd =
|
|
600
|
-
|
|
600
|
+
(emitTarget as BindAttribute)?.value?.endsWith('/import') || (emitTarget as BindAttribute)?.value?.includes('/upload/')
|
|
601
601
|
if (!(emitTarget as BindAttribute).view.parentAuth && needUpdateBackEnd) {
|
|
602
602
|
hasBackEnd = true
|
|
603
603
|
}
|
|
@@ -888,7 +888,7 @@ function ensureSafe(instructList: any[]) {
|
|
|
888
888
|
instruct?.actions?.forEach((actionItem: any) => {
|
|
889
889
|
const { path, action, object } = actionItem || {};
|
|
890
890
|
if (path === 'app') {
|
|
891
|
-
switch(action) {
|
|
891
|
+
switch (action) {
|
|
892
892
|
case 'create':
|
|
893
893
|
riskList.push('重复创建App');
|
|
894
894
|
break;
|
|
@@ -918,7 +918,8 @@ async function _saveNasl(options: TaskOption) {
|
|
|
918
918
|
} else if (hasBackEnd) {
|
|
919
919
|
ChangedNASLType = 'backend';
|
|
920
920
|
}
|
|
921
|
-
|
|
921
|
+
|
|
922
|
+
let res: BatchInstructResult;
|
|
922
923
|
let err: any;
|
|
923
924
|
|
|
924
925
|
if (config.storage.protocol === 'http') {
|
|
@@ -996,6 +997,13 @@ async function _saveNasl(options: TaskOption) {
|
|
|
996
997
|
});
|
|
997
998
|
}
|
|
998
999
|
app.emit?.('saved', err);
|
|
1000
|
+
|
|
1001
|
+
// 更新缓存
|
|
1002
|
+
await LsCache.updateNaslCache(app.id, {
|
|
1003
|
+
...res,
|
|
1004
|
+
getData: () => cloneDeep(app.toJSON()),
|
|
1005
|
+
});
|
|
1006
|
+
|
|
999
1007
|
return err;
|
|
1000
1008
|
}
|
|
1001
1009
|
|
|
@@ -1138,61 +1146,104 @@ export function handleApp(app: ProxyApp) {
|
|
|
1138
1146
|
});
|
|
1139
1147
|
}
|
|
1140
1148
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1149
|
+
async function getBatchAdditionalData(appId: string) {
|
|
1150
|
+
const { data: { result: [globalChangedTime] }, headers }: FullResponse<number> = await storageService.batchQuery({
|
|
1151
|
+
body: [
|
|
1152
|
+
{
|
|
1153
|
+
path: 'app.globalChangedTime',
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
1156
|
+
headers: {
|
|
1157
|
+
appId,
|
|
1158
|
+
checkTabOpenTime: 'true',
|
|
1159
|
+
},
|
|
1160
|
+
config: {
|
|
1161
|
+
shortResponse: false
|
|
1162
|
+
},
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1165
|
+
return {
|
|
1166
|
+
globalChangedTime,
|
|
1167
|
+
tabTimestamp: headers['tabtimestamp'],
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
async function getNaslFromServer(appId: string, globalChangedTime: number | null) {
|
|
1172
|
+
const [naslData] = await storageService.batchQuery({
|
|
1173
|
+
body: [
|
|
1174
|
+
{
|
|
1175
|
+
path: 'app',
|
|
1176
|
+
},
|
|
1177
|
+
],
|
|
1178
|
+
headers: {
|
|
1179
|
+
appId,
|
|
1180
|
+
},
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
// 后端没有此值时,表示为存量应用,不可缓存
|
|
1184
|
+
if (!globalChangedTime) {
|
|
1185
|
+
return naslData;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
await LsCache.updateNaslCache(appId, {
|
|
1189
|
+
getData: () => naslData,
|
|
1190
|
+
// 初次缓存时此值无用,故赋值为 0
|
|
1191
|
+
preGlobalChangedTime: 0,
|
|
1192
|
+
globalChangedTime: globalChangedTime,
|
|
1193
|
+
});
|
|
1194
|
+
|
|
1195
|
+
return naslData as NaslData;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
async function getNaslFromCache(appId: string) {
|
|
1199
|
+
return LsCache.getNaslCacheWithoutCheck(appId).then((data) => data.data);
|
|
1200
|
+
}
|
|
1147
1201
|
|
|
1148
1202
|
/**
|
|
1149
1203
|
* 加载 app
|
|
1150
1204
|
* @param appId 如果是从文件读,就不需要传
|
|
1151
1205
|
* @returns app 对象
|
|
1152
1206
|
*/
|
|
1153
|
-
export async function loadApp(appId
|
|
1207
|
+
export async function loadApp(appId: string) {
|
|
1154
1208
|
try {
|
|
1155
1209
|
// 删除失效数据
|
|
1156
1210
|
deleteExpiredRecords();
|
|
1157
|
-
} catch(err) { }
|
|
1211
|
+
} catch (err) { }
|
|
1158
1212
|
let app: App;
|
|
1159
1213
|
if (config.storage.protocol === 'http') {
|
|
1160
1214
|
console.time('batchQuery');
|
|
1215
|
+
const additionalData = await getBatchAdditionalData(appId);
|
|
1216
|
+
const useCache = await LsCache.canUseNaslCache(appId, additionalData.globalChangedTime);
|
|
1161
1217
|
const promises = [
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
path: 'app'
|
|
1166
|
-
// excludes: ['views'],
|
|
1167
|
-
}
|
|
1168
|
-
],
|
|
1169
|
-
headers: {
|
|
1170
|
-
appId,
|
|
1171
|
-
checkTabOpenTime: 'true'
|
|
1172
|
-
// 其他封装在 storageService 里了
|
|
1173
|
-
},
|
|
1174
|
-
config: {
|
|
1175
|
-
shortResponse: false
|
|
1176
|
-
}
|
|
1177
|
-
}),
|
|
1218
|
+
useCache
|
|
1219
|
+
? getNaslFromCache(appId)
|
|
1220
|
+
: getNaslFromServer(appId, additionalData.globalChangedTime),
|
|
1178
1221
|
storageService.breakpoint({
|
|
1179
1222
|
body: { appId }
|
|
1180
|
-
})
|
|
1181
|
-
|
|
1223
|
+
}),
|
|
1224
|
+
useCache ? Promise.resolve() : LsCache.clearCache(appId),
|
|
1225
|
+
] as [Promise<LsCache.NaslCacheData>, Promise<BreakpointStatus[]>, Promise<void>];
|
|
1226
|
+
|
|
1227
|
+
if (isDebugMode) {
|
|
1228
|
+
if (useCache) {
|
|
1229
|
+
console.log('命中 Nasl 前端缓存');
|
|
1230
|
+
}
|
|
1231
|
+
else {
|
|
1232
|
+
console.log('未命中 Nasl 前端缓存');
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1182
1235
|
|
|
1183
1236
|
const [batchQueryRes, breakpointRes] = await Promise.all(promises)
|
|
1184
1237
|
|
|
1185
1238
|
// 请求
|
|
1186
1239
|
console.timeEnd('batchQuery');
|
|
1187
|
-
|
|
1188
|
-
tabTimestamp = batchQueryRes?.headers?.tabtimestamp;
|
|
1189
|
-
const data = batchQueryRes?.data?.result;
|
|
1240
|
+
tabTimestamp = additionalData.tabTimestamp;
|
|
1190
1241
|
|
|
1191
1242
|
console.time('new App');
|
|
1192
|
-
app = new App(Object.assign(
|
|
1243
|
+
app = new App(Object.assign(batchQueryRes, { id: appId }));
|
|
1193
1244
|
|
|
1194
|
-
breakpointRes?.forEach?.((item
|
|
1195
|
-
const { path, breakpointStatus } = item
|
|
1245
|
+
breakpointRes?.forEach?.((item) => {
|
|
1246
|
+
const { path, breakpointStatus } = item ?? {};
|
|
1196
1247
|
|
|
1197
1248
|
if (breakpointStatus) {
|
|
1198
1249
|
const node = app.findNodeByPath(path)
|
package/src/utils/env.ts
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
export const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
3
3
|
/** Node 环境 */
|
|
4
4
|
export const isNode = process.env.BUILD_TARGET === 'node' || !globalThis.window;
|
|
5
|
+
/** 本地模式 */
|
|
6
|
+
export const isLocalMode = isBrowser && location.hostname.includes('localhost');
|
|
5
7
|
/** 调试模式 */
|
|
6
|
-
export const isDebugMode = isBrowser && /[?&]debug=true/.test(
|
|
8
|
+
export const isDebugMode = isBrowser && (/[?&]debug=true/.test(location.search) || isLocalMode);
|
|
7
9
|
/** 是否是浏览器测试环境 */
|
|
8
|
-
export const isTestBrowser = isBrowser && (
|
|
9
|
-
/codewave-(test|dev)\.163yun\.com$/.test(location.hostname) ||
|
|
10
|
-
location.hostname.includes('localhost')
|
|
11
|
-
);
|
|
10
|
+
export const isTestBrowser = isBrowser && (/codewave-(test|dev)\.163yun\.com$/.test(location.hostname) || isLocalMode);
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isNode } from '../env';
|
|
2
|
+
import { StoreName, DbName, NaslCacheLimit } from './constant';
|
|
3
|
+
import { LanguageDatabase, NaslCacheData, NaslCacheUpdateData } from './types';
|
|
4
|
+
|
|
5
|
+
/** 缓存数据库 */
|
|
6
|
+
const database = isNode
|
|
7
|
+
? undefined
|
|
8
|
+
: import('idb').then((idb) => idb.openDB<LanguageDatabase>(DbName, 1, {
|
|
9
|
+
upgrade(db) {
|
|
10
|
+
db.createObjectStore(StoreName.Nasl);
|
|
11
|
+
},
|
|
12
|
+
blocked(currentVersion, blockedVersion, event) {
|
|
13
|
+
// TODO: 超出容量限制
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
export async function canUseNaslCache(appId: string, globalChangedTime: number) {
|
|
18
|
+
const data = await getNaslCacheWithoutCheck(appId);
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
|
|
21
|
+
if (!data || data.forceUpdate || ((now - data.createdTime) > NaslCacheLimit)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 缓存等于服务端,则表示可以使用缓存
|
|
26
|
+
return data.updatedTime === globalChangedTime;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 取出缓存
|
|
31
|
+
*
|
|
32
|
+
* @description 只是取出缓存,并不校验缓存的有效性
|
|
33
|
+
*/
|
|
34
|
+
export async function getNaslCacheWithoutCheck(appId: string) {
|
|
35
|
+
if (isNode) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const db = await database;
|
|
40
|
+
const data = await db.get(StoreName.Nasl, appId);
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function clearCache(appId: string) {
|
|
45
|
+
if (isNode) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const db = await database;
|
|
50
|
+
await db.delete(StoreName.Nasl, appId);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function updateNaslCache(appId: string, data: NaslCacheUpdateData) {
|
|
54
|
+
if (isNode) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const db = await database;
|
|
59
|
+
const cache = await db.get(StoreName.Nasl, appId);
|
|
60
|
+
|
|
61
|
+
// 数据库中数据为新的,不更新缓存
|
|
62
|
+
if (cache && (data.globalChangedTime <= cache.updatedTime)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const oldGlobalChangedTime = cache?.updatedTime ?? 0;
|
|
67
|
+
const newData: NaslCacheData = {
|
|
68
|
+
id: appId,
|
|
69
|
+
data: data.getData(),
|
|
70
|
+
updatedTime: data.globalChangedTime,
|
|
71
|
+
forceUpdate: cache ? data.preGlobalChangedTime !== oldGlobalChangedTime : false,
|
|
72
|
+
createdTime: cache?.createdTime ?? Date.now(),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// await db.delete(StoreName.Nasl, appId);
|
|
76
|
+
await db.put(StoreName.Nasl, newData, appId);
|
|
77
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DBSchema } from 'idb';
|
|
2
|
+
import { StoreName } from './constant';
|
|
3
|
+
|
|
4
|
+
export type NaslData = object;
|
|
5
|
+
|
|
6
|
+
export interface NaslCacheData {
|
|
7
|
+
/** 应用编号 appId */
|
|
8
|
+
id: string;
|
|
9
|
+
/** 开始缓存的时间 */
|
|
10
|
+
createdTime: number;
|
|
11
|
+
/**
|
|
12
|
+
* 变更时间
|
|
13
|
+
*
|
|
14
|
+
* @description 后端为空时,默认为当前时间
|
|
15
|
+
*/
|
|
16
|
+
updatedTime: number;
|
|
17
|
+
/**
|
|
18
|
+
* 强制弃用缓存标志位
|
|
19
|
+
*
|
|
20
|
+
* 在某些特殊情况下,比如 A、B 两个人,A 先改了页面 PageA,然后 B 改了页面 PageB,再然后 A 又修改了页面 PageA。
|
|
21
|
+
* 此时 A 的电脑上标志位是最新的,所以他刷新页面是会走缓存,而不会走后端。
|
|
22
|
+
* 此时两个后端的 Nasl 已经不同,但是因为两个人改的是不同的页面,所以继续走缓存也没关系。
|
|
23
|
+
* 当 A 进入 B 页面的时候,后端会判定产生互锁,让 A 强制刷新页面,此时 A 的标志位是最新的,所以 A 即便刷新页面也会走缓存,
|
|
24
|
+
* 所以这里就需要另外的标志位来让 A 强制不走缓存。
|
|
25
|
+
*/
|
|
26
|
+
forceUpdate: boolean;
|
|
27
|
+
/** 应用 Nasl 数据 */
|
|
28
|
+
data: NaslData;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface NaslCacheUpdateData {
|
|
32
|
+
preGlobalChangedTime: number;
|
|
33
|
+
globalChangedTime: number;
|
|
34
|
+
getData: () => NaslData;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LanguageDatabase extends DBSchema {
|
|
38
|
+
/** Nasl 缓存数据库 */
|
|
39
|
+
[StoreName.Nasl]: {
|
|
40
|
+
/** AppId 为键名 */
|
|
41
|
+
key: string;
|
|
42
|
+
value: NaslCacheData;
|
|
43
|
+
};
|
|
44
|
+
}
|
package/src/utils/types.ts
CHANGED
|
@@ -15,3 +15,23 @@ export interface FileNode extends BaseNode {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export type EmbeddedTSFileGenerator = Generator<void, EmbeddedTSFileResult, string>;
|
|
18
|
+
|
|
19
|
+
export interface FullResponse<D> {
|
|
20
|
+
headers: Record<string, string>;
|
|
21
|
+
data: {
|
|
22
|
+
code: number;
|
|
23
|
+
msg: string;
|
|
24
|
+
success: boolean;
|
|
25
|
+
result: D[];
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface BreakpointStatus {
|
|
30
|
+
path: string;
|
|
31
|
+
breakpointStatus: null | 'ENABLED' | 'DISABLED'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface BatchInstructResult {
|
|
35
|
+
globalChangedTime: number;
|
|
36
|
+
preGlobalChangedTime: number;
|
|
37
|
+
}
|