forked from ChromeDevTools/devtools-frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathl10n-no-unused-message.js
100 lines (86 loc) · 3.24 KB
/
l10n-no-unused-message.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
// Copyright 2021 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 l10nHelper = require('./l10n-helper.js');
const MODULE_UI_STRINGS_FILENAME_REGEX = /ModuleUIStrings\.(js|ts)$/;
/**
* Returns true iff the passed expression is of the form `UIStrings.bar`.
*/
function isStandardUIStringsMemberExpression(expr) {
if (expr.object.type !== 'Identifier' || expr.object.name !== 'UIStrings') {
return false;
}
return expr.property.type === 'Identifier';
}
/**
* @type {import('eslint').Rule.RuleModule}
*/
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Unused properties on UIStrings objects are not allowed.',
category: 'Possible Errors',
},
fixable: 'code',
schema: [] // no options
},
create: function(context) {
const filename = context.filename ?? context.getFilename();
const sourceCode = context.sourceCode ?? context.getSourceCode();
const declaredUIStringsKeys = new Map();
const usedUIStringsKeys = new Set();
function removeProperty(fixer, property) {
const source = sourceCode;
// For simplicity, we remove whole lines. This assumes that the UIStrings has
// some standard formatting. Otherwise we would have to fiddle a lot
// with tokens and whitespace.
let lineToRemoveStart = source.getLocFromIndex(property.range[0]).line;
const lineToRemoveEnd = source.getLocFromIndex(property.range[1]).line + 1;
// Are there comments in front of the property?
// Move the line we want to remove to the line of the first comment.
const comments = source.getCommentsBefore(property);
if (comments.length > 0) {
lineToRemoveStart = source.getLocFromIndex(comments[0].range[0]).line;
}
const removeStart = source.getIndexFromLoc({line: lineToRemoveStart, column: 0});
const removeEnd = source.getIndexFromLoc({line: Math.min(lineToRemoveEnd, source.lines.length), column: 0});
return fixer.removeRange([removeStart, removeEnd]);
}
return {
VariableDeclarator(variableDeclarator) {
if (MODULE_UI_STRINGS_FILENAME_REGEX.test(filename)) {
return;
}
if (!l10nHelper.isUIStringsVariableDeclarator(context, variableDeclarator)) {
return;
}
for (const property of variableDeclarator.init.properties) {
if (property.type !== 'Property' || property.key.type !== 'Identifier') {
continue;
}
declaredUIStringsKeys.set(property.key.name, property);
}
},
MemberExpression(memberExpression) {
if (!isStandardUIStringsMemberExpression(memberExpression)) {
return;
}
usedUIStringsKeys.add(memberExpression.property.name);
},
'Program:exit': function() {
for (const usedKey of usedUIStringsKeys) {
declaredUIStringsKeys.delete(usedKey);
}
for (const property of declaredUIStringsKeys.values()) {
context.report({
node: property,
message: 'UIStrings message is not used.',
fix: fixer => removeProperty(fixer, property),
});
}
},
};
}
};