@dronedeploy/rocos-js-sdk 3.0.10 → 3.0.12
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/cjs/api/StreamRegister.d.ts +3 -3
- package/cjs/api/StreamRegister.js +6 -6
- package/cjs/api/streams/telemetry/TelemetryStreamAbstract.js +8 -7
- package/cjs/helpers/kscript/Context.d.ts +14 -8
- package/cjs/helpers/kscript/Context.js +59 -22
- package/cjs/helpers/kscript/kscript.d.ts +7 -2
- package/cjs/helpers/kscript/kscript.js +24 -14
- package/cjs/helpers/kscript/nodes/Identifier.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/Identifier.js +2 -1
- package/cjs/helpers/kscript/nodes/Literal.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/Literal.js +4 -1
- package/cjs/helpers/kscript/nodes/Node.d.ts +6 -1
- package/cjs/helpers/kscript/nodes/Node.js +0 -1
- package/cjs/helpers/kscript/nodes/Program.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/Program.js +13 -4
- package/cjs/helpers/kscript/nodes/TemplateLiteral.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/TemplateLiteral.js +8 -0
- package/cjs/helpers/kscript/nodes/VariableDeclaration.d.ts +8 -0
- package/cjs/helpers/kscript/nodes/VariableDeclaration.js +43 -0
- package/cjs/helpers/kscript/nodes/expressions/ArrayExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/ArrayExpression.js +11 -0
- package/cjs/helpers/kscript/nodes/expressions/ArrowFunctionExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/ArrowFunctionExpression.js +19 -5
- package/cjs/helpers/kscript/nodes/expressions/AssignmentExpression.d.ts +8 -0
- package/cjs/helpers/kscript/nodes/expressions/AssignmentExpression.js +33 -0
- package/cjs/helpers/kscript/nodes/expressions/BinaryExpression.d.ts +8 -0
- package/cjs/helpers/kscript/nodes/expressions/BinaryExpression.js +55 -22
- package/cjs/helpers/kscript/nodes/expressions/CallExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/CallExpression.js +11 -1
- package/cjs/helpers/kscript/nodes/expressions/ChainExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/ChainExpression.js +1 -0
- package/cjs/helpers/kscript/nodes/expressions/ConditionalExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/ConditionalExpression.js +10 -0
- package/cjs/helpers/kscript/nodes/expressions/LogicalExpression.d.ts +2 -0
- package/cjs/helpers/kscript/nodes/expressions/LogicalExpression.js +11 -0
- package/cjs/helpers/kscript/nodes/expressions/MemberExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/MemberExpression.js +7 -0
- package/cjs/helpers/kscript/nodes/expressions/NewExpression.d.ts +9 -0
- package/cjs/helpers/kscript/nodes/expressions/NewExpression.js +44 -0
- package/cjs/helpers/kscript/nodes/expressions/ObjectExpression.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/expressions/ObjectExpression.js +29 -0
- package/cjs/helpers/kscript/nodes/expressions/UnaryExpression.d.ts +2 -0
- package/cjs/helpers/kscript/nodes/expressions/UnaryExpression.js +9 -0
- package/cjs/helpers/kscript/nodes/expressions/index.d.ts +2 -1
- package/cjs/helpers/kscript/nodes/expressions/index.js +5 -3
- package/cjs/helpers/kscript/nodes/nodeTypes.d.ts +9 -1
- package/cjs/helpers/kscript/nodes/nodeTypes.js +9 -1
- package/cjs/helpers/kscript/nodes/statements/BlockStatement.d.ts +8 -0
- package/cjs/helpers/kscript/nodes/statements/BlockStatement.js +29 -0
- package/cjs/helpers/kscript/nodes/{expressions → statements}/ExpressionStatement.d.ts +1 -0
- package/cjs/helpers/kscript/nodes/{expressions → statements}/ExpressionStatement.js +8 -1
- package/cjs/helpers/kscript/nodes/statements/ReturnStatement.d.ts +12 -0
- package/cjs/helpers/kscript/nodes/statements/ReturnStatement.js +33 -0
- package/cjs/helpers/kscript/nodes/statements/SwitchStatement.d.ts +9 -0
- package/cjs/helpers/kscript/nodes/statements/SwitchStatement.js +52 -0
- package/cjs/helpers/kscript/nodes/statements/index.d.ts +4 -0
- package/cjs/helpers/kscript/nodes/statements/index.js +14 -0
- package/cjs/models/asset-storage/SyncIntegrations.d.ts +3 -3
- package/cjs/services/AssetStorageService.d.ts +3 -3
- package/cjs/services/BaseStreamService.js +1 -1
- package/cjs/services/WebRTCSignallingService.js +1 -2
- package/esm/api/StreamRegister.d.ts +3 -3
- package/esm/api/StreamRegister.js +6 -6
- package/esm/api/streams/telemetry/TelemetryStreamAbstract.js +8 -7
- package/esm/helpers/kscript/Context.d.ts +14 -8
- package/esm/helpers/kscript/Context.js +59 -22
- package/esm/helpers/kscript/kscript.d.ts +7 -2
- package/esm/helpers/kscript/kscript.js +22 -13
- package/esm/helpers/kscript/nodes/Identifier.d.ts +1 -0
- package/esm/helpers/kscript/nodes/Identifier.js +2 -1
- package/esm/helpers/kscript/nodes/Literal.d.ts +1 -0
- package/esm/helpers/kscript/nodes/Literal.js +4 -1
- package/esm/helpers/kscript/nodes/Node.d.ts +6 -1
- package/esm/helpers/kscript/nodes/Node.js +0 -1
- package/esm/helpers/kscript/nodes/Program.d.ts +1 -0
- package/esm/helpers/kscript/nodes/Program.js +13 -4
- package/esm/helpers/kscript/nodes/TemplateLiteral.d.ts +1 -0
- package/esm/helpers/kscript/nodes/TemplateLiteral.js +8 -0
- package/esm/helpers/kscript/nodes/VariableDeclaration.d.ts +8 -0
- package/esm/helpers/kscript/nodes/VariableDeclaration.js +37 -0
- package/esm/helpers/kscript/nodes/expressions/ArrayExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/ArrayExpression.js +11 -0
- package/esm/helpers/kscript/nodes/expressions/ArrowFunctionExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/ArrowFunctionExpression.js +19 -5
- package/esm/helpers/kscript/nodes/expressions/AssignmentExpression.d.ts +8 -0
- package/esm/helpers/kscript/nodes/expressions/AssignmentExpression.js +27 -0
- package/esm/helpers/kscript/nodes/expressions/BinaryExpression.d.ts +8 -0
- package/esm/helpers/kscript/nodes/expressions/BinaryExpression.js +57 -23
- package/esm/helpers/kscript/nodes/expressions/CallExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/CallExpression.js +11 -1
- package/esm/helpers/kscript/nodes/expressions/ChainExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/ChainExpression.js +1 -0
- package/esm/helpers/kscript/nodes/expressions/ConditionalExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/ConditionalExpression.js +10 -0
- package/esm/helpers/kscript/nodes/expressions/LogicalExpression.d.ts +2 -0
- package/esm/helpers/kscript/nodes/expressions/LogicalExpression.js +13 -1
- package/esm/helpers/kscript/nodes/expressions/MemberExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/MemberExpression.js +7 -0
- package/esm/helpers/kscript/nodes/expressions/NewExpression.d.ts +9 -0
- package/esm/helpers/kscript/nodes/expressions/NewExpression.js +38 -0
- package/esm/helpers/kscript/nodes/expressions/ObjectExpression.d.ts +1 -0
- package/esm/helpers/kscript/nodes/expressions/ObjectExpression.js +29 -0
- package/esm/helpers/kscript/nodes/expressions/UnaryExpression.d.ts +2 -0
- package/esm/helpers/kscript/nodes/expressions/UnaryExpression.js +11 -1
- package/esm/helpers/kscript/nodes/expressions/index.d.ts +2 -1
- package/esm/helpers/kscript/nodes/expressions/index.js +2 -1
- package/esm/helpers/kscript/nodes/nodeTypes.d.ts +9 -1
- package/esm/helpers/kscript/nodes/nodeTypes.js +9 -1
- package/esm/helpers/kscript/nodes/statements/BlockStatement.d.ts +8 -0
- package/esm/helpers/kscript/nodes/statements/BlockStatement.js +23 -0
- package/esm/helpers/kscript/nodes/{expressions → statements}/ExpressionStatement.d.ts +1 -0
- package/esm/helpers/kscript/nodes/{expressions → statements}/ExpressionStatement.js +8 -1
- package/esm/helpers/kscript/nodes/statements/ReturnStatement.d.ts +12 -0
- package/esm/helpers/kscript/nodes/statements/ReturnStatement.js +25 -0
- package/esm/helpers/kscript/nodes/statements/SwitchStatement.d.ts +9 -0
- package/esm/helpers/kscript/nodes/statements/SwitchStatement.js +46 -0
- package/esm/helpers/kscript/nodes/statements/index.d.ts +4 -0
- package/esm/helpers/kscript/nodes/statements/index.js +4 -0
- package/esm/models/asset-storage/SyncIntegrations.d.ts +3 -3
- package/esm/services/AssetStorageService.d.ts +3 -3
- package/esm/services/BaseStreamService.js +1 -1
- package/esm/services/WebRTCSignallingService.js +1 -2
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SwitchStatement = exports.ExpressionStatement = exports.ReturnStatement = exports.BlockStatement = void 0;
|
|
7
|
+
var BlockStatement_1 = require("./BlockStatement");
|
|
8
|
+
Object.defineProperty(exports, "BlockStatement", { enumerable: true, get: function () { return __importDefault(BlockStatement_1).default; } });
|
|
9
|
+
var ReturnStatement_1 = require("./ReturnStatement");
|
|
10
|
+
Object.defineProperty(exports, "ReturnStatement", { enumerable: true, get: function () { return __importDefault(ReturnStatement_1).default; } });
|
|
11
|
+
var ExpressionStatement_1 = require("./ExpressionStatement");
|
|
12
|
+
Object.defineProperty(exports, "ExpressionStatement", { enumerable: true, get: function () { return __importDefault(ExpressionStatement_1).default; } });
|
|
13
|
+
var SwitchStatement_1 = require("./SwitchStatement");
|
|
14
|
+
Object.defineProperty(exports, "SwitchStatement", { enumerable: true, get: function () { return __importDefault(SwitchStatement_1).default; } });
|
|
@@ -12,9 +12,9 @@ export interface AssetSyncDefinitionModel {
|
|
|
12
12
|
export interface AssetSyncDefinitionOverrideModel extends AssetSyncDefinitionModel {
|
|
13
13
|
_isOverridden: boolean;
|
|
14
14
|
}
|
|
15
|
-
export interface AssetSyncDefinitionsModel {
|
|
16
|
-
items:
|
|
17
|
-
profileOverriddenItems?:
|
|
15
|
+
export interface AssetSyncDefinitionsModel<I extends AssetSyncDefinitionModel = AssetSyncDefinitionOverrideModel> {
|
|
16
|
+
items: I[];
|
|
17
|
+
profileOverriddenItems?: AssetSyncDefinitionModel[];
|
|
18
18
|
}
|
|
19
19
|
export interface AssetSyncIntegrationProviderModel {
|
|
20
20
|
provider: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AssetItemModel, AssetItemWithObservationsModel, AssetSyncDefinitionsModel, AssetSyncIntegrationModel, AssetSyncIntegrationProviderModel, CreateAssetSyncIntegrationModel, IBaseService, IRocosSDKConfig, RocosError } from '../models';
|
|
1
|
+
import { AssetItemModel, AssetItemWithObservationsModel, AssetSyncDefinitionModel, AssetSyncDefinitionsModel, AssetSyncIntegrationModel, AssetSyncIntegrationProviderModel, CreateAssetSyncIntegrationModel, IBaseService, IRocosSDKConfig, RocosError } from '../models';
|
|
2
2
|
import { BaseServiceAbstract } from './BaseServiceAbstract';
|
|
3
3
|
export declare class AssetStorageService extends BaseServiceAbstract implements IBaseService {
|
|
4
4
|
constructor(config: IRocosSDKConfig);
|
|
@@ -92,7 +92,7 @@ export declare class AssetStorageService extends BaseServiceAbstract implements
|
|
|
92
92
|
* @param definition
|
|
93
93
|
* @param syncNow - Sync configured paths immediately
|
|
94
94
|
*/
|
|
95
|
-
setRobotSyncDefinitions(projectId: string, callsign: string, definition: AssetSyncDefinitionsModel
|
|
95
|
+
setRobotSyncDefinitions(projectId: string, callsign: string, definition: AssetSyncDefinitionsModel<AssetSyncDefinitionModel>, syncNow?: boolean): Promise<AssetSyncDefinitionsModel>;
|
|
96
96
|
/**
|
|
97
97
|
* Get Robot Sync Definitions
|
|
98
98
|
* @param projectId
|
|
@@ -105,7 +105,7 @@ export declare class AssetStorageService extends BaseServiceAbstract implements
|
|
|
105
105
|
* @param profileId
|
|
106
106
|
* @param definition
|
|
107
107
|
*/
|
|
108
|
-
setProfileSyncDefinitions(projectId: string, profileId: string, definition: AssetSyncDefinitionsModel): Promise<AssetSyncDefinitionsModel>;
|
|
108
|
+
setProfileSyncDefinitions(projectId: string, profileId: string, definition: Omit<AssetSyncDefinitionsModel<AssetSyncDefinitionModel>, 'profileOverriddenItems'>): Promise<AssetSyncDefinitionsModel>;
|
|
109
109
|
/**
|
|
110
110
|
* Get Profile Sync Definitions
|
|
111
111
|
* @param projectId
|
|
@@ -44,7 +44,7 @@ class BaseStreamService {
|
|
|
44
44
|
this.status = msg === models_1.SubscriberStatusEnum.STOPPED || msg === models_1.SubscriberStatusEnum.ALIVE;
|
|
45
45
|
this.status$.next(msg);
|
|
46
46
|
});
|
|
47
|
-
|
|
47
|
+
streamRegister.addStream(stream);
|
|
48
48
|
await this.initStream(stream);
|
|
49
49
|
}
|
|
50
50
|
return { stream, isNew };
|
|
@@ -53,8 +53,7 @@ class WebRTCSignallingService {
|
|
|
53
53
|
this.status = msg === SubscriberStatusEnum_1.SubscriberStatusEnum.STOPPED || msg === SubscriberStatusEnum_1.SubscriberStatusEnum.ALIVE;
|
|
54
54
|
this.status$.next(msg);
|
|
55
55
|
});
|
|
56
|
-
|
|
57
|
-
await streamRegister.addStream(stream);
|
|
56
|
+
streamRegister.addStream(stream);
|
|
58
57
|
await this.initStream(stream);
|
|
59
58
|
}
|
|
60
59
|
return stream;
|
|
@@ -6,8 +6,8 @@ export declare class StreamRegister {
|
|
|
6
6
|
private constructor();
|
|
7
7
|
static getInstance(): StreamRegister;
|
|
8
8
|
static getIdentifier($identifier: string, scope?: string): string;
|
|
9
|
-
addStream(stream: IBaseStream):
|
|
9
|
+
addStream(stream: IBaseStream): void;
|
|
10
10
|
getStream(identifier: string): IBaseStream | undefined;
|
|
11
|
-
removeStream(stream: IBaseStream):
|
|
12
|
-
removeAllStreams():
|
|
11
|
+
removeStream(stream: IBaseStream): void;
|
|
12
|
+
removeAllStreams(): boolean;
|
|
13
13
|
}
|
|
@@ -14,10 +14,10 @@ export class StreamRegister {
|
|
|
14
14
|
static getIdentifier($identifier, scope) {
|
|
15
15
|
return `${$identifier}-${scope ?? ''}`;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
addStream(stream) {
|
|
18
18
|
try {
|
|
19
19
|
if (this.teleStreams.has(stream.identifier)) {
|
|
20
|
-
|
|
20
|
+
this.removeStream(stream);
|
|
21
21
|
}
|
|
22
22
|
this.teleStreams.set(stream.identifier, stream);
|
|
23
23
|
}
|
|
@@ -34,9 +34,9 @@ export class StreamRegister {
|
|
|
34
34
|
getStream(identifier) {
|
|
35
35
|
return this.teleStreams.get(identifier);
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
removeStream(stream) {
|
|
38
38
|
try {
|
|
39
|
-
|
|
39
|
+
stream.stopStream();
|
|
40
40
|
this.teleStreams.delete(stream.identifier);
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
@@ -49,10 +49,10 @@ export class StreamRegister {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
removeAllStreams() {
|
|
53
53
|
try {
|
|
54
54
|
for (const [, stream] of this.teleStreams.entries()) {
|
|
55
|
-
|
|
55
|
+
this.removeStream(stream);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
catch (e) {
|
|
@@ -100,6 +100,14 @@ export class TelemetryStreamAbstract {
|
|
|
100
100
|
const before = this.getSubscriptions();
|
|
101
101
|
this.subscriptions.delete(params.uniqueId);
|
|
102
102
|
const after = this.getSubscriptions();
|
|
103
|
+
// Do this before we send the telemetry request so that new subscriptions don't get this stream from the register while it is closing
|
|
104
|
+
if (!this.subscriptions.size) {
|
|
105
|
+
this.logger.info('No subscriptions remaining closing stream', params.uniqueId);
|
|
106
|
+
this.stopStream();
|
|
107
|
+
// self remove when no subscriptions are left
|
|
108
|
+
StreamRegister.getInstance().removeStream(this);
|
|
109
|
+
this.logger.info('Stream closed');
|
|
110
|
+
}
|
|
103
111
|
// assign the current values from state after change
|
|
104
112
|
this.callsignsLookup = new CallsignsLookup(Object.keys(after));
|
|
105
113
|
this.sources = arrayUnique(Object.values(after).reduce((a, v) => a.concat(v), []));
|
|
@@ -113,13 +121,6 @@ export class TelemetryStreamAbstract {
|
|
|
113
121
|
this.logger.error(`Failed to unsubscribe: ${err}`);
|
|
114
122
|
}
|
|
115
123
|
}
|
|
116
|
-
if (!this.subscriptions.size) {
|
|
117
|
-
this.logger.info('No subscriptions remaining closing stream', params.uniqueId);
|
|
118
|
-
this.stopStream();
|
|
119
|
-
// self remove when no subscriptions a re left
|
|
120
|
-
void StreamRegister.getInstance().removeStream(this);
|
|
121
|
-
this.logger.info('Stream closed');
|
|
122
|
-
}
|
|
123
124
|
}
|
|
124
125
|
sendAcknowledgment(uid, status, noRetry) {
|
|
125
126
|
return this.sendAcknowledgmentInternal(uid, status, noRetry);
|
|
@@ -7,19 +7,20 @@ import type { NodeType } from './nodes';
|
|
|
7
7
|
* If the set is null, all properties are allowed.
|
|
8
8
|
*/
|
|
9
9
|
export type PrototypeWhitelist = Map<unknown, Set<string> | null>;
|
|
10
|
-
export type Scope =
|
|
10
|
+
export type Scope = Record<string, unknown> | Map<string, unknown>;
|
|
11
11
|
export interface ContextOptions {
|
|
12
12
|
nodeBlacklist?: Set<NodeType>;
|
|
13
13
|
prototypeWhitelist?: PrototypeWhitelist;
|
|
14
14
|
functionCallsAllowed?: boolean;
|
|
15
15
|
}
|
|
16
16
|
export default class Context {
|
|
17
|
-
readonly
|
|
18
|
-
readonly
|
|
19
|
-
private readonly
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
private readonly parent;
|
|
18
|
+
private readonly scope;
|
|
19
|
+
private readonly config;
|
|
20
|
+
static create(scope?: Scope, options?: ContextOptions): Context;
|
|
21
|
+
private static buildMap;
|
|
22
|
+
private constructor();
|
|
23
|
+
newChild(scope?: Scope): Context;
|
|
23
24
|
/** Returns true if the property is allowed to be accessed on the prototype.
|
|
24
25
|
*
|
|
25
26
|
* - If the prototype is not in the whitelist, the property is allowed only if it is an own property.
|
|
@@ -30,5 +31,10 @@ export default class Context {
|
|
|
30
31
|
* @param ownProperty Whether the property is owned by the object it is being accessed on.
|
|
31
32
|
*/
|
|
32
33
|
isPrototypeAllowed(prototype: unknown, property: string, ownProperty: boolean): boolean;
|
|
33
|
-
|
|
34
|
+
isNodeAllowed(nodeType: AnyNode['type']): boolean;
|
|
35
|
+
get isFunctionCallAllowed(): boolean;
|
|
36
|
+
private getDescriptor;
|
|
37
|
+
get(key: string): unknown;
|
|
38
|
+
set(key: string, value: unknown): void;
|
|
39
|
+
declare(key: string, value: unknown, constant: boolean): void;
|
|
34
40
|
}
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
export default class Context {
|
|
2
|
-
|
|
2
|
+
static create(scope, options) {
|
|
3
|
+
return new Context(null, {
|
|
4
|
+
functionCallsAllowed: true,
|
|
5
|
+
nodeBlacklist: new Set(),
|
|
6
|
+
prototypeWhitelist: new Map(),
|
|
7
|
+
...(options ?? {}),
|
|
8
|
+
}, scope);
|
|
9
|
+
}
|
|
10
|
+
static buildMap(obj) {
|
|
11
|
+
const entries = obj instanceof Map ? Array.from(obj.entries()) : Object.entries(obj);
|
|
12
|
+
return new Map(entries.map(([key, value]) => [key, { value, constant: false }]));
|
|
13
|
+
}
|
|
14
|
+
constructor(parent, config, scope) {
|
|
15
|
+
this.parent = parent;
|
|
3
16
|
this.scope = scope ? Context.buildMap(scope) : new Map();
|
|
4
|
-
this.
|
|
5
|
-
nodeBlacklist:
|
|
6
|
-
prototypeWhitelist:
|
|
7
|
-
functionCallsAllowed:
|
|
17
|
+
this.config = {
|
|
18
|
+
nodeBlacklist: config.nodeBlacklist ?? new Set(),
|
|
19
|
+
prototypeWhitelist: config.prototypeWhitelist ?? new Map(),
|
|
20
|
+
functionCallsAllowed: config.functionCallsAllowed ?? true,
|
|
8
21
|
};
|
|
9
|
-
this.isFunctionCallAllowed = this.options.functionCallsAllowed;
|
|
10
|
-
}
|
|
11
|
-
isNodeAllowed(nodeType) {
|
|
12
|
-
return !this.options.nodeBlacklist.has(nodeType);
|
|
13
22
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (scope instanceof Map) {
|
|
17
|
-
newEntries = [...scope.entries()];
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
newEntries = Object.entries(scope);
|
|
21
|
-
}
|
|
22
|
-
const newScope = new Map([...this.scope.entries(), ...newEntries]);
|
|
23
|
-
return new Context(newScope, this.options);
|
|
23
|
+
newChild(scope) {
|
|
24
|
+
return new Context(this, this.config, scope);
|
|
24
25
|
}
|
|
25
26
|
/** Returns true if the property is allowed to be accessed on the prototype.
|
|
26
27
|
*
|
|
@@ -32,7 +33,7 @@ export default class Context {
|
|
|
32
33
|
* @param ownProperty Whether the property is owned by the object it is being accessed on.
|
|
33
34
|
*/
|
|
34
35
|
isPrototypeAllowed(prototype, property, ownProperty) {
|
|
35
|
-
const whitelist = this.
|
|
36
|
+
const whitelist = this.config.prototypeWhitelist.get(prototype);
|
|
36
37
|
// If the object owns the property, and it's not in the whitelist, it's allowed.
|
|
37
38
|
// This prevents direct calls to non-whitelisted properties on allowed prototypes
|
|
38
39
|
// e.g. Object.prototype.hasOwnProperty.call(obj, 'toString')
|
|
@@ -43,7 +44,43 @@ export default class Context {
|
|
|
43
44
|
return true;
|
|
44
45
|
return whitelist.has(property);
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
return
|
|
47
|
+
isNodeAllowed(nodeType) {
|
|
48
|
+
return !this.config.nodeBlacklist.has(nodeType);
|
|
49
|
+
}
|
|
50
|
+
get isFunctionCallAllowed() {
|
|
51
|
+
return this.config.functionCallsAllowed;
|
|
52
|
+
}
|
|
53
|
+
getDescriptor(key, searchParents = true) {
|
|
54
|
+
if (this.scope.has(key)) {
|
|
55
|
+
return this.scope.get(key);
|
|
56
|
+
}
|
|
57
|
+
if (searchParents && this.parent) {
|
|
58
|
+
return this.parent.getDescriptor(key);
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
get(key) {
|
|
63
|
+
const descriptor = this.getDescriptor(key);
|
|
64
|
+
if (descriptor) {
|
|
65
|
+
return descriptor.value;
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
set(key, value) {
|
|
70
|
+
const descriptor = this.getDescriptor(key);
|
|
71
|
+
if (!descriptor) {
|
|
72
|
+
throw new Error(`no variable with name ${key}`);
|
|
73
|
+
}
|
|
74
|
+
if (descriptor.constant) {
|
|
75
|
+
throw new Error(`cannot reassign to constant variable ${key}`);
|
|
76
|
+
}
|
|
77
|
+
descriptor.value = value;
|
|
78
|
+
}
|
|
79
|
+
declare(key, value, constant) {
|
|
80
|
+
const descriptor = this.getDescriptor(key, false);
|
|
81
|
+
if (descriptor) {
|
|
82
|
+
throw new Error(`variable ${key} already declared`);
|
|
83
|
+
}
|
|
84
|
+
this.scope.set(key, { value, constant });
|
|
48
85
|
}
|
|
49
86
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ContextOptions, PrototypeWhitelist, Scope } from './Context';
|
|
2
2
|
import { Node } from './nodes';
|
|
3
|
-
export declare
|
|
4
|
-
|
|
3
|
+
export declare const compile: (code: string, scope?: Scope, options?: ContextOptions) => Node;
|
|
4
|
+
/** Throws an error if the code uses an invalid node.
|
|
5
|
+
*
|
|
6
|
+
* This does not check that the code will run without errors, only that the nodes used are allowed.
|
|
7
|
+
**/
|
|
8
|
+
export declare const validate: (code: string, options?: ContextOptions) => void;
|
|
9
|
+
export declare const execute: (code: string, scope?: Scope, options?: ContextOptions) => unknown;
|
|
5
10
|
export declare const SAFE_GLOBALS: Map<string, unknown>;
|
|
6
11
|
export declare const SAFE_PROTOTYPES: PrototypeWhitelist;
|
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
import Context from './Context';
|
|
2
|
-
import { parse } from 'acorn';
|
|
2
|
+
import { parse as acorn } from 'acorn';
|
|
3
3
|
import { construct } from './utils';
|
|
4
|
-
|
|
5
|
-
return compile(code, scope, options).run();
|
|
6
|
-
}
|
|
7
|
-
export function compile(code, scope, options) {
|
|
8
|
-
let program;
|
|
4
|
+
const parse = (code) => {
|
|
9
5
|
try {
|
|
10
6
|
// we add the brackets to ensure that object literals are parsed correctly
|
|
11
|
-
|
|
7
|
+
// e.g. `{ a: 1 }` is not a valid statement, but `({ a: 1 })` is
|
|
8
|
+
return acorn(`(${code})`, { ecmaVersion: 2020, sourceType: 'script' });
|
|
12
9
|
}
|
|
13
10
|
catch (error) {
|
|
14
11
|
if (error instanceof SyntaxError) {
|
|
15
12
|
// fallback to non-wrapped code for edge cases where the brackets cause issues
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
else {
|
|
19
|
-
throw error;
|
|
13
|
+
// e.g. `if (a) 2; else 4;` will throw a syntax error if wrapped in brackets
|
|
14
|
+
return acorn(`${code}`, { ecmaVersion: 2020, sourceType: 'script' });
|
|
20
15
|
}
|
|
16
|
+
throw error;
|
|
21
17
|
}
|
|
22
|
-
|
|
18
|
+
};
|
|
19
|
+
export const compile = (code, scope, options) => {
|
|
20
|
+
const program = parse(code);
|
|
21
|
+
const context = Context.create(scope ?? SAFE_GLOBALS, {
|
|
23
22
|
prototypeWhitelist: SAFE_PROTOTYPES,
|
|
24
23
|
...options,
|
|
25
24
|
});
|
|
26
25
|
return construct(program, context);
|
|
27
|
-
}
|
|
26
|
+
};
|
|
27
|
+
/** Throws an error if the code uses an invalid node.
|
|
28
|
+
*
|
|
29
|
+
* This does not check that the code will run without errors, only that the nodes used are allowed.
|
|
30
|
+
**/
|
|
31
|
+
export const validate = (code, options) => {
|
|
32
|
+
compile(code, undefined, options).validate(true);
|
|
33
|
+
};
|
|
34
|
+
export const execute = (code, scope, options) => {
|
|
35
|
+
return compile(code, scope, options).run();
|
|
36
|
+
};
|
|
28
37
|
export const SAFE_GLOBALS = new Map(Object.entries({
|
|
29
38
|
console: {
|
|
30
39
|
debug: console.debug,
|
|
@@ -7,10 +7,13 @@ export default class LiteralNode extends Node {
|
|
|
7
7
|
constructor(node, context) {
|
|
8
8
|
super(node, context, 'Literal');
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
validate() {
|
|
11
11
|
if (this.node.bigint) {
|
|
12
12
|
throw new Error('BigInts are not supported');
|
|
13
13
|
}
|
|
14
|
+
}
|
|
15
|
+
run() {
|
|
16
|
+
this.validate();
|
|
14
17
|
return this.node.value;
|
|
15
18
|
}
|
|
16
19
|
}
|
|
@@ -3,7 +3,12 @@ import type Context from '../Context';
|
|
|
3
3
|
export default abstract class Node<T extends AnyNode = AnyNode> {
|
|
4
4
|
protected context: Context;
|
|
5
5
|
protected node: T;
|
|
6
|
-
protected scope: Context['scope'];
|
|
7
6
|
protected constructor(node: AnyNode, context: Context, expectedType: T['type'] | T['type'][]);
|
|
7
|
+
/** Runs the node. */
|
|
8
8
|
abstract run(): unknown;
|
|
9
|
+
/** Validates the node. If the node is invalid, an error is thrown.
|
|
10
|
+
*
|
|
11
|
+
* if `validateChildren` is true, the children of the node will also be validated.
|
|
12
|
+
*/
|
|
13
|
+
abstract validate(validateChildren: boolean): void;
|
|
9
14
|
}
|
|
@@ -8,11 +8,20 @@ export default class ProgramNode extends Node {
|
|
|
8
8
|
constructor(node, scope) {
|
|
9
9
|
super(node, scope, 'Program');
|
|
10
10
|
}
|
|
11
|
+
validate(validateChildren = false) {
|
|
12
|
+
if (!validateChildren) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const child of this.node.body) {
|
|
16
|
+
construct(child, this.context).validate(true);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
11
19
|
run() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
this.validate();
|
|
21
|
+
let result;
|
|
22
|
+
for (const child of this.node.body) {
|
|
23
|
+
result = construct(child, this.context).run();
|
|
15
24
|
}
|
|
16
|
-
return
|
|
25
|
+
return result;
|
|
17
26
|
}
|
|
18
27
|
}
|
|
@@ -20,6 +20,14 @@ export default class TemplateLiteralNode extends Node {
|
|
|
20
20
|
constructor(node, scope) {
|
|
21
21
|
super(node, scope, 'TemplateLiteral');
|
|
22
22
|
}
|
|
23
|
+
validate(validateChildren = false) {
|
|
24
|
+
if (!validateChildren) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
for (const expression of this.node.expressions) {
|
|
28
|
+
construct(expression, this.context).validate(true);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
23
31
|
run() {
|
|
24
32
|
return this.node.quasis.reduce((acc, quasi, i) => {
|
|
25
33
|
const expression = this.node.expressions[i] ? construct(this.node.expressions[i], this.context).run() : '';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AnyNode, VariableDeclaration } from 'acorn';
|
|
2
|
+
import Context from '../Context';
|
|
3
|
+
import Node from './Node';
|
|
4
|
+
export default class VariableDeclarationNode extends Node<VariableDeclaration> {
|
|
5
|
+
constructor(node: AnyNode, context: Context);
|
|
6
|
+
validate(validateChildren?: boolean): void;
|
|
7
|
+
run(): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Node from './Node';
|
|
2
|
+
import { construct } from '../utils';
|
|
3
|
+
export default class VariableDeclarationNode extends Node {
|
|
4
|
+
constructor(node, context) {
|
|
5
|
+
super(node, context, 'VariableDeclaration');
|
|
6
|
+
}
|
|
7
|
+
validate(validateChildren = false) {
|
|
8
|
+
if (this.node.kind === 'var') {
|
|
9
|
+
throw new Error('var is not supported. use let or const instead');
|
|
10
|
+
}
|
|
11
|
+
for (const declaration of this.node.declarations) {
|
|
12
|
+
if (declaration.id.type !== 'Identifier') {
|
|
13
|
+
throw new Error('variable name must be an identifier');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (!validateChildren) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const declaration of this.node.declarations) {
|
|
20
|
+
construct(declaration.id, this.context).validate(true);
|
|
21
|
+
if (declaration.init) {
|
|
22
|
+
construct(declaration.init, this.context).validate(true);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
run() {
|
|
27
|
+
this.validate();
|
|
28
|
+
for (const declaration of this.node.declarations) {
|
|
29
|
+
const id = declaration.id.name;
|
|
30
|
+
let init;
|
|
31
|
+
if (declaration.init) {
|
|
32
|
+
init = construct(declaration.init, this.context).run();
|
|
33
|
+
}
|
|
34
|
+
this.context.declare(id, init, this.node.kind === 'const');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -4,6 +4,17 @@ export default class ArrayExpressionNode extends Node {
|
|
|
4
4
|
constructor(node, context) {
|
|
5
5
|
super(node, context, 'ArrayExpression');
|
|
6
6
|
}
|
|
7
|
+
validate(validateChildren = false) {
|
|
8
|
+
if (!validateChildren) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
for (const element of this.node.elements) {
|
|
12
|
+
if (element === null) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
construct(element, this.context).validate(true);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
7
18
|
run() {
|
|
8
19
|
const array = [];
|
|
9
20
|
for (const element of this.node.elements) {
|
|
@@ -10,5 +10,6 @@ import Node from '../Node';
|
|
|
10
10
|
export default class ArrowFunctionExpressionNode extends Node<ArrowFunctionExpression> {
|
|
11
11
|
private readonly params;
|
|
12
12
|
constructor(node: AnyNode, context: Context);
|
|
13
|
+
validate(validateChildren?: boolean): void;
|
|
13
14
|
run(): unknown;
|
|
14
15
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Node from '../Node';
|
|
2
|
+
import { ReturnStatementError } from '../statements/ReturnStatement';
|
|
2
3
|
import { construct } from '../../utils';
|
|
3
4
|
/** Represents an arrow function expression.
|
|
4
5
|
*
|
|
@@ -14,21 +15,34 @@ export default class ArrowFunctionExpressionNode extends Node {
|
|
|
14
15
|
}
|
|
15
16
|
this.params = this.node.params;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
+
validate(validateChildren = false) {
|
|
18
19
|
if (!this.context.isFunctionCallAllowed)
|
|
19
20
|
throw new Error('functions are not allowed');
|
|
20
|
-
if (!this.node.expression)
|
|
21
|
-
throw new Error('functions must be an expression');
|
|
22
21
|
if (this.node.async)
|
|
23
22
|
throw new Error('async functions are not supported');
|
|
23
|
+
if (!validateChildren) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
construct(this.node.body, this.context).validate(true);
|
|
27
|
+
}
|
|
28
|
+
run() {
|
|
29
|
+
this.validate();
|
|
24
30
|
return (...args) => {
|
|
25
31
|
const scope = new Map();
|
|
26
32
|
for (const param of this.params) {
|
|
27
33
|
const index = this.params.indexOf(param);
|
|
28
34
|
scope.set(param.name, args?.[index]);
|
|
29
35
|
}
|
|
30
|
-
const newContext = this.context.
|
|
31
|
-
|
|
36
|
+
const newContext = this.context.newChild(scope);
|
|
37
|
+
try {
|
|
38
|
+
return construct(this.node.body, newContext).run();
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
if (e instanceof ReturnStatementError) {
|
|
42
|
+
return e.value;
|
|
43
|
+
}
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
32
46
|
};
|
|
33
47
|
}
|
|
34
48
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AnyNode, AssignmentExpression } from 'acorn';
|
|
2
|
+
import Context from '../../Context';
|
|
3
|
+
import Node from '../Node';
|
|
4
|
+
export default class AssignmentExpressionNode extends Node<AssignmentExpression> {
|
|
5
|
+
constructor(node: AnyNode, context: Context);
|
|
6
|
+
validate(validateChildren?: boolean): void;
|
|
7
|
+
run(): unknown;
|
|
8
|
+
}
|