@servicenow/eslint-plugin-sdk-app-plugin 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +16 -0
- package/README.md +22 -0
- package/lib/configs/recommended.js +17 -0
- package/lib/index.js +14 -0
- package/lib/rules/no-promise.js +43 -0
- package/lib/rules/no-unsupported-node-builtins.js +37 -0
- package/lib/util/utility.js +45 -0
- package/package.json +37 -0
- package/tests/rules/no-promise.test.js +26 -0
- package/tests/rules/no-unsupported-node-builtins.test.js +52 -0
package/.eslintrc.js
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @servicenow/eslint-plugin-sdk-app-plugin
|
|
2
|
+
|
|
3
|
+
Plugin to disallow Browser and Node.js APIs not supported in rhino engine
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install && npm i -g .
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Add `@servicenow/sdk-app-plugin` to the plugins section and update the extends array with "plugin:sdk-app-plugin/recommended" as shown below in your `.eslintrc` configuration file.
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"plugins": ["@servicenow/sdk-app-plugin"],
|
|
18
|
+
"extends": ["plugin:@servicenow/sdk-app-plugin/recommended"]
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Refer to [ServiceNow ](https://docs.servicenow.com/bundle/washingtondc-api-reference/page/script/sdk/concept/servicenow-sdk.html) docs for more information
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { getRestrictedGlobals } = require('../util/utility')
|
|
2
|
+
const restrictedGlobals = getRestrictedGlobals()
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
plugins:['@servicenow/sdk-app-plugin'],
|
|
6
|
+
rules:{
|
|
7
|
+
'@servicenow/sdk-app-plugin/file-extension-in-import':['error','always'],
|
|
8
|
+
'no-restricted-globals':['error',...restrictedGlobals],
|
|
9
|
+
'@servicenow/sdk-app-plugin/no-promise':'error',
|
|
10
|
+
'@servicenow/sdk-app-plugin/no-async-functions': 'error',
|
|
11
|
+
'@servicenow/sdk-app-plugin/no-dynamic-import': 'error',
|
|
12
|
+
'@servicenow/sdk-app-plugin/no-regexp-lookbehind-assertions': 'error',
|
|
13
|
+
'@servicenow/sdk-app-plugin/no-regexp-unicode-property-escapes': 'error',
|
|
14
|
+
'no-console': 'error',
|
|
15
|
+
'@servicenow/sdk-app-plugin/no-unsupported-node-builtins': 'error'
|
|
16
|
+
}
|
|
17
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
configs:{
|
|
3
|
+
'recommended':require('./configs/recommended')
|
|
4
|
+
},
|
|
5
|
+
rules:{
|
|
6
|
+
'file-extension-in-import':require('eslint-plugin-n/lib/rules/file-extension-in-import'),
|
|
7
|
+
'no-async-functions':require('eslint-plugin-es-x/lib/rules/no-async-functions'),
|
|
8
|
+
'no-promise':require('./rules/no-promise'),
|
|
9
|
+
'no-dynamic-import': require('eslint-plugin-es-x/lib/rules/no-dynamic-import'),
|
|
10
|
+
'no-regexp-lookbehind-assertions': require('eslint-plugin-es-x/lib/rules/no-regexp-lookbehind-assertions'),
|
|
11
|
+
'no-regexp-unicode-property-escapes': require('eslint-plugin-es-x/lib/rules/no-regexp-unicode-property-escapes'),
|
|
12
|
+
'no-unsupported-node-builtins': require('./rules/no-unsupported-node-builtins')
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const PROMISE_STATIC_METHODS = {
|
|
2
|
+
all: true,
|
|
3
|
+
allSettled: true,
|
|
4
|
+
any: true,
|
|
5
|
+
race: true,
|
|
6
|
+
reject: true,
|
|
7
|
+
resolve: true,
|
|
8
|
+
withResolvers: true,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
meta: {
|
|
13
|
+
docs: {
|
|
14
|
+
description: 'disallow the `Promise` class.',
|
|
15
|
+
category: 'ES2015',
|
|
16
|
+
recommended: false
|
|
17
|
+
},
|
|
18
|
+
fixable: null,
|
|
19
|
+
messages: {
|
|
20
|
+
forbidden: 'ES2015 Promise class is not supported in now platform.'
|
|
21
|
+
},
|
|
22
|
+
schema:[],
|
|
23
|
+
type:'problem',
|
|
24
|
+
},
|
|
25
|
+
create(context) {
|
|
26
|
+
return {
|
|
27
|
+
CallExpression(node) {
|
|
28
|
+
if(node.callee.type === 'MemberExpression' &&
|
|
29
|
+
node.callee.object.name === 'Promise' &&
|
|
30
|
+
node.callee.object.type === 'Identifier' &&
|
|
31
|
+
PROMISE_STATIC_METHODS[node.callee.property.name]) {
|
|
32
|
+
context.report({context,node, messageId:'forbidden'})
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
NewExpression(node) {
|
|
37
|
+
if(node.callee.name === 'Promise') {
|
|
38
|
+
context.report({context,node, messageId:'forbidden'})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { createTrackMap } = require('../util/utility')
|
|
2
|
+
const { ReferenceTracker } = require('@eslint-community/eslint-utils')
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
meta: {
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'disallow unsupported Node.js built-in APIs',
|
|
8
|
+
recommended: true
|
|
9
|
+
},
|
|
10
|
+
fixable: null,
|
|
11
|
+
messages: {
|
|
12
|
+
forbidden: 'The {{name}} Node.js API is not supported in now platform.'
|
|
13
|
+
},
|
|
14
|
+
schema:[],
|
|
15
|
+
type:'problem',
|
|
16
|
+
},
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
"Program:exit"(node){
|
|
20
|
+
const sourceCode = context.sourceCode
|
|
21
|
+
const tracker = new ReferenceTracker(sourceCode.getScope(node), { mode: 'legacy' })
|
|
22
|
+
const trackMap = createTrackMap(false)
|
|
23
|
+
const globalsTrackMap = createTrackMap(true)
|
|
24
|
+
|
|
25
|
+
const references = [
|
|
26
|
+
...tracker.iterateCjsReferences(trackMap),
|
|
27
|
+
...tracker.iterateEsmReferences(trackMap),
|
|
28
|
+
...tracker.iterateGlobalReferences(globalsTrackMap)
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
for(const { node, info } of references) {
|
|
32
|
+
context.report({ node, messageId: 'forbidden', data: info })
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const globals = require('globals')
|
|
2
|
+
const { READ } = require('@eslint-community/eslint-utils')
|
|
3
|
+
|
|
4
|
+
const globalsAllowList = []
|
|
5
|
+
const BROWSER_API_WARNING = 'Web APIs are not supported by the now platform'
|
|
6
|
+
const NO_GLOBAL_THIS = 'ES2020 `globalThis` variable is not supported by the now platform'
|
|
7
|
+
|
|
8
|
+
const getRestrictedGlobals = () => {
|
|
9
|
+
const globalRules = [{name:'globalThis', message: NO_GLOBAL_THIS}]
|
|
10
|
+
const browserRules = Object.keys(globals.browser)
|
|
11
|
+
.filter((key) => !globalsAllowList.includes(key))
|
|
12
|
+
.map((key) => {
|
|
13
|
+
return {
|
|
14
|
+
name: key,
|
|
15
|
+
message: BROWSER_API_WARNING,
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
return globalRules.concat(browserRules)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getCoreNodeModules = () => ["assert","buffer","child_process","cluster","crypto","dgram","dns","domain","events","freelist","fs","http","https","module","net","os","path","punycode","querystring","readline","repl","smalloc","stream","string_decoder","sys","timers","tls","tracing","tty","url","util","vm","zlib"]
|
|
22
|
+
|
|
23
|
+
const getNodeGlobals = () => Object.keys(globals.nodeBuiltin)
|
|
24
|
+
|
|
25
|
+
const createTrackMap = (isNodeGlobals) => {
|
|
26
|
+
const trackMapItems = isNodeGlobals ? getNodeGlobals() : getCoreNodeModules()
|
|
27
|
+
const trackMap = {}
|
|
28
|
+
|
|
29
|
+
for(const item of trackMapItems) {
|
|
30
|
+
trackMap[item] = {
|
|
31
|
+
[READ] : {
|
|
32
|
+
name: item
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return trackMap
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
getRestrictedGlobals,
|
|
42
|
+
createTrackMap,
|
|
43
|
+
getCoreNodeModules,
|
|
44
|
+
getNodeGlobals
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@servicenow/eslint-plugin-sdk-app-plugin",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Plugin to disallow Browser and Node.js APIs not supported in rhino engine",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"eslint",
|
|
7
|
+
"eslintplugin",
|
|
8
|
+
"eslint-plugin"
|
|
9
|
+
],
|
|
10
|
+
"author": "",
|
|
11
|
+
"main": "./lib/index.js",
|
|
12
|
+
"exports": "./lib/index.js",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"lint": "npm-run-all \"lint:*\"",
|
|
15
|
+
"lint:js": "eslint .",
|
|
16
|
+
"test": "mocha tests --recursive"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@eslint-community/eslint-utils": "4.4.0",
|
|
20
|
+
"eslint": "8.50.0",
|
|
21
|
+
"eslint-plugin-n": "16.3.1",
|
|
22
|
+
"eslint-plugin-es-x": "7.2.0",
|
|
23
|
+
"eslint-plugin-eslint-plugin": "5.0.0",
|
|
24
|
+
"globals": "13.23.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"mocha": "10.0.0",
|
|
28
|
+
"npm-run-all": "4.1.5"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": "^14.17.0 || ^16.0.0 || >= 18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"eslint": ">=8"
|
|
35
|
+
},
|
|
36
|
+
"license": "ISC"
|
|
37
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
const noPromise = require('../../lib/rules/no-promise');
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester({
|
|
5
|
+
parserOptions: { ecmaVersion: 2015 }
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const errorMessages = [{ message: 'ES2015 Promise class is not supported in now platform.' }]
|
|
9
|
+
|
|
10
|
+
ruleTester.run(
|
|
11
|
+
'no-promise',
|
|
12
|
+
noPromise,
|
|
13
|
+
{
|
|
14
|
+
valid: [{
|
|
15
|
+
code: "const Promise = 'value';",
|
|
16
|
+
}],
|
|
17
|
+
invalid: [{
|
|
18
|
+
code: 'const p = new Promise()',
|
|
19
|
+
errors: errorMessages,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
code: 'Promise.all()',
|
|
23
|
+
errors: errorMessages
|
|
24
|
+
}],
|
|
25
|
+
}
|
|
26
|
+
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
const noUnsupportedNodeBuiltins = require('../../lib/rules/no-unsupported-node-builtins');
|
|
3
|
+
const { getCoreNodeModules, getNodeGlobals } = require('../../lib/util/utility');
|
|
4
|
+
|
|
5
|
+
const ruleTester = new RuleTester({
|
|
6
|
+
parserOptions: { sourceType: 'module' },
|
|
7
|
+
env: {node: true, es6: true}
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const getInvalidsForNoUnsupportedNodeBuiltsRule = () => {
|
|
11
|
+
const invalids = []
|
|
12
|
+
const nodeModules = getCoreNodeModules()
|
|
13
|
+
const nodeGlobals = getNodeGlobals()
|
|
14
|
+
|
|
15
|
+
for(const module of nodeModules) {
|
|
16
|
+
invalids.push({
|
|
17
|
+
code: `const ${module} = require('${module}')`,
|
|
18
|
+
errors: [{ message: `The ${module} Node.js API is not supported in now platform.` }]
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for(const module of nodeModules) {
|
|
23
|
+
invalids.push({
|
|
24
|
+
code: `import ${module} from '${module}'`,
|
|
25
|
+
errors: [{ message: `The ${module} Node.js API is not supported in now platform.` }]
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for(const global of nodeGlobals) {
|
|
30
|
+
invalids.push({
|
|
31
|
+
code: `const x = ${global}`,
|
|
32
|
+
errors: [{ message: `The ${global} Node.js API is not supported in now platform.` }]
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return invalids
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ruleTester.run(
|
|
40
|
+
'no-unsupported-node-builtins',
|
|
41
|
+
noUnsupportedNodeBuiltins,
|
|
42
|
+
{
|
|
43
|
+
valid: [{
|
|
44
|
+
code: "const fs = {'Dir':'cool'}; const x = fs.Dir",
|
|
45
|
+
},{
|
|
46
|
+
code: "const fs = {readFileSync: function(){}}; fs.readFileSync()"
|
|
47
|
+
},{
|
|
48
|
+
code: "const Buffer = {from: function(){}}; Buffer.from()"
|
|
49
|
+
}],
|
|
50
|
+
invalid: getInvalidsForNoUnsupportedNodeBuiltsRule()
|
|
51
|
+
}
|
|
52
|
+
);
|