forked from ChromeDevTools/devtools-frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinject-checkbox-styles.js
127 lines (111 loc) · 4.18 KB
/
inject-checkbox-styles.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
127
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
const {isLitHtmlTemplateCall} = require('./utils.js');
const path = require('path');
const FRONT_END_DIRECTORY = path.join(__dirname, '..', '..', '..', 'front_end');
// NOTE: the actual file is input.ts, but for the sake of importing we want
// input.js as that's what the import statement would reference.
const COMMON_INPUT_STYLES = path.join(FRONT_END_DIRECTORY, 'ui', 'components', 'input', 'input.js');
/**
* @type {import('eslint').Rule.RuleModule}
*/
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Ensure common checkbox styles are imported in Lit components',
category: 'Possible Errors',
},
fixable: 'code',
messages: {
missingCheckboxStylesImport:
'When rendering a checkbox, ensure the common checkbox styles are imported from components/input/input.ts.',
missingCheckboxStylesAdoption:
'When rendering a checkbox, ensure the common checkbox styles are adopted into the component shadow root.',
},
schema: [] // no options
},
create: function(context) {
const filename = context.filename ?? context.getFilename();
let foundInputStylesImport = false;
let inputStylesImportedName = null;
let adoptedStyleSheetsCallNode = null;
const litCheckboxElements = new Set();
return {
TaggedTemplateExpression(node) {
if (!isLitHtmlTemplateCall(node)) {
return;
}
const litNodesContainingCheckbox = node.quasi.quasis.filter(element => {
return element.value.raw.includes('type="checkbox"');
});
for (const node of litNodesContainingCheckbox) {
// We store the node so we can use it as the basis for the ESLint error later.
litCheckboxElements.add(node);
}
},
ImportDeclaration(node) {
if (foundInputStylesImport) {
return;
}
// Get the absolute path of the current file's directory, so we can
// compare it to COMMON_INPUT_STYLES and see if the file does import the common styles.
const absoluteDirectory = path.dirname(path.resolve(filename));
const fullImportPath = path.resolve(absoluteDirectory, node.source.value);
foundInputStylesImport = fullImportPath === COMMON_INPUT_STYLES;
if (foundInputStylesImport) {
inputStylesImportedName = node.specifiers[0].local.name;
}
},
'AssignmentExpression[left.type="MemberExpression"][left.property.name="adoptedStyleSheets"]'(node) {
adoptedStyleSheetsCallNode = node;
},
'Program:exit'() {
if (litCheckboxElements.size === 0) {
// No checkboxes to check, so we are done.
return;
}
if (!foundInputStylesImport) {
for (const checkbox of litCheckboxElements) {
context.report({
node: checkbox,
messageId: 'missingCheckboxStylesImport',
});
}
return;
}
if (!adoptedStyleSheetsCallNode) {
for (const checkbox of litCheckboxElements) {
context.report({
node: checkbox,
messageId: 'missingCheckboxStylesAdoption',
});
}
return;
}
const inputCheckboxStylesAdoptionReference = adoptedStyleSheetsCallNode.right.elements.find(elem => {
// Ensure we find [Input.checkboxStyles] in the adopted stylesheets.
if (elem.type !== 'MemberExpression') {
return false;
}
// Check that if we imported the styles as `Input`, that the reference here matches.
if (elem.object.name !== inputStylesImportedName) {
return false;
}
if (elem.property.name !== 'checkboxStyles') {
return false;
}
return true;
});
if (!inputCheckboxStylesAdoptionReference) {
context.report({
node: adoptedStyleSheetsCallNode,
messageId: 'missingCheckboxStylesAdoption',
});
}
}
};
}
};