@dronedeploy/rocos-js-sdk 3.0.10 → 3.0.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|