-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathno-unknown-wire-adapters.js
126 lines (113 loc) · 4.65 KB
/
no-unknown-wire-adapters.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
'use strict';
const { Minimatch } = require('minimatch');
const { docUrl } = require('../util/doc-url');
module.exports = {
meta: {
docs: {
description: 'restrict usage of unknown wire adapters',
category: 'LWC',
url: docUrl('no-unknown-wire-adapters'),
},
schema: [
{
type: 'object',
required: ['adapters'],
properties: {
adapters: {
type: 'array',
items: {
type: 'object',
required: ['module', 'identifier'],
properties: {
module: {
type: 'string',
},
identifier: {
type: 'string',
},
},
},
},
},
additionalProperties: false,
},
],
},
create(context) {
const knownAdapters = context.options[0].adapters.map((adapter) => {
return {
module: new Minimatch(adapter.module),
identifier: new Minimatch(adapter.identifier),
};
});
return {
Decorator(node) {
const { expression } = node;
// Checking if the @wire decorator is valid is already covered by "valid-wire"
// linting rule
if (
expression.type !== 'CallExpression' ||
expression.callee.type !== 'Identifier' ||
expression.callee.name !== 'wire'
) {
return;
}
// Checking if the wire adapter is an identifier is already covered by "valid-wire"
// linting rule
const [adapterNode] = expression.arguments;
if (!adapterNode || adapterNode.type !== 'Identifier') {
return;
}
const adapterName = adapterNode.name;
// Let's resolve the reference to the wire adapter identifier in the current scope.
const scope = context.getScope();
const adapterVariable = scope.references.find(
(r) => r.identifier === adapterNode,
).resolved;
if (!adapterVariable) {
return context.report({
node: adapterNode,
message: `"${adapterName}" is not a known adapter.`,
});
}
// Check if the adapter declaration is an import identifier.
const adapterDeclarationNode = adapterVariable.identifiers[0];
if (
adapterDeclarationNode.parent.type !== 'ImportSpecifier' &&
adapterDeclarationNode.parent.type !== 'ImportDefaultSpecifier'
) {
return context.report({
node: adapterNode,
message: `"${adapterName}" is not a known adapter.`,
});
}
// Extract the imported modules information.
const adapterModule = adapterDeclarationNode.parent.parent.source.value;
const importedAdapterIdentifier =
adapterDeclarationNode.parent.type === 'ImportSpecifier'
? adapterDeclarationNode.parent.imported.name
: 'default';
// Finally check if the imported identifier originates from a known module.
const isKnownAdapter = knownAdapters.some((adapter) => {
return (
adapter.module.match(adapterModule) &&
adapter.identifier.match(importedAdapterIdentifier)
);
});
if (!isKnownAdapter) {
const localAdapterIdentifier = adapterDeclarationNode.parent.local.name;
return context.report({
node: adapterNode,
message: `"${localAdapterIdentifier}" from "${adapterModule}" is not a known adapter.`,
});
}
},
};
},
};