biome-plugin-suitescript 0.1.1 → 0.3.0
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/README.md +157 -27
- package/biome-manifest.json +261 -7
- package/configs/all.json +29 -0
- package/configs/minimal.json +14 -0
- package/configs/recommended.json +20 -0
- package/dist/cli/analyze.js +33 -3
- package/dist/lib/define.js +35 -5
- package/dist/lib/headers.js +12 -0
- package/dist/lib/module-calls.js +65 -0
- package/dist/lib/module-script-types.js +76 -0
- package/dist/lib/options.js +35 -0
- package/dist/lib/required-options.js +14 -0
- package/dist/lib/script-side.js +83 -0
- package/dist/lib/script-types.js +37 -14
- package/dist/lib/suiteql.js +16 -0
- package/dist/lib/suitescript.js +23 -0
- package/dist/lib/typings-data.js +4327 -0
- package/dist/lib/typings.js +2 -0
- package/dist/rules/logRequireDetails.js +4 -0
- package/dist/rules/logRequireTitle.js +1 -0
- package/dist/rules/noAuthorizationHeaderInInternalRequest.js +24 -0
- package/dist/rules/noBeforeSubmitRecordReload.js +19 -0
- package/dist/rules/noBlockedHttpsHeader.js +32 -0
- package/dist/rules/noBlockedResponseHeader.js +35 -0
- package/dist/rules/noBrowserGlobals.js +25 -0
- package/dist/rules/noClientLog.js +14 -0
- package/dist/rules/noConflictingClientScriptProps.js +36 -0
- package/dist/rules/noDynamicRequire.js +23 -0
- package/dist/rules/noDynamicSuiteQL.js +29 -0
- package/dist/rules/noEmptyEntryPoints.js +19 -0
- package/dist/rules/noExtraDeps.js +16 -0
- package/dist/rules/noExtraParams.js +17 -0
- package/dist/rules/noGlobalShadowing.js +38 -0
- package/dist/rules/noHardcodedAuthPasswords.js +27 -0
- package/dist/rules/noHardcodedSecrets.js +43 -0
- package/dist/rules/noHeaderUnderscores.js +23 -0
- package/dist/rules/noInnerHtml.js +41 -0
- package/dist/rules/noInsecureCookie.js +27 -0
- package/dist/rules/noInsecureHttpsUrl.js +20 -0
- package/dist/rules/noInvalidDefine.js +47 -0
- package/dist/rules/noInvalidEnumMember.js +24 -0
- package/dist/rules/noLocationHeader.js +20 -0
- package/dist/rules/noLogModule.js +8 -2
- package/dist/rules/noMapReduceSearchResults.js +33 -0
- package/dist/rules/noMissingModules.js +29 -0
- package/dist/rules/noModuleScopeApiCalls.js +49 -0
- package/dist/rules/noMultipleDefine.js +14 -0
- package/dist/rules/noNativeIterators.js +19 -0
- package/dist/rules/noPositionalOptions.js +26 -0
- package/dist/rules/noPostMessageWildcard.js +15 -0
- package/dist/rules/noPublicFileUpload.js +20 -0
- package/dist/rules/noQueryColumnFieldAndFormula.js +19 -0
- package/dist/rules/noRecordInLoop.js +34 -0
- package/dist/rules/noRequireInsteadOfDefine.js +25 -0
- package/dist/rules/noSecretKeyGuidAndSecret.js +16 -0
- package/dist/rules/noSensitiveBrowserStorage.js +24 -0
- package/dist/rules/noStackInResponse.js +21 -0
- package/dist/rules/noSuiteQLSelectStar.js +18 -0
- package/dist/rules/noSuiteQLSystemNoteJoin.js +19 -0
- package/dist/rules/noSuiteQLTypeInSearch.js +41 -0
- package/dist/rules/noSuiteScript1Api.js +84 -0
- package/dist/rules/noUnknownModuleMember.js +23 -0
- package/dist/rules/noUnknownOptions.js +31 -0
- package/dist/rules/noUnsupportedServerWidgetFieldType.js +40 -0
- package/dist/rules/noWeakHash.js +17 -0
- package/dist/rules/noWildcardCors.js +16 -0
- package/dist/rules/noWrongScriptTypeModules.js +30 -0
- package/dist/rules/requireClientValidateReturn.js +27 -0
- package/dist/rules/requireCustpagePrefix.js +23 -0
- package/dist/rules/requireEachReturn.js +38 -0
- package/dist/rules/requireLogModule.js +25 -0
- package/dist/rules/requireOptions.js +26 -0
- package/dist/rules/requireOrderByForPagedSuiteQL.js +17 -0
- package/dist/rules/requireQueryOptions.js +53 -0
- package/dist/rules/requireServerResponseOptions.js +33 -0
- package/dist/rules/requireServerWidgetOptions.js +37 -0
- package/package.json +3 -1
- package/dist/rules/noExtraModules.js +0 -23
package/biome-manifest.json
CHANGED
|
@@ -3,30 +3,122 @@
|
|
|
3
3
|
"configs": [
|
|
4
4
|
{
|
|
5
5
|
"suitescript2": "./configs/suitescript2.json"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"minimal": "./configs/minimal.json"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"recommended": "./configs/recommended.json"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"all": "./configs/all.json"
|
|
6
15
|
}
|
|
7
16
|
],
|
|
8
17
|
"plugins": {
|
|
9
18
|
"presets": {
|
|
10
19
|
"all": [
|
|
11
20
|
"noAmdName",
|
|
12
|
-
"
|
|
21
|
+
"noExtraDeps",
|
|
22
|
+
"noExtraParams",
|
|
23
|
+
"noInvalidDefine",
|
|
13
24
|
"noInvalidModules",
|
|
14
25
|
"noModuleExtensions",
|
|
26
|
+
"noMultipleDefine",
|
|
27
|
+
"noRequireInsteadOfDefine",
|
|
28
|
+
"noDynamicRequire",
|
|
15
29
|
"moduleVars",
|
|
16
30
|
"logRequireTitle",
|
|
31
|
+
"entryPoints",
|
|
32
|
+
"noMissingModules",
|
|
33
|
+
"noGlobalShadowing",
|
|
34
|
+
"noDynamicSuiteQL",
|
|
35
|
+
"noSuiteScript1Api",
|
|
36
|
+
"noModuleScopeApiCalls",
|
|
37
|
+
"noNativeIterators",
|
|
38
|
+
"noWrongScriptTypeModules",
|
|
39
|
+
"noBrowserGlobals",
|
|
40
|
+
"noInsecureHttpsUrl",
|
|
41
|
+
"noBeforeSubmitRecordReload",
|
|
42
|
+
"noEmptyEntryPoints",
|
|
43
|
+
"requireCustpagePrefix",
|
|
44
|
+
"noHeaderUnderscores",
|
|
45
|
+
"noQueryColumnFieldAndFormula",
|
|
46
|
+
"requireClientValidateReturn",
|
|
47
|
+
"noPostMessageWildcard",
|
|
48
|
+
"noInnerHtml",
|
|
49
|
+
"noWildcardCors",
|
|
50
|
+
"noSuiteQLTypeInSearch",
|
|
51
|
+
"requireEachReturn",
|
|
52
|
+
"noAuthorizationHeaderInInternalRequest",
|
|
53
|
+
"noBlockedResponseHeader",
|
|
54
|
+
"noBlockedHttpsHeader",
|
|
55
|
+
"requireOptions",
|
|
56
|
+
"noPositionalOptions",
|
|
57
|
+
"noUnknownModuleMember",
|
|
58
|
+
"requireServerWidgetOptions",
|
|
59
|
+
"requireQueryOptions",
|
|
60
|
+
"requireServerResponseOptions",
|
|
61
|
+
"noConflictingClientScriptProps",
|
|
62
|
+
"noUnsupportedServerWidgetFieldType",
|
|
63
|
+
"noHardcodedAuthPasswords",
|
|
64
|
+
"noSecretKeyGuidAndSecret",
|
|
65
|
+
"requireOrderByForPagedSuiteQL",
|
|
17
66
|
"logRequireDetails",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
67
|
+
"noUnknownOptions",
|
|
68
|
+
"noInvalidEnumMember",
|
|
69
|
+
"requireLogModule",
|
|
70
|
+
"noRecordInLoop",
|
|
71
|
+
"noMapReduceSearchResults",
|
|
72
|
+
"noClientLog"
|
|
20
73
|
],
|
|
21
|
-
"minimal": ["
|
|
74
|
+
"minimal": ["noExtraDeps", "noExtraParams", "noInvalidModules"],
|
|
22
75
|
"recommended": [
|
|
23
76
|
"noAmdName",
|
|
24
|
-
"
|
|
77
|
+
"noExtraDeps",
|
|
78
|
+
"noExtraParams",
|
|
79
|
+
"noInvalidDefine",
|
|
25
80
|
"noInvalidModules",
|
|
26
81
|
"noModuleExtensions",
|
|
82
|
+
"noMultipleDefine",
|
|
83
|
+
"noRequireInsteadOfDefine",
|
|
84
|
+
"noDynamicRequire",
|
|
27
85
|
"moduleVars",
|
|
28
86
|
"logRequireTitle",
|
|
29
|
-
"
|
|
87
|
+
"entryPoints",
|
|
88
|
+
"noMissingModules",
|
|
89
|
+
"noGlobalShadowing",
|
|
90
|
+
"noDynamicSuiteQL",
|
|
91
|
+
"noSuiteScript1Api",
|
|
92
|
+
"noModuleScopeApiCalls",
|
|
93
|
+
"noNativeIterators",
|
|
94
|
+
"noWrongScriptTypeModules",
|
|
95
|
+
"noBrowserGlobals",
|
|
96
|
+
"noInsecureHttpsUrl",
|
|
97
|
+
"noBeforeSubmitRecordReload",
|
|
98
|
+
"noEmptyEntryPoints",
|
|
99
|
+
"requireCustpagePrefix",
|
|
100
|
+
"noHeaderUnderscores",
|
|
101
|
+
"noQueryColumnFieldAndFormula",
|
|
102
|
+
"requireClientValidateReturn",
|
|
103
|
+
"noPostMessageWildcard",
|
|
104
|
+
"noInnerHtml",
|
|
105
|
+
"noWildcardCors",
|
|
106
|
+
"noSuiteQLTypeInSearch",
|
|
107
|
+
"requireEachReturn",
|
|
108
|
+
"noAuthorizationHeaderInInternalRequest",
|
|
109
|
+
"noBlockedResponseHeader",
|
|
110
|
+
"noBlockedHttpsHeader",
|
|
111
|
+
"requireOptions",
|
|
112
|
+
"noPositionalOptions",
|
|
113
|
+
"noUnknownModuleMember",
|
|
114
|
+
"requireServerWidgetOptions",
|
|
115
|
+
"requireQueryOptions",
|
|
116
|
+
"requireServerResponseOptions",
|
|
117
|
+
"noConflictingClientScriptProps",
|
|
118
|
+
"noUnsupportedServerWidgetFieldType",
|
|
119
|
+
"noHardcodedAuthPasswords",
|
|
120
|
+
"noSecretKeyGuidAndSecret",
|
|
121
|
+
"requireOrderByForPagedSuiteQL"
|
|
30
122
|
]
|
|
31
123
|
},
|
|
32
124
|
"rules": [
|
|
@@ -46,16 +138,178 @@
|
|
|
46
138
|
"noAmdName": "./dist/rules/noAmdName.grit"
|
|
47
139
|
},
|
|
48
140
|
{
|
|
49
|
-
"
|
|
141
|
+
"noAuthorizationHeaderInInternalRequest": "./dist/rules/noAuthorizationHeaderInInternalRequest.js"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"noBeforeSubmitRecordReload": "./dist/rules/noBeforeSubmitRecordReload.js"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"noBlockedHttpsHeader": "./dist/rules/noBlockedHttpsHeader.js"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"noBlockedResponseHeader": "./dist/rules/noBlockedResponseHeader.js"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"noBrowserGlobals": "./dist/rules/noBrowserGlobals.js"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"noClientLog": "./dist/rules/noClientLog.js"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"noConflictingClientScriptProps": "./dist/rules/noConflictingClientScriptProps.js"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"noDynamicRequire": "./dist/rules/noDynamicRequire.js"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"noDynamicSuiteQL": "./dist/rules/noDynamicSuiteQL.js"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"noEmptyEntryPoints": "./dist/rules/noEmptyEntryPoints.js"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"noExtraDeps": "./dist/rules/noExtraDeps.js"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"noExtraParams": "./dist/rules/noExtraParams.js"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"noGlobalShadowing": "./dist/rules/noGlobalShadowing.js"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"noHardcodedAuthPasswords": "./dist/rules/noHardcodedAuthPasswords.js"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"noHardcodedSecrets": "./dist/rules/noHardcodedSecrets.js"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"noHeaderUnderscores": "./dist/rules/noHeaderUnderscores.js"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"noInnerHtml": "./dist/rules/noInnerHtml.js"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"noInsecureCookie": "./dist/rules/noInsecureCookie.js"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"noInsecureHttpsUrl": "./dist/rules/noInsecureHttpsUrl.js"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"noInvalidDefine": "./dist/rules/noInvalidDefine.js"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"noInvalidEnumMember": "./dist/rules/noInvalidEnumMember.js"
|
|
50
202
|
},
|
|
51
203
|
{
|
|
52
204
|
"noInvalidModules": "./dist/rules/noInvalidModules.js"
|
|
53
205
|
},
|
|
206
|
+
{
|
|
207
|
+
"noLocationHeader": "./dist/rules/noLocationHeader.js"
|
|
208
|
+
},
|
|
54
209
|
{
|
|
55
210
|
"noLogModule": "./dist/rules/noLogModule.js"
|
|
56
211
|
},
|
|
212
|
+
{
|
|
213
|
+
"noMapReduceSearchResults": "./dist/rules/noMapReduceSearchResults.js"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"noMissingModules": "./dist/rules/noMissingModules.js"
|
|
217
|
+
},
|
|
57
218
|
{
|
|
58
219
|
"noModuleExtensions": "./dist/rules/noModuleExtensions.grit"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"noModuleScopeApiCalls": "./dist/rules/noModuleScopeApiCalls.js"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"noMultipleDefine": "./dist/rules/noMultipleDefine.js"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"noNativeIterators": "./dist/rules/noNativeIterators.js"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"noPositionalOptions": "./dist/rules/noPositionalOptions.js"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"noPostMessageWildcard": "./dist/rules/noPostMessageWildcard.js"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"noPublicFileUpload": "./dist/rules/noPublicFileUpload.js"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"noQueryColumnFieldAndFormula": "./dist/rules/noQueryColumnFieldAndFormula.js"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"noRecordInLoop": "./dist/rules/noRecordInLoop.js"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"noRequireInsteadOfDefine": "./dist/rules/noRequireInsteadOfDefine.js"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"noSecretKeyGuidAndSecret": "./dist/rules/noSecretKeyGuidAndSecret.js"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"noSensitiveBrowserStorage": "./dist/rules/noSensitiveBrowserStorage.js"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"noStackInResponse": "./dist/rules/noStackInResponse.js"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"noSuiteQLSelectStar": "./dist/rules/noSuiteQLSelectStar.js"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"noSuiteQLSystemNoteJoin": "./dist/rules/noSuiteQLSystemNoteJoin.js"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"noSuiteQLTypeInSearch": "./dist/rules/noSuiteQLTypeInSearch.js"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"noSuiteScript1Api": "./dist/rules/noSuiteScript1Api.js"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"noUnknownModuleMember": "./dist/rules/noUnknownModuleMember.js"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"noUnknownOptions": "./dist/rules/noUnknownOptions.js"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"noUnsupportedServerWidgetFieldType": "./dist/rules/noUnsupportedServerWidgetFieldType.js"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"noWeakHash": "./dist/rules/noWeakHash.js"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"noWildcardCors": "./dist/rules/noWildcardCors.js"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"noWrongScriptTypeModules": "./dist/rules/noWrongScriptTypeModules.js"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"requireClientValidateReturn": "./dist/rules/requireClientValidateReturn.js"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"requireCustpagePrefix": "./dist/rules/requireCustpagePrefix.js"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"requireEachReturn": "./dist/rules/requireEachReturn.js"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"requireLogModule": "./dist/rules/requireLogModule.js"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"requireOptions": "./dist/rules/requireOptions.js"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"requireOrderByForPagedSuiteQL": "./dist/rules/requireOrderByForPagedSuiteQL.js"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"requireQueryOptions": "./dist/rules/requireQueryOptions.js"
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"requireServerResponseOptions": "./dist/rules/requireServerResponseOptions.js"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"requireServerWidgetOptions": "./dist/rules/requireServerWidgetOptions.js"
|
|
59
313
|
}
|
|
60
314
|
]
|
|
61
315
|
},
|
package/configs/all.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"javascript": {
|
|
3
|
+
"globals": ["define", "require", "log", "util"]
|
|
4
|
+
},
|
|
5
|
+
"linter": {
|
|
6
|
+
"rules": {
|
|
7
|
+
"correctness": {
|
|
8
|
+
"noUnusedFunctionParameters": "off"
|
|
9
|
+
},
|
|
10
|
+
"nursery": {
|
|
11
|
+
"noImpliedEval": "error",
|
|
12
|
+
"useIncludes": "warn"
|
|
13
|
+
},
|
|
14
|
+
"preset": "recommended",
|
|
15
|
+
"security": {
|
|
16
|
+
"noGlobalEval": "error"
|
|
17
|
+
},
|
|
18
|
+
"style": {
|
|
19
|
+
"useConst": "warn",
|
|
20
|
+
"useForOf": "warn",
|
|
21
|
+
"useTemplate": "warn"
|
|
22
|
+
},
|
|
23
|
+
"suspicious": {
|
|
24
|
+
"noVar": "warn"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"plugins": ["biome-plugin-suitescript/presets/all"]
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"javascript": {
|
|
3
|
+
"globals": ["define", "require", "log", "util"]
|
|
4
|
+
},
|
|
5
|
+
"linter": {
|
|
6
|
+
"rules": {
|
|
7
|
+
"correctness": {
|
|
8
|
+
"noUnusedFunctionParameters": "off"
|
|
9
|
+
},
|
|
10
|
+
"preset": "recommended"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"plugins": ["biome-plugin-suitescript/presets/minimal"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"javascript": {
|
|
3
|
+
"globals": ["define", "require", "log", "util"]
|
|
4
|
+
},
|
|
5
|
+
"linter": {
|
|
6
|
+
"rules": {
|
|
7
|
+
"correctness": {
|
|
8
|
+
"noUnusedFunctionParameters": "off"
|
|
9
|
+
},
|
|
10
|
+
"nursery": {
|
|
11
|
+
"noImpliedEval": "error"
|
|
12
|
+
},
|
|
13
|
+
"preset": "recommended",
|
|
14
|
+
"security": {
|
|
15
|
+
"noGlobalEval": "error"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"plugins": ["biome-plugin-suitescript/presets/recommended"]
|
|
20
|
+
}
|
package/dist/cli/analyze.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Node-only analysis of a single SuiteScript source file (ESTree via oxc-parser).
|
|
2
2
|
import { parseSync, } from "oxc-parser";
|
|
3
3
|
import { declaredProblems, inferredProblems, inferScriptType, typeByName, } from "../lib/inference.js";
|
|
4
|
+
import { misplacedModule, sideOf, unsupportedModule, } from "../lib/module-script-types.js";
|
|
4
5
|
const API_VERSION = "2.1";
|
|
5
6
|
const UPGRADABLE = new Set(["1.0", "2.0", "2.x"]);
|
|
6
7
|
function isCallback(node) {
|
|
@@ -97,6 +98,7 @@ function exportedNames(node) {
|
|
|
97
98
|
}
|
|
98
99
|
function inspectProgram(program) {
|
|
99
100
|
let isScript = false;
|
|
101
|
+
const modules = [];
|
|
100
102
|
const returned = [];
|
|
101
103
|
let opaque = false;
|
|
102
104
|
// Only trust `returned` when an inline define() callback or ES syntax was seen;
|
|
@@ -106,8 +108,11 @@ function inspectProgram(program) {
|
|
|
106
108
|
if (node.type === "ImportDeclaration" ||
|
|
107
109
|
node.type === "ExportNamedDeclaration")
|
|
108
110
|
known = true;
|
|
109
|
-
if (node.type === "ImportDeclaration" &&
|
|
111
|
+
if (node.type === "ImportDeclaration" &&
|
|
112
|
+
/^N(\/|$)/.test(node.source.value)) {
|
|
110
113
|
isScript = true;
|
|
114
|
+
modules.push(node.source.value);
|
|
115
|
+
}
|
|
111
116
|
if (node.type === "ExportNamedDeclaration")
|
|
112
117
|
returned.push(...exportedNames(node));
|
|
113
118
|
if (node.type === "ExpressionStatement" &&
|
|
@@ -115,6 +120,14 @@ function inspectProgram(program) {
|
|
|
115
120
|
const call = node.expression;
|
|
116
121
|
if (call.callee.type === "Identifier" && call.callee.name === "define") {
|
|
117
122
|
isScript = true;
|
|
123
|
+
const dependencies = call.arguments.at(-2);
|
|
124
|
+
if (dependencies?.type === "ArrayExpression") {
|
|
125
|
+
for (const element of dependencies.elements) {
|
|
126
|
+
if (element?.type === "Literal" &&
|
|
127
|
+
typeof element.value === "string")
|
|
128
|
+
modules.push(element.value);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
118
131
|
const callback = call.arguments.at(-1);
|
|
119
132
|
if (isCallback(callback)) {
|
|
120
133
|
const names = amdReturnedNames(callback);
|
|
@@ -132,7 +145,11 @@ function inspectProgram(program) {
|
|
|
132
145
|
}
|
|
133
146
|
}
|
|
134
147
|
}
|
|
135
|
-
return {
|
|
148
|
+
return {
|
|
149
|
+
isScript,
|
|
150
|
+
modules,
|
|
151
|
+
returned: opaque || !known ? undefined : returned,
|
|
152
|
+
};
|
|
136
153
|
}
|
|
137
154
|
function findTag(comments, name) {
|
|
138
155
|
const pattern = new RegExp(`${name}(?:[ \\t]+(\\S+))?`);
|
|
@@ -182,7 +199,7 @@ export function analyzeSource(filename, source) {
|
|
|
182
199
|
}
|
|
183
200
|
const apiVersion = findTag(parsed.comments, "@NApiVersion");
|
|
184
201
|
const scriptType = findTag(parsed.comments, "@NScriptType");
|
|
185
|
-
const { isScript, returned } = inspectProgram(parsed.program);
|
|
202
|
+
const { isScript, modules, returned } = inspectProgram(parsed.program);
|
|
186
203
|
const inferred = isScript && returned ? inferScriptType(returned) : undefined;
|
|
187
204
|
// Not a script: no tags and nothing that implies an entry point.
|
|
188
205
|
if (!apiVersion && !scriptType && !inferred)
|
|
@@ -223,5 +240,18 @@ export function analyzeSource(filename, source) {
|
|
|
223
240
|
for (const message of problems)
|
|
224
241
|
report("entryPoints", message, scriptType?.offset ?? 0);
|
|
225
242
|
}
|
|
243
|
+
// The declared type wins; otherwise fall back to what the entry points imply.
|
|
244
|
+
const declaredType = declared ? typeByName(declared) : undefined;
|
|
245
|
+
const side = sideOf(declaredType ? [declaredType] : (inferred?.types ?? []));
|
|
246
|
+
const single = declaredType ??
|
|
247
|
+
(inferred?.types.length === 1 ? inferred.types[0] : undefined);
|
|
248
|
+
if (side || single) {
|
|
249
|
+
for (const module of modules) {
|
|
250
|
+
const message = (side && misplacedModule(side, module)) ||
|
|
251
|
+
(single && unsupportedModule(single.name, module));
|
|
252
|
+
if (message)
|
|
253
|
+
report("modules", message, scriptType?.offset ?? 0);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
226
256
|
return { diagnostics, upgrade };
|
|
227
257
|
}
|
package/dist/lib/define.js
CHANGED
|
@@ -8,11 +8,38 @@ export function stringValue(node) {
|
|
|
8
8
|
return undefined;
|
|
9
9
|
return node.text.slice(1, -1);
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* The array literal a variable is initialised with, for `var dependencies = [...]`
|
|
13
|
+
* followed by `define(dependencies, ...)`. The first matching declaration in the
|
|
14
|
+
* file wins; a variable that is not an array literal is not resolved.
|
|
15
|
+
*/
|
|
16
|
+
function declaredArray(from, name) {
|
|
17
|
+
const root = [...from.ancestors()].at(-1);
|
|
18
|
+
const visit = (node) => {
|
|
19
|
+
if (node.kind === "JS_VARIABLE_DECLARATOR") {
|
|
20
|
+
const children = node.children();
|
|
21
|
+
const id = children.find((c) => c.kind === "JS_IDENTIFIER_BINDING");
|
|
22
|
+
const init = children.find((c) => c.kind === "JS_INITIALIZER_CLAUSE");
|
|
23
|
+
const value = init?.children()[0];
|
|
24
|
+
if (id?.text === name && value?.kind === "JS_ARRAY_EXPRESSION") {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (const child of node.children()) {
|
|
29
|
+
const found = visit(child);
|
|
30
|
+
if (found)
|
|
31
|
+
return found;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
};
|
|
35
|
+
return root ? visit(root) : undefined;
|
|
36
|
+
}
|
|
11
37
|
/**
|
|
12
38
|
* Parses an AMD `define([...], function (...) {})` call.
|
|
13
39
|
*
|
|
14
|
-
* Returns undefined unless `call` is `define(...)` with a dependency array
|
|
15
|
-
* followed by a function callback (the
|
|
40
|
+
* Returns undefined unless `call` is `define(...)` with a dependency array (a
|
|
41
|
+
* literal, or a variable initialised with one) followed by a function callback (the
|
|
42
|
+
* optional leading module id is allowed).
|
|
16
43
|
*/
|
|
17
44
|
export function parseDefine(call) {
|
|
18
45
|
if (call.callee?.text !== "define")
|
|
@@ -20,11 +47,14 @@ export function parseDefine(call) {
|
|
|
20
47
|
const args = call.arguments?.children()[0]?.children() ?? [];
|
|
21
48
|
if (args.length < 2 || args.length > 3)
|
|
22
49
|
return undefined;
|
|
23
|
-
const
|
|
50
|
+
const given = args[args.length - 2];
|
|
24
51
|
const callback = args[args.length - 1];
|
|
25
|
-
if (!
|
|
52
|
+
if (!given || !callback)
|
|
26
53
|
return undefined;
|
|
27
|
-
|
|
54
|
+
const deps = given.kind === "JS_IDENTIFIER_EXPRESSION"
|
|
55
|
+
? declaredArray(call, given.text)
|
|
56
|
+
: given;
|
|
57
|
+
if (deps?.kind !== "JS_ARRAY_EXPRESSION")
|
|
28
58
|
return undefined;
|
|
29
59
|
if (!FUNCTION_KINDS.includes(callback.kind))
|
|
30
60
|
return undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { optionsObject, propertyValue, stringValue } from "./options.js";
|
|
2
|
+
/** The header name and value nodes of `x.setHeader({ name, value })` or `addHeader`. */
|
|
3
|
+
export function headerCall(call) {
|
|
4
|
+
if (!/\.(setHeader|addHeader)$/.test(call.callee?.text ?? ""))
|
|
5
|
+
return undefined;
|
|
6
|
+
const options = optionsObject(call);
|
|
7
|
+
const nameNode = options && propertyValue(options, "name");
|
|
8
|
+
const name = stringValue(nameNode)?.toLowerCase();
|
|
9
|
+
if (!options || !nameNode || !name)
|
|
10
|
+
return undefined;
|
|
11
|
+
return { name, nameNode, value: propertyValue(options, "value") };
|
|
12
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { dependencies } from "./biome-modules.js";
|
|
2
|
+
import { parseDefine, stringValue } from "./define.js";
|
|
3
|
+
import { isFunction } from "./script-side.js";
|
|
4
|
+
import { TYPINGS } from "./typings-data.js";
|
|
5
|
+
const has = (object, key) => Object.hasOwn(object, key);
|
|
6
|
+
/**
|
|
7
|
+
* The N/ module a receiver expression (`record` in `record.load`) is bound to by a
|
|
8
|
+
* define() callback parameter or an import. A local variable or parameter of the
|
|
9
|
+
* same name shadows it, and a global resolves to nothing.
|
|
10
|
+
*/
|
|
11
|
+
export function moduleOfReceiver(receiver, model) {
|
|
12
|
+
if (receiver.kind !== "JS_IDENTIFIER_EXPRESSION")
|
|
13
|
+
return undefined;
|
|
14
|
+
const reference = receiver.children()[0];
|
|
15
|
+
if (reference?.kind !== "JS_REFERENCE_IDENTIFIER")
|
|
16
|
+
return undefined;
|
|
17
|
+
const declaration = model.binding(reference)?.syntax();
|
|
18
|
+
if (!declaration)
|
|
19
|
+
return undefined;
|
|
20
|
+
const nearestFunction = declaration.ancestors().find(isFunction);
|
|
21
|
+
for (const ancestor of declaration.ancestors()) {
|
|
22
|
+
if (ancestor.kind === "JS_IMPORT") {
|
|
23
|
+
return dependencies(ancestor).find((d) => d.param?.text === declaration.text)?.name;
|
|
24
|
+
}
|
|
25
|
+
if (ancestor.kind === "JS_CALL_EXPRESSION") {
|
|
26
|
+
const def = parseDefine(ancestor);
|
|
27
|
+
if (def && nearestFunction?.text === def.callback.text) {
|
|
28
|
+
const index = def.params.findIndex((p) => p?.text === declaration.text);
|
|
29
|
+
return index >= 0 ? stringValue(def.elements[index]) : undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/** The generated data for a module, if there is any. */
|
|
36
|
+
export function typingsOf(module) {
|
|
37
|
+
return module && has(TYPINGS, module) ? TYPINGS[module] : undefined;
|
|
38
|
+
}
|
|
39
|
+
/** A call to a function of a loaded N/ module that the type definitions describe. */
|
|
40
|
+
export function moduleCall(call, model) {
|
|
41
|
+
let callee = call.callee;
|
|
42
|
+
if (callee?.kind !== "JS_STATIC_MEMBER_EXPRESSION")
|
|
43
|
+
return undefined;
|
|
44
|
+
if (callee.children()[1]?.text === "promise") {
|
|
45
|
+
const inner = callee.children()[0];
|
|
46
|
+
if (inner?.kind !== "JS_STATIC_MEMBER_EXPRESSION")
|
|
47
|
+
return undefined;
|
|
48
|
+
callee = inner;
|
|
49
|
+
}
|
|
50
|
+
const [object, member] = callee.children();
|
|
51
|
+
if (!object || !member)
|
|
52
|
+
return undefined;
|
|
53
|
+
const module = moduleOfReceiver(object, model);
|
|
54
|
+
const typings = typingsOf(module);
|
|
55
|
+
if (!module || !typings || !has(typings.functions, member.text)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
alternatives: typings.functions[member.text],
|
|
60
|
+
callee: callee.text,
|
|
61
|
+
fn: member.text,
|
|
62
|
+
module,
|
|
63
|
+
typings,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Which side of NetSuite a script type runs on, and the N/ modules that only
|
|
2
|
+
// work on one side. From the "Supported Script Types" column of Oracle's SuiteScript
|
|
3
|
+
// module reference; loading a module on the wrong side fails at runtime.
|
|
4
|
+
// N/ui/message is not listed although the table marks it client-only. No agent
|
|
5
|
+
// skill requires it to be client-only: the SAFE guide's complete Suitelet sample
|
|
6
|
+
// (references/appendices/appendix-ncache-sample.md) loads it and passes
|
|
7
|
+
// message.Type to Form.addPageInitMessage. The type definitions accept a message
|
|
8
|
+
// there too (N/ui/serverWidget.d.ts). And Oracle's Form.addPageInitMessage page
|
|
9
|
+
// (Suitelets and user event beforeLoad) and FAQ sample build the message on the
|
|
10
|
+
// server. Only show() and hide() need a browser.
|
|
11
|
+
// Pure logic shared by the Biome rules and the CLI.
|
|
12
|
+
export const CLIENT_ONLY_MODULES = new Set([
|
|
13
|
+
"N/currentRecord",
|
|
14
|
+
"N/portlet",
|
|
15
|
+
"N/ui/dialog",
|
|
16
|
+
]);
|
|
17
|
+
export const SERVER_ONLY_MODULES = new Set([
|
|
18
|
+
"N/auth",
|
|
19
|
+
"N/cache",
|
|
20
|
+
"N/certificateControl",
|
|
21
|
+
"N/compress",
|
|
22
|
+
"N/config",
|
|
23
|
+
"N/crypto",
|
|
24
|
+
"N/crypto/certificate",
|
|
25
|
+
"N/dataset",
|
|
26
|
+
"N/documentCapture",
|
|
27
|
+
"N/encode",
|
|
28
|
+
"N/error",
|
|
29
|
+
"N/file",
|
|
30
|
+
"N/https/clientCertificate",
|
|
31
|
+
"N/keyControl",
|
|
32
|
+
"N/llm",
|
|
33
|
+
"N/machineTranslation",
|
|
34
|
+
"N/pgp",
|
|
35
|
+
"N/piremoval",
|
|
36
|
+
"N/plugin",
|
|
37
|
+
"N/redirect",
|
|
38
|
+
"N/render",
|
|
39
|
+
"N/sftp",
|
|
40
|
+
"N/task",
|
|
41
|
+
"N/task/accounting/recognition",
|
|
42
|
+
"N/ui/serverWidget",
|
|
43
|
+
"N/workbook",
|
|
44
|
+
"N/workflow",
|
|
45
|
+
]);
|
|
46
|
+
/** The side shared by every candidate script type, or undefined when unknown or mixed. */
|
|
47
|
+
export function sideOf(types) {
|
|
48
|
+
if (types.length === 0)
|
|
49
|
+
return undefined;
|
|
50
|
+
const clients = types.filter((t) => t.name === "ClientScript").length;
|
|
51
|
+
if (clients === types.length)
|
|
52
|
+
return "client";
|
|
53
|
+
return clients === 0 ? "server" : undefined;
|
|
54
|
+
}
|
|
55
|
+
/** A message when `module` cannot be loaded by a script on `side`. */
|
|
56
|
+
export function misplacedModule(side, module) {
|
|
57
|
+
if (side === "server" && CLIENT_ONLY_MODULES.has(module))
|
|
58
|
+
return `${module} is only available in client scripts.`;
|
|
59
|
+
if (side === "client" && SERVER_ONLY_MODULES.has(module))
|
|
60
|
+
return `${module} is only available in server scripts.`;
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const CUSTOM_TOOL_UNSUPPORTED = new Set([
|
|
64
|
+
"N/http",
|
|
65
|
+
"N/https",
|
|
66
|
+
"N/llm",
|
|
67
|
+
"N/sftp",
|
|
68
|
+
]);
|
|
69
|
+
/** A message when a single script type cannot load `module` at all. */
|
|
70
|
+
export function unsupportedModule(scriptType, module) {
|
|
71
|
+
if (scriptType === "CustomTool" && CUSTOM_TOOL_UNSUPPORTED.has(module))
|
|
72
|
+
return `${module} is not supported in custom tool scripts.`;
|
|
73
|
+
if (scriptType === "BundleInstallationScript" && !/^N(\/|$)/.test(module))
|
|
74
|
+
return "Custom modules are not supported in bundle installation scripts.";
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|