@hubspot/ui-extensions-dev-server 0.9.3 → 0.9.5
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/dist/index.js +7 -17
- package/dist/lib/DevModeParentInterface.d.ts +1 -1
- package/dist/lib/DevModeParentInterface.js +15 -10
- package/dist/lib/ast.d.ts +2 -12
- package/dist/lib/ast.js +150 -131
- package/dist/lib/build.js +8 -8
- package/dist/lib/config.js +7 -6
- package/dist/lib/dev.js +2 -1
- package/dist/lib/parsing-utils.d.ts +31 -0
- package/dist/lib/parsing-utils.js +294 -0
- package/dist/lib/plugins/codeBlockingPlugin.js +2 -1
- package/dist/lib/plugins/devBuildPlugin.js +9 -19
- package/dist/lib/plugins/manifestPlugin.js +1 -1
- package/dist/lib/plugins/relevantModulesPlugin.js +2 -1
- package/dist/lib/server.js +4 -4
- package/dist/lib/types.d.ts +16 -3
- package/dist/lib/utils.js +11 -11
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -15,23 +15,13 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) ||
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
35
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
26
|
exports.DevModeUnifiedInterfaceNonSingleton = exports.DevModeUnifiedInterface = exports.DevModeInterfaceNonSingleton = exports.DevModeInterface = exports.buildSingleExtension = exports.remoteBuild = void 0;
|
|
37
27
|
const build_1 = require("./lib/build");
|
|
@@ -12,7 +12,7 @@ export declare abstract class DevModeParentInterface {
|
|
|
12
12
|
protected abstract _generateAppExtensionMappings(components: ProjectComponentMap | UnifiedProjectComponentMap): AppExtensionMapping[];
|
|
13
13
|
_getPlatformVersion(projectConfig?: ProjectConfig): PlatformVersion;
|
|
14
14
|
_reset(): void;
|
|
15
|
-
parentSetup({ onUploadRequired,
|
|
15
|
+
parentSetup({ onUploadRequired, logger, urls, setActiveApp, choices, }: DevModeBaseSetupArguments): Promise<void>;
|
|
16
16
|
start({ requestPorts, accountId, projectConfig, }: DevModeStartArguments): Promise<void>;
|
|
17
17
|
fileChange(filePath: string, __event: unknown): Promise<void>;
|
|
18
18
|
cleanup(): Promise<void>;
|
|
@@ -8,6 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.DevModeParentInterface = void 0;
|
|
13
16
|
const constants_1 = require("./constants");
|
|
@@ -16,6 +19,7 @@ const config_1 = require("./config");
|
|
|
16
19
|
const constants_2 = require("./constants");
|
|
17
20
|
const utils_1 = require("./utils");
|
|
18
21
|
const DevServerState_1 = require("./DevServerState");
|
|
22
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
19
23
|
const defaultLogger = {
|
|
20
24
|
info: (...args) => {
|
|
21
25
|
console.log(...args);
|
|
@@ -63,9 +67,9 @@ class DevModeParentInterface {
|
|
|
63
67
|
this.isConfigured = false;
|
|
64
68
|
this.isRunning = false;
|
|
65
69
|
}
|
|
66
|
-
parentSetup(
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
parentSetup({ onUploadRequired, logger, urls, setActiveApp, choices = [], }) {
|
|
71
|
+
var _a, _b, _c;
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
69
73
|
if (this.isConfigured) {
|
|
70
74
|
logger.debug('Dev server has already been configured, skipping');
|
|
71
75
|
return;
|
|
@@ -80,7 +84,8 @@ class DevModeParentInterface {
|
|
|
80
84
|
this.configs = [choices[0].value];
|
|
81
85
|
}
|
|
82
86
|
else {
|
|
83
|
-
const
|
|
87
|
+
const promptModule = inquirer_1.default.createPromptModule();
|
|
88
|
+
const answers = yield promptModule({
|
|
84
89
|
type: 'checkbox',
|
|
85
90
|
name: 'extensions',
|
|
86
91
|
message: 'Which extension(s) would you like to run?',
|
|
@@ -100,13 +105,13 @@ class DevModeParentInterface {
|
|
|
100
105
|
}
|
|
101
106
|
this.isConfigured = true;
|
|
102
107
|
if (typeof setActiveApp === 'function') {
|
|
103
|
-
yield setActiveApp((
|
|
108
|
+
yield setActiveApp((_c = (_b = (_a = this.configs) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.appConfig) === null || _c === void 0 ? void 0 : _c.uid);
|
|
104
109
|
}
|
|
105
110
|
});
|
|
106
111
|
}
|
|
107
|
-
start(
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
start({ requestPorts, accountId, projectConfig, }) {
|
|
113
|
+
var _a, _b, _c, _d;
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
110
115
|
this.logger.debug('Start function was invoked', {
|
|
111
116
|
accountId,
|
|
112
117
|
projectConfig,
|
|
@@ -133,7 +138,7 @@ class DevModeParentInterface {
|
|
|
133
138
|
this.logger.debug('Call to port manager failed, using default ports');
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
|
-
const { proxy: localDevUrlMapping } = (0, config_1.loadLocalConfig)(((
|
|
141
|
+
const { proxy: localDevUrlMapping } = (0, config_1.loadLocalConfig)(((_b = (_a = this.configs) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.path) || '', this.logger) || {};
|
|
137
142
|
try {
|
|
138
143
|
this.devServerState = new DevServerState_1.DevServerState({
|
|
139
144
|
localDevUrlMapping,
|
|
@@ -144,7 +149,7 @@ class DevModeParentInterface {
|
|
|
144
149
|
webSocketPort,
|
|
145
150
|
logger: this.logger,
|
|
146
151
|
urls: this.urls,
|
|
147
|
-
appConfig: (
|
|
152
|
+
appConfig: (_d = (_c = this.configs) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.appConfig,
|
|
148
153
|
});
|
|
149
154
|
}
|
|
150
155
|
catch (e) {
|
package/dist/lib/ast.d.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import { SourceCodeMetadata, SourceCodeChecks, Logger } from './types';
|
|
1
|
+
import { SourceCodeMetadata, SourceCodeChecks, Logger, NodeValue } from './types';
|
|
2
2
|
import { Program, Node } from 'estree';
|
|
3
|
-
type NodeValue = string | number | boolean | null | undefined | RegExp | bigint | NodeValue[] | NodeObject;
|
|
4
|
-
type NodeObject = {
|
|
5
|
-
[key: string]: NodeValue;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* This is a simple utility function to rebuild the value from a node.
|
|
9
|
-
* It'll work for simple stuff, but it's likely to fail in complicated cases.
|
|
10
|
-
* Use with caution!
|
|
11
|
-
*/
|
|
12
|
-
export declare function getValueFromNode(node: Node): NodeValue;
|
|
13
3
|
/**
|
|
14
4
|
* We only support image imports that are within the extension directory.
|
|
15
5
|
* This function will check if an image is out of bounds and collect any that are out of bounds, so we can warn the user before they run into build issues.
|
|
@@ -22,5 +12,5 @@ export declare function traverseAbstractSyntaxTree(ast: Program, checks: SourceC
|
|
|
22
12
|
importedHooks: {};
|
|
23
13
|
dependencies: never[];
|
|
24
14
|
};
|
|
15
|
+
variableDeclarations: Map<string, NodeValue>;
|
|
25
16
|
};
|
|
26
|
-
export {};
|
package/dist/lib/ast.js
CHANGED
|
@@ -4,37 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
8
|
-
exports.checkForOutOfBoundsImageImports = checkForOutOfBoundsImageImports;
|
|
9
|
-
exports.traverseAbstractSyntaxTree = traverseAbstractSyntaxTree;
|
|
7
|
+
exports.traverseAbstractSyntaxTree = exports.checkForOutOfBoundsImageImports = void 0;
|
|
10
8
|
const path_1 = __importDefault(require("path"));
|
|
11
9
|
// @ts-expect-error no type defs
|
|
12
10
|
const estraverse_1 = require("estraverse");
|
|
13
11
|
const utils_1 = require("./utils");
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
if (!node) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
return ((node.type === 'ImportSpecifier' && node.imported.name === variableName) ||
|
|
20
|
-
(node.type === 'ImportDefaultSpecifier' &&
|
|
21
|
-
node.local.name === variableName) ||
|
|
22
|
-
(node.type === 'ImportNamespaceSpecifier' &&
|
|
23
|
-
node.local.name === variableName));
|
|
24
|
-
}
|
|
25
|
-
function _isIdentifierDefined(node, parent, name) {
|
|
26
|
-
if (parent &&
|
|
27
|
-
(parent.type === 'MemberExpression' || parent.type === 'CallExpression')) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
return node.type === 'Identifier' && node.name === name;
|
|
31
|
-
}
|
|
32
|
-
function _isFunctionInvoked(node, functionName) {
|
|
33
|
-
return (node.type === 'CallExpression' &&
|
|
34
|
-
node.callee &&
|
|
35
|
-
'name' in node.callee &&
|
|
36
|
-
node.callee.name === functionName);
|
|
37
|
-
}
|
|
12
|
+
const parsing_utils_1 = require("./parsing-utils");
|
|
13
|
+
const PARSED_HOOKS = ['useCrmProperties', 'useAssociations'];
|
|
38
14
|
function _checkForFunctionMetadata(node, parent, output, functionName) {
|
|
39
15
|
if (!node) {
|
|
40
16
|
return;
|
|
@@ -42,7 +18,7 @@ function _checkForFunctionMetadata(node, parent, output, functionName) {
|
|
|
42
18
|
if (!output.functions[functionName]) {
|
|
43
19
|
output.functions[functionName] = {};
|
|
44
20
|
}
|
|
45
|
-
if (
|
|
21
|
+
if ((0, parsing_utils_1.isFunctionInvoked)(node, functionName)) {
|
|
46
22
|
output.functions[functionName].invoked = true;
|
|
47
23
|
// If the function is invoked before being defined we will assume it is a global function
|
|
48
24
|
output.functions[functionName].scope = output.functions[functionName]
|
|
@@ -50,56 +26,38 @@ function _checkForFunctionMetadata(node, parent, output, functionName) {
|
|
|
50
26
|
? 'Local'
|
|
51
27
|
: 'Global';
|
|
52
28
|
}
|
|
53
|
-
else if (
|
|
54
|
-
|
|
29
|
+
else if ((0, parsing_utils_1.isIdentifierDefined)(node, parent, functionName) ||
|
|
30
|
+
(0, parsing_utils_1.isVariableImported)(node, functionName)) {
|
|
55
31
|
output.functions[functionName].defined = true;
|
|
56
32
|
}
|
|
57
33
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
case 'NaN':
|
|
73
|
-
return NaN;
|
|
74
|
-
case 'Infinity':
|
|
75
|
-
return Infinity;
|
|
76
|
-
default:
|
|
77
|
-
return name;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
case 'ArrayExpression':
|
|
81
|
-
return node.elements.map((element) => element ? getValueFromNode(element) : null);
|
|
82
|
-
case 'ObjectExpression': {
|
|
83
|
-
const obj = {};
|
|
84
|
-
node.properties.forEach((prop) => {
|
|
85
|
-
if (prop.type === 'Property') {
|
|
86
|
-
const property = prop;
|
|
87
|
-
let key = undefined;
|
|
88
|
-
if (property.key.type === 'Identifier') {
|
|
89
|
-
key = property.key.name;
|
|
90
|
-
}
|
|
91
|
-
else if (property.key.type === 'Literal') {
|
|
92
|
-
key = String(property.key.value);
|
|
93
|
-
}
|
|
94
|
-
if (key) {
|
|
95
|
-
obj[key] = getValueFromNode(property.value);
|
|
96
|
-
}
|
|
34
|
+
function _collectVariableDeclarations(node, state) {
|
|
35
|
+
if (!node) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Handle variable declarations (const, let, var)
|
|
39
|
+
if (node.type === 'VariableDeclaration') {
|
|
40
|
+
node.declarations.forEach((declaration) => {
|
|
41
|
+
if (declaration.type === 'VariableDeclarator' &&
|
|
42
|
+
declaration.id.type === 'Identifier' &&
|
|
43
|
+
declaration.init) {
|
|
44
|
+
const variableName = declaration.id.name;
|
|
45
|
+
const result = (0, parsing_utils_1.getValueFromNode)(declaration.init, state);
|
|
46
|
+
if (result.status === 'SUCCESS') {
|
|
47
|
+
state.variableDeclarations.set(variableName, result.nodeValue);
|
|
97
48
|
}
|
|
98
|
-
}
|
|
99
|
-
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Handle assignment expressions for let variables (e.g., myVar = newValue)
|
|
53
|
+
if (node.type === 'AssignmentExpression' && node.left.type === 'Identifier') {
|
|
54
|
+
const variableName = node.left.name;
|
|
55
|
+
if (state.variableDeclarations.has(variableName)) {
|
|
56
|
+
const result = (0, parsing_utils_1.getValueFromNode)(node.right, state);
|
|
57
|
+
if (result.status === 'SUCCESS') {
|
|
58
|
+
state.variableDeclarations.set(variableName, result.nodeValue);
|
|
59
|
+
}
|
|
100
60
|
}
|
|
101
|
-
default:
|
|
102
|
-
return `Unsupported node type: ${node.type}`;
|
|
103
61
|
}
|
|
104
62
|
}
|
|
105
63
|
/**
|
|
@@ -124,6 +82,113 @@ function checkForOutOfBoundsImageImports(node, output, extensionPath) {
|
|
|
124
82
|
}
|
|
125
83
|
}
|
|
126
84
|
}
|
|
85
|
+
exports.checkForOutOfBoundsImageImports = checkForOutOfBoundsImageImports;
|
|
86
|
+
function _processCrmPropertiesHook(node, output) {
|
|
87
|
+
if (node.type !== 'CallExpression')
|
|
88
|
+
return;
|
|
89
|
+
const propertyType = 'CrmRecordProperties';
|
|
90
|
+
const propertiesNode = node.arguments[0];
|
|
91
|
+
const optionsNode = node.arguments[1];
|
|
92
|
+
const requestedProperties = [];
|
|
93
|
+
const propertiesResult = propertiesNode
|
|
94
|
+
? (0, parsing_utils_1.getValueFromNode)(propertiesNode, output)
|
|
95
|
+
: null;
|
|
96
|
+
if (propertiesResult &&
|
|
97
|
+
propertiesResult.status === 'SUCCESS' &&
|
|
98
|
+
Array.isArray(propertiesResult.nodeValue)) {
|
|
99
|
+
propertiesResult.nodeValue.forEach((val) => {
|
|
100
|
+
if (typeof val === 'string') {
|
|
101
|
+
requestedProperties.push(val);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (requestedProperties.length > 0) {
|
|
106
|
+
let options = {};
|
|
107
|
+
const optionsResult = optionsNode
|
|
108
|
+
? (0, parsing_utils_1.getValueFromNode)(optionsNode, output)
|
|
109
|
+
: null;
|
|
110
|
+
if (optionsResult &&
|
|
111
|
+
optionsResult.status === 'SUCCESS' &&
|
|
112
|
+
optionsResult.nodeValue &&
|
|
113
|
+
typeof optionsResult.nodeValue === 'object' &&
|
|
114
|
+
!Array.isArray(optionsResult.nodeValue) &&
|
|
115
|
+
!(optionsResult.nodeValue instanceof RegExp)) {
|
|
116
|
+
options = optionsResult.nodeValue;
|
|
117
|
+
}
|
|
118
|
+
output.dataDependencies.dependencies.push({
|
|
119
|
+
referenceId: (0, utils_1.generateHash)(propertyType, requestedProperties),
|
|
120
|
+
properties: {
|
|
121
|
+
type: propertyType,
|
|
122
|
+
recordProperties: requestedProperties,
|
|
123
|
+
options,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function _processAssociationsHook(node, output) {
|
|
129
|
+
if (node.type !== 'CallExpression')
|
|
130
|
+
return;
|
|
131
|
+
const propertyType = 'CrmRecordAssociationProperties';
|
|
132
|
+
const requestNode = node.arguments[0];
|
|
133
|
+
const optionsNode = node.arguments[1];
|
|
134
|
+
const requestResult = requestNode
|
|
135
|
+
? (0, parsing_utils_1.getValueFromNode)(requestNode, output)
|
|
136
|
+
: null;
|
|
137
|
+
if (!requestResult ||
|
|
138
|
+
requestResult.status === 'FAIL' ||
|
|
139
|
+
!requestResult.nodeValue ||
|
|
140
|
+
typeof requestResult.nodeValue !== 'object' ||
|
|
141
|
+
Array.isArray(requestResult.nodeValue)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const request = requestResult.nodeValue;
|
|
145
|
+
const toObjectTypeId = request.toObjectType;
|
|
146
|
+
const requestProperties = request.properties;
|
|
147
|
+
if (typeof toObjectTypeId !== 'string') {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const propertiesArray = [];
|
|
151
|
+
if (requestProperties && Array.isArray(requestProperties)) {
|
|
152
|
+
requestProperties.forEach((val) => {
|
|
153
|
+
if (typeof val === 'string') {
|
|
154
|
+
propertiesArray.push(val);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const paginationOptions = {};
|
|
159
|
+
const otherOptions = {};
|
|
160
|
+
const optionsResult = optionsNode
|
|
161
|
+
? (0, parsing_utils_1.getValueFromNode)(optionsNode, output)
|
|
162
|
+
: null;
|
|
163
|
+
if (optionsResult &&
|
|
164
|
+
optionsResult.status === 'SUCCESS' &&
|
|
165
|
+
optionsResult.nodeValue &&
|
|
166
|
+
typeof optionsResult.nodeValue === 'object' &&
|
|
167
|
+
!Array.isArray(optionsResult.nodeValue) &&
|
|
168
|
+
!(optionsResult.nodeValue instanceof RegExp)) {
|
|
169
|
+
const options = optionsResult.nodeValue;
|
|
170
|
+
Object.keys(options).forEach((key) => {
|
|
171
|
+
otherOptions[key] = options[key];
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (request.pageLength !== undefined) {
|
|
175
|
+
paginationOptions.pageLength = request.pageLength;
|
|
176
|
+
}
|
|
177
|
+
if (request.offset !== undefined) {
|
|
178
|
+
paginationOptions.offset = request.offset;
|
|
179
|
+
}
|
|
180
|
+
const sortedPropertiesForHash = [...propertiesArray].sort();
|
|
181
|
+
output.dataDependencies.dependencies.push({
|
|
182
|
+
referenceId: (0, utils_1.generateHash)(propertyType, toObjectTypeId, sortedPropertiesForHash.join('-')),
|
|
183
|
+
properties: {
|
|
184
|
+
type: propertyType,
|
|
185
|
+
toObjectTypeId,
|
|
186
|
+
requestProperties: propertiesArray,
|
|
187
|
+
paginationOptions,
|
|
188
|
+
options: otherOptions,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
}
|
|
127
192
|
/**
|
|
128
193
|
* This function collects all internal data dependencies for the extension
|
|
129
194
|
* Specifically, it collects dependencies which are using our custom hooks, eg `useCrmProperties`
|
|
@@ -137,13 +202,11 @@ function _collectDataDependencies(node, output, logger) {
|
|
|
137
202
|
if (node.type === 'ImportDeclaration' &&
|
|
138
203
|
typeof node.source.value === 'string' &&
|
|
139
204
|
node.source.value.startsWith('@hubspot/ui-extensions')) {
|
|
140
|
-
const isExperimental = node.source.value === '@hubspot/ui-extensions/experimental';
|
|
141
205
|
// If the imports are coming from our own package, loop over them to check for hooks
|
|
142
206
|
node.specifiers.forEach((specifier) => {
|
|
143
207
|
// If the specifier is an ImportSpecifier and the imported name is one of our tracked hooks, we will track it.
|
|
144
208
|
if (specifier.type === 'ImportSpecifier' &&
|
|
145
|
-
|
|
146
|
-
EXPERIMENTAL_HOOKS.includes(specifier.imported.name)) {
|
|
209
|
+
PARSED_HOOKS.includes(specifier.imported.name)) {
|
|
147
210
|
// The local name is the name the hook is imported as in the file, and the imported name is the original name of the hook.
|
|
148
211
|
output.dataDependencies.importedHooks[`${specifier.local.name}`] =
|
|
149
212
|
specifier.imported.name;
|
|
@@ -151,12 +214,10 @@ function _collectDataDependencies(node, output, logger) {
|
|
|
151
214
|
else if (
|
|
152
215
|
// We also have to track namespace level imports
|
|
153
216
|
specifier.type === 'ImportNamespaceSpecifier') {
|
|
154
|
-
// If the specifier is a namespace import, we will track all hooks that are imported from that namespace.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
});
|
|
159
|
-
}
|
|
217
|
+
// If the specifier is a namespace import, we will track all hooks that are imported from that namespace.
|
|
218
|
+
PARSED_HOOKS.forEach((hook) => {
|
|
219
|
+
output.dataDependencies.importedHooks[`${specifier.local.name}.${hook}`] = hook;
|
|
220
|
+
});
|
|
160
221
|
}
|
|
161
222
|
});
|
|
162
223
|
// Check for calls to our hooks.
|
|
@@ -179,55 +240,10 @@ function _collectDataDependencies(node, output, logger) {
|
|
|
179
240
|
}
|
|
180
241
|
// Then we handle each hook individually, as the usages and tracking format are different.
|
|
181
242
|
if (hookName === 'useCrmProperties') {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const requestedProperties = [];
|
|
187
|
-
// If the first argument is an array with at least one element, collect the properties.
|
|
188
|
-
if (propertiesNode &&
|
|
189
|
-
propertiesNode.type === 'ArrayExpression' &&
|
|
190
|
-
propertiesNode.elements.length > 0) {
|
|
191
|
-
propertiesNode.elements.forEach((element) => {
|
|
192
|
-
/**
|
|
193
|
-
* We only support strings for now, and ignore the rest.
|
|
194
|
-
* This might be more generalized in the future as we support more hooks.
|
|
195
|
-
*/
|
|
196
|
-
if (element &&
|
|
197
|
-
element.type === 'Literal' &&
|
|
198
|
-
typeof element.value === 'string') {
|
|
199
|
-
requestedProperties.push(element.value);
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
logger.warn(`Invalid property type in useCrmProperties: ${element ? element.type : 'undefined'}`);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
if (requestedProperties.length > 0) {
|
|
206
|
-
let options = {};
|
|
207
|
-
if (optionsNode) {
|
|
208
|
-
const optionsValue = getValueFromNode(optionsNode);
|
|
209
|
-
if (optionsValue !== null &&
|
|
210
|
-
optionsValue !== undefined &&
|
|
211
|
-
typeof optionsValue === 'object' &&
|
|
212
|
-
!Array.isArray(optionsValue) &&
|
|
213
|
-
!(optionsValue instanceof RegExp)) {
|
|
214
|
-
options = optionsValue;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
output.dataDependencies.dependencies.push({
|
|
218
|
-
/**
|
|
219
|
-
* This refID is a hash of the property type and the requested properties.
|
|
220
|
-
* This should allow us to create the same hash at execution time, to find the correct data from BE.
|
|
221
|
-
*/
|
|
222
|
-
referenceId: (0, utils_1.generateHash)(propertyType, requestedProperties),
|
|
223
|
-
properties: {
|
|
224
|
-
type: propertyType,
|
|
225
|
-
recordProperties: requestedProperties,
|
|
226
|
-
options,
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
243
|
+
_processCrmPropertiesHook(node, output);
|
|
244
|
+
}
|
|
245
|
+
else if (hookName === 'useAssociations') {
|
|
246
|
+
_processAssociationsHook(node, output);
|
|
231
247
|
}
|
|
232
248
|
}
|
|
233
249
|
}
|
|
@@ -245,6 +261,7 @@ function traverseAbstractSyntaxTree(ast, checks, extensionPath, logger) {
|
|
|
245
261
|
importedHooks: {},
|
|
246
262
|
dependencies: [],
|
|
247
263
|
},
|
|
264
|
+
variableDeclarations: new Map(),
|
|
248
265
|
};
|
|
249
266
|
try {
|
|
250
267
|
(0, estraverse_1.traverse)(ast, {
|
|
@@ -254,6 +271,7 @@ function traverseAbstractSyntaxTree(ast, checks, extensionPath, logger) {
|
|
|
254
271
|
_checkForFunctionMetadata(node, parent, state, check.functionName);
|
|
255
272
|
});
|
|
256
273
|
checkForOutOfBoundsImageImports(node, state, extensionPath);
|
|
274
|
+
_collectVariableDeclarations(node, state);
|
|
257
275
|
_collectDataDependencies(node, state, logger);
|
|
258
276
|
}
|
|
259
277
|
catch (e) {
|
|
@@ -268,3 +286,4 @@ function traverseAbstractSyntaxTree(ast, checks, extensionPath, logger) {
|
|
|
268
286
|
}
|
|
269
287
|
return state;
|
|
270
288
|
}
|
|
289
|
+
exports.traverseAbstractSyntaxTree = traverseAbstractSyntaxTree;
|
package/dist/lib/build.js
CHANGED
|
@@ -12,9 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.extensionErrorBaseMessage = void 0;
|
|
16
|
-
exports.buildSingleExtension = buildSingleExtension;
|
|
17
|
-
exports.remoteBuild = remoteBuild;
|
|
15
|
+
exports.remoteBuild = exports.buildSingleExtension = exports.extensionErrorBaseMessage = void 0;
|
|
18
16
|
const vite_1 = require("vite");
|
|
19
17
|
const constants_1 = require("./constants");
|
|
20
18
|
const manifestPlugin_1 = __importDefault(require("./plugins/manifestPlugin"));
|
|
@@ -24,9 +22,9 @@ const codeBlockingPlugin_1 = __importDefault(require("./plugins/codeBlockingPlug
|
|
|
24
22
|
const friendlyLoggingPlugin_1 = __importDefault(require("./plugins/friendlyLoggingPlugin"));
|
|
25
23
|
const allowedExtensions = ['.js', '.ts', '.tsx', '.jsx'];
|
|
26
24
|
exports.extensionErrorBaseMessage = `Supported file extensions are [${allowedExtensions.join(', ')}], received:`;
|
|
27
|
-
function buildSingleExtension(
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
function buildSingleExtension({ file, outputDir = constants_1.OUTPUT_DIR, emptyOutDir = true, minify = false, root = process.cwd(), // This is the vite default, so using that as our default
|
|
26
|
+
logLevel = 'info', }) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
28
|
const output = (0, utils_1.getUrlSafeFileName)(file);
|
|
31
29
|
yield (0, vite_1.build)({
|
|
32
30
|
logLevel,
|
|
@@ -53,8 +51,9 @@ function buildSingleExtension(_a) {
|
|
|
53
51
|
});
|
|
54
52
|
});
|
|
55
53
|
}
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
exports.buildSingleExtension = buildSingleExtension;
|
|
55
|
+
function remoteBuild(root, entryPoint, outputDir = constants_1.OUTPUT_DIR, logLevel) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
57
|
const fileInfo = path_1.default.parse(entryPoint);
|
|
59
58
|
if (!allowedExtensions.includes(fileInfo.ext)) {
|
|
60
59
|
throw new Error(`${exports.extensionErrorBaseMessage} ${fileInfo.ext}`);
|
|
@@ -68,3 +67,4 @@ function remoteBuild(root_1, entryPoint_1) {
|
|
|
68
67
|
});
|
|
69
68
|
});
|
|
70
69
|
}
|
|
70
|
+
exports.remoteBuild = remoteBuild;
|
package/dist/lib/config.js
CHANGED
|
@@ -5,12 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
6
|
};
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.loadConfigByPath =
|
|
9
|
-
exports.validateCardConfig = validateCardConfig;
|
|
10
|
-
exports.loadExtensionConfig = loadExtensionConfig;
|
|
11
|
-
exports.validateProxyConfigKey = validateProxyConfigKey;
|
|
12
|
-
exports.validateProxyConfigValue = validateProxyConfigValue;
|
|
13
|
-
exports.loadLocalConfig = loadLocalConfig;
|
|
8
|
+
exports.loadLocalConfig = exports.validateProxyConfigValue = exports.validateProxyConfigKey = exports.loadExtensionConfig = exports.validateCardConfig = exports.loadConfigByPath = void 0;
|
|
14
9
|
const fs_1 = __importDefault(require("fs"));
|
|
15
10
|
const path_1 = __importDefault(require("path"));
|
|
16
11
|
const utils_1 = require("./utils");
|
|
@@ -18,6 +13,7 @@ function loadConfigByPath(configPath) {
|
|
|
18
13
|
const source = fs_1.default.readFileSync(configPath).toString();
|
|
19
14
|
return JSON.parse(source);
|
|
20
15
|
}
|
|
16
|
+
exports.loadConfigByPath = loadConfigByPath;
|
|
21
17
|
function validateCardConfig(config) {
|
|
22
18
|
if (!config || typeof config !== 'object') {
|
|
23
19
|
return new Error('Card config must be an object');
|
|
@@ -54,6 +50,7 @@ function validateCardConfig(config) {
|
|
|
54
50
|
}
|
|
55
51
|
return true;
|
|
56
52
|
}
|
|
53
|
+
exports.validateCardConfig = validateCardConfig;
|
|
57
54
|
function loadExtensionConfig(appConfig, appPath) {
|
|
58
55
|
var _a, _b;
|
|
59
56
|
const crmCardsSubConfigFiles = (_b = (_a = appConfig === null || appConfig === void 0 ? void 0 : appConfig.extensions) === null || _a === void 0 ? void 0 : _a.crm) === null || _b === void 0 ? void 0 : _b.cards;
|
|
@@ -84,6 +81,7 @@ function loadExtensionConfig(appConfig, appPath) {
|
|
|
84
81
|
});
|
|
85
82
|
return outputConfig;
|
|
86
83
|
}
|
|
84
|
+
exports.loadExtensionConfig = loadExtensionConfig;
|
|
87
85
|
function validateProxyConfigKey(urlKey, logger, localConfigPath) {
|
|
88
86
|
try {
|
|
89
87
|
const url = new URL(urlKey);
|
|
@@ -95,6 +93,7 @@ function validateProxyConfigKey(urlKey, logger, localConfigPath) {
|
|
|
95
93
|
logger.warn(`The key "${urlKey}" in "${localConfigPath}" is an invalid url`);
|
|
96
94
|
}
|
|
97
95
|
}
|
|
96
|
+
exports.validateProxyConfigKey = validateProxyConfigKey;
|
|
98
97
|
function validateProxyConfigValue(value, key, logger, localConfigPath) {
|
|
99
98
|
try {
|
|
100
99
|
// eslint-disable-next-line no-new
|
|
@@ -104,6 +103,7 @@ function validateProxyConfigValue(value, key, logger, localConfigPath) {
|
|
|
104
103
|
logger.warn(`The value "${value}" for key "${key}" in "${localConfigPath}" is an invalid url`);
|
|
105
104
|
}
|
|
106
105
|
}
|
|
106
|
+
exports.validateProxyConfigValue = validateProxyConfigValue;
|
|
107
107
|
function loadLocalConfig(appPath, logger) {
|
|
108
108
|
const localConfigFilename = 'local.json';
|
|
109
109
|
const localConfigPath = path_1.default.join(appPath, localConfigFilename);
|
|
@@ -125,3 +125,4 @@ function loadLocalConfig(appPath, logger) {
|
|
|
125
125
|
return undefined;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
exports.loadLocalConfig = loadLocalConfig;
|
package/dist/lib/dev.js
CHANGED
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.startDevMode =
|
|
15
|
+
exports.startDevMode = void 0;
|
|
16
16
|
const vite_1 = require("vite");
|
|
17
17
|
const path_1 = __importDefault(require("path"));
|
|
18
18
|
const server_1 = __importDefault(require("./server"));
|
|
@@ -73,3 +73,4 @@ function startDevMode(devServerState) {
|
|
|
73
73
|
return shutdownServer;
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
|
+
exports.startDevMode = startDevMode;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Node } from 'estree';
|
|
2
|
+
import { NodeValue, SourceCodeMetadata } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts the value from a given AST node based on its type.
|
|
5
|
+
* This function handles various node types such as Literal, Identifier (aka variables), ArrayExpression,
|
|
6
|
+
* ObjectExpression, SpreadElement, TemplateLiteral, UnaryExpression, and MemberExpression (accessing props on objects).
|
|
7
|
+
* It also supports nested structures and handles special cases like undefined, NaN, and Infinity.
|
|
8
|
+
*
|
|
9
|
+
* It does not handle function calls, complex expressions, or anything that requires evaluation of code logic.
|
|
10
|
+
* This is not a full JavaScript interpreter, but rather a utility to extract static values from the AST.
|
|
11
|
+
*
|
|
12
|
+
* Use this function carefully, as it assumes that the AST is well-formed and that the node types are as expected.
|
|
13
|
+
* Many types are not yet supported. Anything this function is used for should have a backup runtime evaluation,
|
|
14
|
+
* or be set up to fail gracefully if parsing fails.
|
|
15
|
+
*
|
|
16
|
+
* @param node - The AST node from which to extract the value.
|
|
17
|
+
* @param state - The current state of the source code metadata, including variable declarations.
|
|
18
|
+
* @returns An object containing the status of the operation, the extracted node value,
|
|
19
|
+
* or an error message if the extraction fails.
|
|
20
|
+
* The status can be 'SUCCESS' or 'FAIL'.
|
|
21
|
+
* If the status is 'SUCCESS', nodeValue will contain the extracted value.
|
|
22
|
+
* If the status is 'FAIL', error will contain the error message.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getValueFromNode(node: Node, state: SourceCodeMetadata): {
|
|
25
|
+
status: 'SUCCESS' | 'FAIL';
|
|
26
|
+
nodeValue?: NodeValue;
|
|
27
|
+
error?: string;
|
|
28
|
+
};
|
|
29
|
+
export declare function isVariableImported(node: Node, variableName: string): boolean;
|
|
30
|
+
export declare function isIdentifierDefined(node: Node, parent: Node | null, name: string): boolean;
|
|
31
|
+
export declare function isFunctionInvoked(node: Node, functionName: string): boolean;
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isFunctionInvoked = exports.isIdentifierDefined = exports.isVariableImported = exports.getValueFromNode = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Extracts the value from a given AST node based on its type.
|
|
6
|
+
* This function handles various node types such as Literal, Identifier (aka variables), ArrayExpression,
|
|
7
|
+
* ObjectExpression, SpreadElement, TemplateLiteral, UnaryExpression, and MemberExpression (accessing props on objects).
|
|
8
|
+
* It also supports nested structures and handles special cases like undefined, NaN, and Infinity.
|
|
9
|
+
*
|
|
10
|
+
* It does not handle function calls, complex expressions, or anything that requires evaluation of code logic.
|
|
11
|
+
* This is not a full JavaScript interpreter, but rather a utility to extract static values from the AST.
|
|
12
|
+
*
|
|
13
|
+
* Use this function carefully, as it assumes that the AST is well-formed and that the node types are as expected.
|
|
14
|
+
* Many types are not yet supported. Anything this function is used for should have a backup runtime evaluation,
|
|
15
|
+
* or be set up to fail gracefully if parsing fails.
|
|
16
|
+
*
|
|
17
|
+
* @param node - The AST node from which to extract the value.
|
|
18
|
+
* @param state - The current state of the source code metadata, including variable declarations.
|
|
19
|
+
* @returns An object containing the status of the operation, the extracted node value,
|
|
20
|
+
* or an error message if the extraction fails.
|
|
21
|
+
* The status can be 'SUCCESS' or 'FAIL'.
|
|
22
|
+
* If the status is 'SUCCESS', nodeValue will contain the extracted value.
|
|
23
|
+
* If the status is 'FAIL', error will contain the error message.
|
|
24
|
+
*/
|
|
25
|
+
function getValueFromNode(node, state) {
|
|
26
|
+
try {
|
|
27
|
+
switch (node.type) {
|
|
28
|
+
case 'Literal':
|
|
29
|
+
return { status: 'SUCCESS', nodeValue: node.value };
|
|
30
|
+
case 'Identifier': {
|
|
31
|
+
const name = node.name;
|
|
32
|
+
switch (name) {
|
|
33
|
+
case 'undefined':
|
|
34
|
+
return { status: 'SUCCESS', nodeValue: undefined };
|
|
35
|
+
case 'NaN':
|
|
36
|
+
return { status: 'SUCCESS', nodeValue: NaN };
|
|
37
|
+
case 'Infinity':
|
|
38
|
+
return { status: 'SUCCESS', nodeValue: Infinity };
|
|
39
|
+
default:
|
|
40
|
+
if (state.variableDeclarations.has(name)) {
|
|
41
|
+
return {
|
|
42
|
+
status: 'SUCCESS',
|
|
43
|
+
nodeValue: state.variableDeclarations.get(name),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// If for some reason the variable tracking fails, return unsupported.
|
|
47
|
+
return { status: 'FAIL', error: `Identifier ${name} is not found` };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
case 'ArrayExpression': {
|
|
51
|
+
const arrayValue = [];
|
|
52
|
+
if (node.elements.length === 0) {
|
|
53
|
+
return { status: 'SUCCESS', nodeValue: arrayValue };
|
|
54
|
+
}
|
|
55
|
+
// Arrays have to be built from their elements, to handle special cases like nested arrays from spread operators.
|
|
56
|
+
for (const element of node.elements) {
|
|
57
|
+
if (typeof element === 'object' && element !== null) {
|
|
58
|
+
if (element.type === 'SpreadElement') {
|
|
59
|
+
const result = getValueFromNode(element, state);
|
|
60
|
+
if (result.status === 'FAIL') {
|
|
61
|
+
return {
|
|
62
|
+
status: 'FAIL',
|
|
63
|
+
error: `Array spread element failed: ${result.error}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const value = result.nodeValue;
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
arrayValue.push(...value);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
arrayValue.push(value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const result = getValueFromNode(element, state);
|
|
76
|
+
if (result.status === 'FAIL') {
|
|
77
|
+
return {
|
|
78
|
+
status: 'FAIL',
|
|
79
|
+
error: `Array element failed: ${result.error}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
arrayValue.push(result.nodeValue);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
arrayValue.push(element);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { status: 'SUCCESS', nodeValue: arrayValue };
|
|
90
|
+
}
|
|
91
|
+
case 'ObjectExpression': {
|
|
92
|
+
const obj = {};
|
|
93
|
+
for (const prop of node.properties) {
|
|
94
|
+
switch (prop.type) {
|
|
95
|
+
case 'Property': {
|
|
96
|
+
const property = prop;
|
|
97
|
+
let key = undefined;
|
|
98
|
+
if (property.key.type === 'Identifier') {
|
|
99
|
+
key = property.key.name;
|
|
100
|
+
}
|
|
101
|
+
else if (property.key.type === 'Literal') {
|
|
102
|
+
key = String(property.key.value);
|
|
103
|
+
}
|
|
104
|
+
if (key) {
|
|
105
|
+
const result = getValueFromNode(property.value, state);
|
|
106
|
+
if (result.status === 'FAIL') {
|
|
107
|
+
return {
|
|
108
|
+
status: 'FAIL',
|
|
109
|
+
error: `Object property '${key}' failed: ${result.error}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
obj[key] = result.nodeValue;
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case 'SpreadElement': {
|
|
117
|
+
const result = getValueFromNode(prop, state);
|
|
118
|
+
if (result.status === 'FAIL') {
|
|
119
|
+
return {
|
|
120
|
+
status: 'FAIL',
|
|
121
|
+
error: `Object spread element failed: ${result.error}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const spreadValue = result.nodeValue;
|
|
125
|
+
if (spreadValue && typeof spreadValue === 'object') {
|
|
126
|
+
Object.assign(obj, spreadValue);
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
default:
|
|
131
|
+
// Ignore unsupported property types, as we don't have a key for them.
|
|
132
|
+
// This could be a computed property or something else we don't handle.
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { status: 'SUCCESS', nodeValue: obj };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Spread elements are a bit tricky. They can be used to directly spread an array or object,
|
|
140
|
+
* or they can be used to spread a variable that is defined elsewhere. Our strategy is to return
|
|
141
|
+
* whatever element should be spread, and then handle the spreading in the parent array or object.
|
|
142
|
+
*
|
|
143
|
+
* There are also trickier cases we don't handle, like spreading a function call that returns an
|
|
144
|
+
* array or object. When the spread element is unsupported, we return a special symbol.
|
|
145
|
+
*/
|
|
146
|
+
case 'SpreadElement':
|
|
147
|
+
if (node.argument) {
|
|
148
|
+
if (node.argument.type === 'Identifier' && node.argument.name) {
|
|
149
|
+
return {
|
|
150
|
+
status: 'SUCCESS',
|
|
151
|
+
nodeValue: state.variableDeclarations.get(node.argument.name) || null,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
else if (node.argument.type === 'ArrayExpression' ||
|
|
155
|
+
node.argument.type === 'ObjectExpression') {
|
|
156
|
+
return getValueFromNode(node.argument, state);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
status: 'FAIL',
|
|
161
|
+
error: `Unsupported SpreadElement type: ${node.argument.type}`,
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Template literals are built of an alternating sequence of static
|
|
165
|
+
* strings and expressions. We will concatenate the static strings and
|
|
166
|
+
* evaluate the expressions to build the final string.
|
|
167
|
+
*/
|
|
168
|
+
case 'TemplateLiteral': {
|
|
169
|
+
let result = '';
|
|
170
|
+
if (node.expressions && node.quasis) {
|
|
171
|
+
const { quasis, expressions } = node;
|
|
172
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
173
|
+
// Prefer cooked value if available, otherwise use raw.
|
|
174
|
+
result += quasis[i].value.cooked || quasis[i].value.raw;
|
|
175
|
+
if (i < expressions.length) {
|
|
176
|
+
const expression = expressions[i];
|
|
177
|
+
const expressionResult = getValueFromNode(expression, state);
|
|
178
|
+
if (expressionResult.status === 'SUCCESS') {
|
|
179
|
+
const expressionValue = expressionResult.nodeValue;
|
|
180
|
+
if (expressionValue === null ||
|
|
181
|
+
expressionValue === undefined ||
|
|
182
|
+
typeof expressionValue === 'string' ||
|
|
183
|
+
typeof expressionValue === 'number' ||
|
|
184
|
+
typeof expressionValue === 'boolean') {
|
|
185
|
+
result += String(expressionValue);
|
|
186
|
+
}
|
|
187
|
+
else if (Array.isArray(expressionValue)) {
|
|
188
|
+
result += expressionValue.join(',');
|
|
189
|
+
}
|
|
190
|
+
else if (typeof expressionValue === 'object') {
|
|
191
|
+
result += '[object Object]';
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
result += `Unsupported TemplateLiteral expression value type: ${typeof expressionValue}`;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
result += expressionResult.error;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return { status: 'SUCCESS', nodeValue: result };
|
|
204
|
+
}
|
|
205
|
+
case 'UnaryExpression': {
|
|
206
|
+
const argResult = getValueFromNode(node.argument, state);
|
|
207
|
+
if (argResult.status === 'FAIL') {
|
|
208
|
+
return argResult;
|
|
209
|
+
}
|
|
210
|
+
const arg = argResult.nodeValue;
|
|
211
|
+
switch (node.operator) {
|
|
212
|
+
case '-':
|
|
213
|
+
return {
|
|
214
|
+
status: 'SUCCESS',
|
|
215
|
+
nodeValue: typeof arg === 'number' ? -arg : NaN,
|
|
216
|
+
};
|
|
217
|
+
case '+':
|
|
218
|
+
return {
|
|
219
|
+
status: 'SUCCESS',
|
|
220
|
+
nodeValue: typeof arg === 'number' ? +arg : NaN,
|
|
221
|
+
};
|
|
222
|
+
case '!':
|
|
223
|
+
return { status: 'SUCCESS', nodeValue: !arg };
|
|
224
|
+
case 'typeof':
|
|
225
|
+
return { status: 'SUCCESS', nodeValue: typeof arg };
|
|
226
|
+
default:
|
|
227
|
+
return {
|
|
228
|
+
status: 'FAIL',
|
|
229
|
+
error: `Unsupported unary operator: ${node.operator}`,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Member expressions are used to access properties of objects.
|
|
234
|
+
case 'MemberExpression': {
|
|
235
|
+
if (node.property.type === 'Identifier' && node.property.name) {
|
|
236
|
+
// We have to recursively get the value of the object, due to the way that nested objects are parsed.
|
|
237
|
+
const objectResult = getValueFromNode(node.object, state);
|
|
238
|
+
if (objectResult.status === 'FAIL') {
|
|
239
|
+
return objectResult;
|
|
240
|
+
}
|
|
241
|
+
const objectData = objectResult.nodeValue;
|
|
242
|
+
if (objectData &&
|
|
243
|
+
typeof objectData === 'object' &&
|
|
244
|
+
!Array.isArray(objectData) &&
|
|
245
|
+
!(objectData instanceof RegExp)) {
|
|
246
|
+
return {
|
|
247
|
+
status: 'SUCCESS',
|
|
248
|
+
nodeValue: objectData[node.property.name],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
status: 'FAIL',
|
|
254
|
+
error: `Unsupported MemberExpression property type: ${node.property.type}`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
default:
|
|
258
|
+
return { status: 'FAIL', error: `Unsupported node type: ${node.type}` };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
status: 'FAIL',
|
|
264
|
+
error: error instanceof Error ? error.message : String(error),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
exports.getValueFromNode = getValueFromNode;
|
|
269
|
+
function isVariableImported(node, variableName) {
|
|
270
|
+
if (!node) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
return ((node.type === 'ImportSpecifier' && node.imported.name === variableName) ||
|
|
274
|
+
(node.type === 'ImportDefaultSpecifier' &&
|
|
275
|
+
node.local.name === variableName) ||
|
|
276
|
+
(node.type === 'ImportNamespaceSpecifier' &&
|
|
277
|
+
node.local.name === variableName));
|
|
278
|
+
}
|
|
279
|
+
exports.isVariableImported = isVariableImported;
|
|
280
|
+
function isIdentifierDefined(node, parent, name) {
|
|
281
|
+
if (parent &&
|
|
282
|
+
(parent.type === 'MemberExpression' || parent.type === 'CallExpression')) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
return node.type === 'Identifier' && node.name === name;
|
|
286
|
+
}
|
|
287
|
+
exports.isIdentifierDefined = isIdentifierDefined;
|
|
288
|
+
function isFunctionInvoked(node, functionName) {
|
|
289
|
+
return (node.type === 'CallExpression' &&
|
|
290
|
+
node.callee &&
|
|
291
|
+
'name' in node.callee &&
|
|
292
|
+
node.callee.name === functionName);
|
|
293
|
+
}
|
|
294
|
+
exports.isFunctionInvoked = isFunctionInvoked;
|
|
@@ -6,7 +6,7 @@ const ast_1 = require("../ast");
|
|
|
6
6
|
const codeBlockingPlugin = ({ logger, extensionPath }) => {
|
|
7
7
|
return {
|
|
8
8
|
name: 'ui-extensions-code-blocking-plugin',
|
|
9
|
-
enforce: 'post',
|
|
9
|
+
enforce: 'post',
|
|
10
10
|
transform(code, filename) {
|
|
11
11
|
if ((0, utils_1.isNodeModule)(filename)) {
|
|
12
12
|
return { code, map: null }; // We don't want to parse node modules
|
|
@@ -18,6 +18,7 @@ const codeBlockingPlugin = ({ logger, extensionPath }) => {
|
|
|
18
18
|
importedHooks: {},
|
|
19
19
|
dependencies: [],
|
|
20
20
|
},
|
|
21
|
+
variableDeclarations: new Map(),
|
|
21
22
|
};
|
|
22
23
|
const requireFunctionName = 'require';
|
|
23
24
|
try {
|
|
@@ -17,23 +17,13 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
17
17
|
}) : function(o, v) {
|
|
18
18
|
o["default"] = v;
|
|
19
19
|
});
|
|
20
|
-
var __importStar = (this && this.__importStar) ||
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return ownKeys(o);
|
|
28
|
-
};
|
|
29
|
-
return function (mod) {
|
|
30
|
-
if (mod && mod.__esModule) return mod;
|
|
31
|
-
var result = {};
|
|
32
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
-
__setModuleDefault(result, mod);
|
|
34
|
-
return result;
|
|
35
|
-
};
|
|
36
|
-
})();
|
|
20
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
21
|
+
if (mod && mod.__esModule) return mod;
|
|
22
|
+
var result = {};
|
|
23
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
24
|
+
__setModuleDefault(result, mod);
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
37
27
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
38
28
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
39
29
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -78,7 +68,7 @@ const devBuildPlugin = (options) => {
|
|
|
78
68
|
} }));
|
|
79
69
|
}
|
|
80
70
|
};
|
|
81
|
-
const devBuild = (
|
|
71
|
+
const devBuild = (server, extensionMetadata, emptyOutDir = false) => __awaiter(void 0, void 0, void 0, function* () {
|
|
82
72
|
try {
|
|
83
73
|
const { config: extensionConfig } = extensionMetadata;
|
|
84
74
|
const { extensionPath } = extensionConfig;
|
|
@@ -161,7 +151,7 @@ const devBuildPlugin = (options) => {
|
|
|
161
151
|
yield devBuild(localServer, devServerState.extensionsMetadata[i], i === 0);
|
|
162
152
|
}
|
|
163
153
|
}),
|
|
164
|
-
handleHotUpdate: (
|
|
154
|
+
handleHotUpdate: ({ file, server }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
165
155
|
// If the file is not in the relevantModules list, it's update is inconsequential
|
|
166
156
|
const extensionsToRebuild = devServerState.extensionsMetadata.filter((metadata) => {
|
|
167
157
|
const { config } = metadata;
|
|
@@ -17,7 +17,7 @@ const manifestPlugin = (options) => {
|
|
|
17
17
|
let allDataDependencies;
|
|
18
18
|
return {
|
|
19
19
|
name: 'ui-extensions-manifest-generation-plugin',
|
|
20
|
-
enforce: 'post',
|
|
20
|
+
enforce: 'post',
|
|
21
21
|
buildStart() {
|
|
22
22
|
// Reset the source metadata for the new build
|
|
23
23
|
allDataDependencies = [];
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRelevantModules =
|
|
3
|
+
exports.getRelevantModules = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
5
|
const relevantModules = {};
|
|
6
6
|
function getRelevantModules(output) {
|
|
7
7
|
return relevantModules[output] || [];
|
|
8
8
|
}
|
|
9
|
+
exports.getRelevantModules = getRelevantModules;
|
|
9
10
|
const relevantModulesPlugin = ({ output, logger }) => {
|
|
10
11
|
return {
|
|
11
12
|
name: 'ui-extensions-relevant-modules-plugin',
|
package/dist/lib/server.js
CHANGED
|
@@ -31,9 +31,9 @@ function listen(app, port) {
|
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
function startDevServer(
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
function startDevServer({ devServerState, viteDevServer, }) {
|
|
35
|
+
var _a;
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
37
|
const app = (0, express_1.default)();
|
|
38
38
|
// Setup middleware
|
|
39
39
|
app.use((0, cors_1.default)());
|
|
@@ -75,7 +75,7 @@ function startDevServer(_a) {
|
|
|
75
75
|
}
|
|
76
76
|
throw new Error(e);
|
|
77
77
|
}
|
|
78
|
-
(
|
|
78
|
+
(_a = devServerState.extensionsMetadata) === null || _a === void 0 ? void 0 : _a.forEach((metadata) => {
|
|
79
79
|
const { baseMessage } = metadata;
|
|
80
80
|
devServerState.logger.debug(`Listening at ${baseMessage.callback}`);
|
|
81
81
|
});
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { PLATFORM_VERSION, PRIVATE_APP, PUBLIC_APP } from './constants';
|
|
2
2
|
import { LocalDevUrlMapping } from '@hubspot/app-functions-dev-server';
|
|
3
|
-
import { PromptModule } from 'inquirer';
|
|
4
3
|
export interface ObjectTypes {
|
|
5
4
|
name: string;
|
|
6
5
|
}
|
|
@@ -201,13 +200,27 @@ export interface FunctionMetadata {
|
|
|
201
200
|
export type DataDependency = {
|
|
202
201
|
referenceId: string;
|
|
203
202
|
properties: {
|
|
204
|
-
type:
|
|
203
|
+
type: 'CrmRecordProperties';
|
|
205
204
|
recordProperties: string[];
|
|
206
205
|
options: {
|
|
207
206
|
[key: string]: any;
|
|
208
207
|
};
|
|
208
|
+
} | {
|
|
209
|
+
type: 'CrmRecordAssociationProperties';
|
|
210
|
+
toObjectTypeId: string;
|
|
211
|
+
requestProperties: string[];
|
|
212
|
+
paginationOptions: {
|
|
213
|
+
[key: string]: any;
|
|
214
|
+
};
|
|
215
|
+
options: {
|
|
216
|
+
[key: string]: any;
|
|
217
|
+
};
|
|
209
218
|
};
|
|
210
219
|
};
|
|
220
|
+
export type NodeValue = string | number | boolean | null | undefined | RegExp | bigint | symbol | NodeValue[] | NodeObject;
|
|
221
|
+
export type NodeObject = {
|
|
222
|
+
[key: string]: NodeValue;
|
|
223
|
+
};
|
|
211
224
|
export interface SourceCodeMetadata {
|
|
212
225
|
functions: {
|
|
213
226
|
[functionName: string]: FunctionMetadata;
|
|
@@ -219,6 +232,7 @@ export interface SourceCodeMetadata {
|
|
|
219
232
|
};
|
|
220
233
|
dependencies: DataDependency[];
|
|
221
234
|
};
|
|
235
|
+
variableDeclarations: Map<string, NodeValue>;
|
|
222
236
|
}
|
|
223
237
|
export interface FunctionInvocationCheck {
|
|
224
238
|
functionName: string;
|
|
@@ -246,7 +260,6 @@ export interface DevModeStartArguments {
|
|
|
246
260
|
}
|
|
247
261
|
export interface DevModeBaseSetupArguments {
|
|
248
262
|
onUploadRequired?: VoidFunction;
|
|
249
|
-
promptUser: PromptModule;
|
|
250
263
|
logger: Logger;
|
|
251
264
|
urls: {
|
|
252
265
|
api: string;
|
package/dist/lib/utils.js
CHANGED
|
@@ -3,17 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.UnhandledPlatformVersionError = void 0;
|
|
7
|
-
exports.getUrlSafeFileName = getUrlSafeFileName;
|
|
8
|
-
exports.stripAnsiColorCodes = stripAnsiColorCodes;
|
|
9
|
-
exports.loadManifest = loadManifest;
|
|
10
|
-
exports.buildSourceId = buildSourceId;
|
|
11
|
-
exports.isNodeModule = isNodeModule;
|
|
12
|
-
exports.isExtensionFile = isExtensionFile;
|
|
13
|
-
exports.throwUnhandledPlatformVersionError = throwUnhandledPlatformVersionError;
|
|
14
|
-
exports.extractAllowedUrls = extractAllowedUrls;
|
|
15
|
-
exports.generateHash = generateHash;
|
|
16
|
-
exports.isImage = isImage;
|
|
6
|
+
exports.isImage = exports.generateHash = exports.extractAllowedUrls = exports.throwUnhandledPlatformVersionError = exports.UnhandledPlatformVersionError = exports.isExtensionFile = exports.isNodeModule = exports.buildSourceId = exports.loadManifest = exports.stripAnsiColorCodes = exports.getUrlSafeFileName = void 0;
|
|
17
7
|
const path_1 = __importDefault(require("path"));
|
|
18
8
|
const fs_1 = __importDefault(require("fs"));
|
|
19
9
|
const constants_1 = require("./constants");
|
|
@@ -21,6 +11,7 @@ function getUrlSafeFileName(filePath) {
|
|
|
21
11
|
const { name } = path_1.default.parse(filePath);
|
|
22
12
|
return encodeURIComponent(`${name}.js`);
|
|
23
13
|
}
|
|
14
|
+
exports.getUrlSafeFileName = getUrlSafeFileName;
|
|
24
15
|
// Strips ANSI color codes out of strings because we don't want to pass them to the browser
|
|
25
16
|
function stripAnsiColorCodes(stringWithColorCodes) {
|
|
26
17
|
if (!stringWithColorCodes) {
|
|
@@ -30,6 +21,7 @@ function stripAnsiColorCodes(stringWithColorCodes) {
|
|
|
30
21
|
// eslint-disable-next-line no-control-regex
|
|
31
22
|
/[\u001b][[]*([0-9]{1,4};?)*[m]/g, '');
|
|
32
23
|
}
|
|
24
|
+
exports.stripAnsiColorCodes = stripAnsiColorCodes;
|
|
33
25
|
function loadManifest(outputDir, output) {
|
|
34
26
|
try {
|
|
35
27
|
return JSON.parse(fs_1.default
|
|
@@ -40,12 +32,14 @@ function loadManifest(outputDir, output) {
|
|
|
40
32
|
return {};
|
|
41
33
|
}
|
|
42
34
|
}
|
|
35
|
+
exports.loadManifest = loadManifest;
|
|
43
36
|
function buildSourceId(appConfig, extensionConfig) {
|
|
44
37
|
if (appConfig.uid && extensionConfig.data.uid) {
|
|
45
38
|
return `${appConfig.uid}::${extensionConfig.data.uid}`;
|
|
46
39
|
}
|
|
47
40
|
return null;
|
|
48
41
|
}
|
|
42
|
+
exports.buildSourceId = buildSourceId;
|
|
49
43
|
function isNodeModule(filepath) {
|
|
50
44
|
if (!filepath) {
|
|
51
45
|
return false;
|
|
@@ -53,6 +47,7 @@ function isNodeModule(filepath) {
|
|
|
53
47
|
const directory = path_1.default.parse(filepath).dir;
|
|
54
48
|
return directory.includes('node_modules');
|
|
55
49
|
}
|
|
50
|
+
exports.isNodeModule = isNodeModule;
|
|
56
51
|
/**
|
|
57
52
|
* Check if a given file is within the extension path
|
|
58
53
|
*/
|
|
@@ -72,6 +67,7 @@ function isExtensionFile(filepath, extensionPath) {
|
|
|
72
67
|
return false;
|
|
73
68
|
}
|
|
74
69
|
}
|
|
70
|
+
exports.isExtensionFile = isExtensionFile;
|
|
75
71
|
class UnhandledPlatformVersionError extends Error {
|
|
76
72
|
constructor(platformVersion) {
|
|
77
73
|
super(`Unsupported platform version "${platformVersion}"`);
|
|
@@ -81,12 +77,14 @@ exports.UnhandledPlatformVersionError = UnhandledPlatformVersionError;
|
|
|
81
77
|
function throwUnhandledPlatformVersionError(platformVersion) {
|
|
82
78
|
throw new UnhandledPlatformVersionError(platformVersion);
|
|
83
79
|
}
|
|
80
|
+
exports.throwUnhandledPlatformVersionError = throwUnhandledPlatformVersionError;
|
|
84
81
|
function extractAllowedUrls(appConfig) {
|
|
85
82
|
if (!appConfig || !('allowedUrls' in appConfig) || !appConfig.allowedUrls) {
|
|
86
83
|
return [];
|
|
87
84
|
}
|
|
88
85
|
return appConfig.allowedUrls;
|
|
89
86
|
}
|
|
87
|
+
exports.extractAllowedUrls = extractAllowedUrls;
|
|
90
88
|
function simpleHash(input) {
|
|
91
89
|
let hash = 0;
|
|
92
90
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -122,9 +120,11 @@ function generateHash(...args) {
|
|
|
122
120
|
return '';
|
|
123
121
|
}
|
|
124
122
|
}
|
|
123
|
+
exports.generateHash = generateHash;
|
|
125
124
|
/**
|
|
126
125
|
* Check if a given URL is an image (of a type we support)
|
|
127
126
|
*/
|
|
128
127
|
function isImage(url) {
|
|
129
128
|
return /\.(png|jpg|jpeg|gif|svg|webp|avif|raw|url|inline)$/.test(url);
|
|
130
129
|
}
|
|
130
|
+
exports.isImage = isImage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/ui-extensions-dev-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"bin": {
|
|
6
6
|
"uie": "./dist/lib/bin/cli.js"
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"optional": true
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "8344193a13ab5874924b02d67413dad052558ecf"
|
|
74
74
|
}
|