@plumeria/eslint-plugin 10.4.3 → 10.5.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/README.md CHANGED
@@ -10,6 +10,7 @@ The `plugin:@plumeria/recommended` config enables the following:
10
10
  - `@plumeria/style-name-requires-import`: **error**
11
11
  - `@plumeria/no-combinator`: **error**
12
12
  - `@plumeria/no-destructure`: **error**
13
+ - `@plumeria/no-inline-object`: **error**
13
14
  - `@plumeria/no-inner-call`: **error**
14
15
  - `@plumeria/no-unknown-css-properties`: **error**
15
16
  - `@plumeria/no-unused-keys`: **warn**
@@ -29,7 +30,6 @@ export default [plumeria.flatConfigs.recommended];
29
30
 
30
31
  Disallow styleName prop in files without a @plumeria/core import.
31
32
 
32
-
33
33
  ### no-combinator
34
34
 
35
35
  Disallow combinators `>`, `+`, `~` and descendant combinator (space) unless inside functional pseudo-classes.
@@ -38,6 +38,10 @@ Disallow combinators `>`, `+`, `~` and descendant combinator (space) unless insi
38
38
 
39
39
  Disallow destructuring APIs.
40
40
 
41
+ ### no-inline-object
42
+
43
+ Disallow passing inline object to `styleName` and `css.use()`. Only compiled styles from `css.create()` are allowed.
44
+
41
45
  ### no-inner-call
42
46
 
43
47
  Disallow calling APIs inside functions.
package/dist/index.js CHANGED
@@ -1,19 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.plumeria = void 0;
4
+ const style_name_requires_import_1 = require("./rules/style-name-requires-import");
4
5
  const no_combinator_1 = require("./rules/no-combinator");
5
6
  const no_destructure_1 = require("./rules/no-destructure");
7
+ const no_inline_object_1 = require("./rules/no-inline-object");
6
8
  const no_inner_call_1 = require("./rules/no-inner-call");
7
9
  const no_unused_keys_1 = require("./rules/no-unused-keys");
8
10
  const sort_properties_1 = require("./rules/sort-properties");
9
11
  const format_properties_1 = require("./rules/format-properties");
10
12
  const validate_values_1 = require("./rules/validate-values");
11
- const style_name_requires_import_1 = require("./rules/style-name-requires-import");
12
13
  const no_unknown_css_properties_1 = require("./rules/no-unknown-css-properties");
13
14
  const rules = {
14
15
  'style-name-requires-import': style_name_requires_import_1.styleNameRequiresImport,
15
16
  'no-combinator': no_combinator_1.noCombinator,
16
17
  'no-destructure': no_destructure_1.noDestructure,
18
+ 'no-inline-object': no_inline_object_1.noInlineObject,
17
19
  'no-inner-call': no_inner_call_1.noInnerCall,
18
20
  'no-unknown-css-properties': no_unknown_css_properties_1.noUnknownCssProperties,
19
21
  'no-unused-keys': no_unused_keys_1.noUnusedKeys,
@@ -28,6 +30,7 @@ const configs = {
28
30
  '@plumeria/style-name-requires-import': 'error',
29
31
  '@plumeria/no-combinator': 'error',
30
32
  '@plumeria/no-destructure': 'error',
33
+ '@plumeria/no-inline-object': 'error',
31
34
  '@plumeria/no-inner-call': 'error',
32
35
  '@plumeria/no-unknown-css-properties': 'error',
33
36
  '@plumeria/no-unused-keys': 'warn',
@@ -48,6 +51,7 @@ const flatConfigs = {
48
51
  '@plumeria/style-name-requires-import': 'error',
49
52
  '@plumeria/no-combinator': 'error',
50
53
  '@plumeria/no-destructure': 'error',
54
+ '@plumeria/no-inline-object': 'error',
51
55
  '@plumeria/no-inner-call': 'error',
52
56
  '@plumeria/no-unknown-css-properties': 'error',
53
57
  '@plumeria/no-unused-keys': 'warn',
@@ -18,106 +18,163 @@ exports.formatProperties = {
18
18
  },
19
19
  },
20
20
  create(context) {
21
+ const plumeriaAliases = {};
21
22
  const sourceCode = getSourceCode(context);
22
- return {
23
- ObjectExpression(node) {
24
- if (!node.parent || node.parent.type !== 'Property')
25
- return;
26
- if (node.properties.length === 0)
27
- return;
28
- const properties = node.properties;
29
- const parentLine = sourceCode.lines[node.parent.loc.start.line - 1];
30
- const baseIndent = parentLine.match(/^(\s*)/)[1];
31
- const innerIndent = baseIndent + ' ';
32
- const countNewlines = (text) => (text.match(/\n/g) ?? []).length;
33
- const isWhitespaceOnly = (text) => /^\s*$/.test(text);
34
- const fullText = sourceCode.getText();
35
- const openBrace = sourceCode.getFirstToken(node);
36
- const closeBrace = sourceCode.getLastToken(node);
37
- let hasError = false;
38
- let hasBlankLines = false;
39
- const textBeforeFirst = fullText.slice(openBrace.range[1], properties[0].range[0]);
40
- const newlinesBeforeFirst = countNewlines(textBeforeFirst);
41
- if (newlinesBeforeFirst === 0)
23
+ function checkStyleObject(node) {
24
+ if (node.type !== 'ObjectExpression' || node.properties.length === 0)
25
+ return;
26
+ const properties = node.properties;
27
+ const parentLine = sourceCode.lines[node.parent.loc.start.line - 1];
28
+ const baseIndent = parentLine.match(/^(\s*)/)[1];
29
+ const innerIndent = baseIndent + ' ';
30
+ const countNewlines = (text) => (text.match(/\n/g) ?? []).length;
31
+ const isWhitespaceOnly = (text) => /^\s*$/.test(text);
32
+ const fullText = sourceCode.getText();
33
+ const openBrace = sourceCode.getFirstToken(node);
34
+ const closeBrace = sourceCode.getLastToken(node);
35
+ let hasError = false;
36
+ let hasBlankLines = false;
37
+ const textBeforeFirst = fullText.slice(openBrace.range[1], properties[0].range[0]);
38
+ const newlinesBeforeFirst = countNewlines(textBeforeFirst);
39
+ if (newlinesBeforeFirst === 0)
40
+ hasError = true;
41
+ for (let i = 0; i < properties.length - 1; i++) {
42
+ const current = properties[i];
43
+ const next = properties[i + 1];
44
+ const comma = sourceCode.getTokenAfter(current);
45
+ const sliceStart = comma.range[1];
46
+ const between = fullText.slice(sliceStart, next.range[0]);
47
+ const newlines = countNewlines(between);
48
+ if (newlines === 0)
42
49
  hasError = true;
50
+ if (newlines > 1 && isWhitespaceOnly(between))
51
+ hasBlankLines = true;
52
+ }
53
+ const lastProp = properties[properties.length - 1];
54
+ const lastComma = sourceCode.getTokenAfter(lastProp);
55
+ const lastSliceStart = lastComma?.value === ',' ? lastComma.range[1] : lastProp.range[1];
56
+ const textAfterLast = fullText.slice(lastSliceStart, closeBrace.range[0]);
57
+ const newlinesAfterLast = countNewlines(textAfterLast);
58
+ if (newlinesAfterLast === 0)
59
+ hasError = true;
60
+ properties.forEach((prop) => {
61
+ if (prop.type === 'Property' &&
62
+ prop.value &&
63
+ prop.value.type === 'ObjectExpression') {
64
+ checkStyleObject(prop.value);
65
+ }
66
+ });
67
+ if (!hasError && !hasBlankLines)
68
+ return;
69
+ const buildFixes = (fixer) => {
70
+ const fixes = [];
71
+ fixes.push(fixer.replaceTextRange([openBrace.range[1], properties[0].range[0]], `\n${innerIndent}`));
43
72
  for (let i = 0; i < properties.length - 1; i++) {
44
73
  const current = properties[i];
45
74
  const next = properties[i + 1];
46
75
  const comma = sourceCode.getTokenAfter(current);
47
- const sliceStart = comma.range[1];
48
- const between = fullText.slice(sliceStart, next.range[0]);
49
- const newlines = countNewlines(between);
50
- if (newlines === 0)
51
- hasError = true;
52
- if (newlines > 1 && isWhitespaceOnly(between))
53
- hasBlankLines = true;
76
+ const betweenText = fullText.slice(comma.range[1], next.range[0]);
77
+ if (isWhitespaceOnly(betweenText)) {
78
+ fixes.push(fixer.replaceTextRange([comma.range[1], next.range[0]], `\n${innerIndent}`));
79
+ }
54
80
  }
55
- const lastProp = properties[properties.length - 1];
56
81
  const lastComma = sourceCode.getTokenAfter(lastProp);
57
- const lastSliceStart = lastComma?.value === ',' ? lastComma.range[1] : lastProp.range[1];
58
- const textAfterLast = fullText.slice(lastSliceStart, closeBrace.range[0]);
59
- const newlinesAfterLast = countNewlines(textAfterLast);
60
- if (newlinesAfterLast === 0)
61
- hasError = true;
62
- if (!hasError && !hasBlankLines)
63
- return;
64
- const buildFixes = (fixer) => {
65
- const fixes = [];
66
- fixes.push(fixer.replaceTextRange([openBrace.range[1], properties[0].range[0]], `\n${innerIndent}`));
67
- for (let i = 0; i < properties.length - 1; i++) {
68
- const current = properties[i];
69
- const next = properties[i + 1];
70
- const comma = sourceCode.getTokenAfter(current);
71
- if (comma.value === ',') {
72
- const betweenText = fullText.slice(comma.range[1], next.range[0]);
73
- if (isWhitespaceOnly(betweenText)) {
74
- fixes.push(fixer.replaceTextRange([comma.range[1], next.range[0]], `\n${innerIndent}`));
75
- }
76
- }
77
- }
78
- const lastComma = sourceCode.getTokenAfter(lastProp);
79
- if (lastComma?.value === ',') {
80
- fixes.push(fixer.replaceTextRange([lastComma.range[1], closeBrace.range[0]], `\n${baseIndent}`));
81
- }
82
- else {
83
- fixes.push(fixer.replaceTextRange([lastProp.range[1], closeBrace.range[0]], `\n${baseIndent}`));
84
- }
85
- return fixes;
86
- };
87
- if (hasError) {
82
+ if (lastComma?.value === ',') {
83
+ fixes.push(fixer.replaceTextRange([lastComma.range[1], closeBrace.range[0]], `\n${baseIndent}`));
84
+ }
85
+ else {
86
+ fixes.push(fixer.replaceTextRange([lastProp.range[1], closeBrace.range[0]], `\n${baseIndent}`));
87
+ }
88
+ return fixes;
89
+ };
90
+ if (hasError) {
91
+ context.report({
92
+ node,
93
+ messageId: 'mustBeMultiline',
94
+ fix: buildFixes,
95
+ });
96
+ return;
97
+ }
98
+ let reported = false;
99
+ for (let i = 0; i < properties.length - 1; i++) {
100
+ const current = properties[i];
101
+ const next = properties[i + 1];
102
+ const comma = sourceCode.getTokenAfter(current);
103
+ const sliceStart = comma.range[1];
104
+ const between = fullText.slice(sliceStart, next.range[0]);
105
+ if (countNewlines(between) > 1 && isWhitespaceOnly(between)) {
106
+ const blankLineNumber = current.loc.end.line + 1;
88
107
  context.report({
89
- node,
90
- messageId: 'mustBeMultiline',
91
- fix: buildFixes,
108
+ loc: {
109
+ start: {
110
+ line: blankLineNumber,
111
+ column: 0,
112
+ },
113
+ end: {
114
+ line: blankLineNumber + 1,
115
+ column: 0,
116
+ },
117
+ },
118
+ messageId: 'noEmptyLines',
119
+ fix: reported ? null : buildFixes,
92
120
  });
93
- return;
121
+ reported = true;
94
122
  }
95
- let reported = false;
96
- for (let i = 0; i < properties.length - 1; i++) {
97
- const current = properties[i];
98
- const next = properties[i + 1];
99
- const comma = sourceCode.getTokenAfter(current);
100
- const sliceStart = comma.range[1];
101
- const between = fullText.slice(sliceStart, next.range[0]);
102
- if (countNewlines(between) > 1 && isWhitespaceOnly(between)) {
103
- const blankLineNumber = current.loc.end.line + 1;
104
- context.report({
105
- loc: {
106
- start: {
107
- line: blankLineNumber,
108
- column: 0,
109
- },
110
- end: {
111
- line: blankLineNumber + 1,
112
- column: 0,
113
- },
114
- },
115
- messageId: 'noEmptyLines',
116
- fix: reported ? null : buildFixes,
117
- });
118
- reported = true;
123
+ }
124
+ }
125
+ return {
126
+ ImportDeclaration(node) {
127
+ if (node.source.value === '@plumeria/core') {
128
+ node.specifiers.forEach((specifier) => {
129
+ if (specifier.type === 'ImportNamespaceSpecifier' ||
130
+ specifier.type === 'ImportDefaultSpecifier') {
131
+ plumeriaAliases[specifier.local.name] = 'NAMESPACE';
132
+ }
133
+ else {
134
+ const spec = specifier;
135
+ const importedName = spec.imported.type === 'Identifier'
136
+ ? spec.imported.name
137
+ : String(spec.imported.value);
138
+ plumeriaAliases[specifier.local.name] = importedName;
139
+ }
140
+ });
141
+ }
142
+ },
143
+ CallExpression(node) {
144
+ let isCssProperties = false;
145
+ if (node.callee.type === 'MemberExpression') {
146
+ if (node.callee.object.type === 'Identifier' &&
147
+ plumeriaAliases[node.callee.object.name] === 'NAMESPACE') {
148
+ const propertyName = node.callee.property.type === 'Identifier'
149
+ ? node.callee.property.name
150
+ : null;
151
+ if (propertyName === 'create' ||
152
+ propertyName === 'keyframes' ||
153
+ propertyName === 'viewTransition') {
154
+ isCssProperties = true;
155
+ }
156
+ }
157
+ }
158
+ else if (node.callee.type === 'Identifier') {
159
+ const alias = plumeriaAliases[node.callee.name];
160
+ if (alias === 'create' ||
161
+ alias === 'keyframes' ||
162
+ alias === 'viewTransition') {
163
+ isCssProperties = true;
119
164
  }
120
165
  }
166
+ if (isCssProperties) {
167
+ node.arguments.forEach((arg) => {
168
+ if (arg.type === 'ObjectExpression') {
169
+ arg.properties.forEach((prop) => {
170
+ if (prop.type === 'Property' &&
171
+ prop.value.type === 'ObjectExpression') {
172
+ checkStyleObject(prop.value);
173
+ }
174
+ });
175
+ }
176
+ });
177
+ }
121
178
  },
122
179
  };
123
180
  },
@@ -43,13 +43,11 @@ exports.noCombinator = {
43
43
  while (next < len && isSpace(s[next])) {
44
44
  next++;
45
45
  }
46
- if (next < len) {
47
- const nextChar = s[next];
48
- const prevChar = s[i - 1];
49
- if (!isCombinatorOrSeparator(prevChar) &&
50
- !isCombinatorOrSeparator(nextChar)) {
51
- return false;
52
- }
46
+ const nextChar = s[next];
47
+ const prevChar = s[i - 1];
48
+ if (!isCombinatorOrSeparator(prevChar) &&
49
+ !isCombinatorOrSeparator(nextChar)) {
50
+ return false;
53
51
  }
54
52
  i = next;
55
53
  continue;
@@ -114,10 +112,11 @@ exports.noCombinator = {
114
112
  specifier.type === 'ImportDefaultSpecifier') {
115
113
  plumeriaAliases[specifier.local.name] = 'NAMESPACE';
116
114
  }
117
- else if (specifier.type === 'ImportSpecifier') {
118
- const importedName = specifier.imported.type === 'Identifier'
119
- ? specifier.imported.name
120
- : String(specifier.imported.value);
115
+ else {
116
+ const spec = specifier;
117
+ const importedName = spec.imported.type === 'Identifier'
118
+ ? spec.imported.name
119
+ : String(spec.imported.value);
121
120
  plumeriaAliases[specifier.local.name] = importedName;
122
121
  }
123
122
  });
@@ -209,9 +208,7 @@ exports.noCombinator = {
209
208
  found = '+';
210
209
  else if (text.includes('~'))
211
210
  found = '~';
212
- else if (text.includes(' ') ||
213
- text.includes('\t') ||
214
- text.includes('\n'))
211
+ else
215
212
  found = '(space)';
216
213
  context.report({
217
214
  node: node,
@@ -24,10 +24,11 @@ exports.noDestructure = {
24
24
  else if (specifier.type === 'ImportDefaultSpecifier') {
25
25
  plumeriaAliases[specifier.local.name] = 'NAMESPACE';
26
26
  }
27
- else if (specifier.type === 'ImportSpecifier') {
28
- const importedName = specifier.imported.type === 'Identifier'
29
- ? specifier.imported.name
30
- : String(specifier.imported.value);
27
+ else {
28
+ const spec = specifier;
29
+ const importedName = spec.imported.type === 'Identifier'
30
+ ? spec.imported.name
31
+ : String(spec.imported.value);
31
32
  plumeriaAliases[specifier.local.name] = importedName;
32
33
  }
33
34
  });
@@ -0,0 +1,2 @@
1
+ import type { Rule } from 'eslint';
2
+ export declare const noInlineObject: Rule.RuleModule;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noInlineObject = void 0;
4
+ exports.noInlineObject = {
5
+ meta: {
6
+ type: 'problem',
7
+ docs: {
8
+ description: 'Disallow inline objects in styleName and css.use',
9
+ },
10
+ messages: {
11
+ noInlineObjectInStyleName: 'Do not pass inline objects to styleName. It only accepts compiled styles from css.create().',
12
+ noInlineObjectInCssUse: 'Do not pass inline objects to css.use(). It only accepts compiled styles from css.create().',
13
+ },
14
+ schema: [],
15
+ },
16
+ create(context) {
17
+ function isInsideOtherCall(node) {
18
+ let current = node.parent;
19
+ while (current && current.type !== 'JSXAttribute') {
20
+ if (current.type === 'CallExpression') {
21
+ const callee = current.callee;
22
+ if (callee.type === 'MemberExpression' &&
23
+ callee.object.type === 'Identifier' &&
24
+ callee.object.name === 'css' &&
25
+ callee.property.type === 'Identifier' &&
26
+ callee.property.name === 'use') {
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ current = current.parent;
32
+ }
33
+ return false;
34
+ }
35
+ return {
36
+ 'JSXAttribute[name.name="styleName"] ObjectExpression'(node) {
37
+ if (isInsideOtherCall(node))
38
+ return;
39
+ context.report({
40
+ node,
41
+ messageId: 'noInlineObjectInStyleName',
42
+ });
43
+ },
44
+ 'CallExpression[callee.object.name="css"][callee.property.name="use"] ObjectExpression'(node) {
45
+ if (isInsideOtherCall(node))
46
+ return;
47
+ context.report({
48
+ node,
49
+ messageId: 'noInlineObjectInCssUse',
50
+ });
51
+ },
52
+ };
53
+ },
54
+ };
@@ -25,10 +25,11 @@ exports.noInnerCall = {
25
25
  else if (specifier.type === 'ImportDefaultSpecifier') {
26
26
  plumeriaAliases[specifier.local.name] = 'NAMESPACE';
27
27
  }
28
- else if (specifier.type === 'ImportSpecifier') {
29
- const importedName = specifier.imported.type === 'Identifier'
30
- ? specifier.imported.name
31
- : String(specifier.imported.value);
28
+ else {
29
+ const spec = specifier;
30
+ const importedName = spec.imported.type === 'Identifier'
31
+ ? spec.imported.name
32
+ : String(spec.imported.value);
32
33
  plumeriaAliases[specifier.local.name] = importedName;
33
34
  }
34
35
  });
@@ -3,8 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noUnknownCssProperties = void 0;
4
4
  const known_css_properties_1 = require("known-css-properties");
5
5
  const knownProperties = new Set(known_css_properties_1.all);
6
+ const kebabCache = new Map();
6
7
  function toKebabCase(str) {
7
- return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
8
+ if (kebabCache.has(str)) {
9
+ return kebabCache.get(str);
10
+ }
11
+ const result = str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
12
+ kebabCache.set(str, result);
13
+ return result;
8
14
  }
9
15
  exports.noUnknownCssProperties = {
10
16
  meta: {
@@ -27,9 +33,12 @@ exports.noUnknownCssProperties = {
27
33
  specifier.type === 'ImportDefaultSpecifier') {
28
34
  plumeriaAliases[specifier.local.name] = 'NAMESPACE';
29
35
  }
30
- else if (specifier.type === 'ImportSpecifier' &&
31
- specifier.imported.type === 'Identifier') {
32
- plumeriaAliases[specifier.local.name] = specifier.imported.name;
36
+ else {
37
+ const spec = specifier;
38
+ const importedName = spec.imported.type === 'Identifier'
39
+ ? spec.imported.name
40
+ : String(spec.imported.value);
41
+ plumeriaAliases[specifier.local.name] = importedName;
33
42
  }
34
43
  });
35
44
  }
@@ -74,34 +83,29 @@ exports.noUnknownCssProperties = {
74
83
  function checkStyleObject(node) {
75
84
  node.properties.forEach((prop) => {
76
85
  if (prop.type === 'Property') {
77
- let keyName = '';
78
- if (prop.key.type === 'Identifier') {
79
- keyName = prop.key.name;
80
- }
81
- else if (prop.key.type === 'Literal') {
82
- keyName = String(prop.key.value);
86
+ if (prop.value.type === 'ObjectExpression') {
87
+ checkStyleObject(prop.value);
83
88
  }
84
- if (keyName) {
89
+ if (!prop.computed) {
90
+ const keyName = prop.key.type === 'Identifier'
91
+ ? prop.key.name
92
+ : String(prop.key.value);
85
93
  if (!keyName.startsWith(':') &&
86
94
  !keyName.startsWith('[') &&
87
- !keyName.startsWith('@')) {
88
- if (!keyName.startsWith('--')) {
89
- const kebabName = toKebabCase(keyName);
90
- if (!knownProperties.has(kebabName)) {
91
- context.report({
92
- node: prop.key,
93
- messageId: 'unknownProperty',
94
- data: {
95
- name: keyName,
96
- },
97
- });
98
- }
95
+ !keyName.startsWith('@') &&
96
+ !keyName.startsWith('--')) {
97
+ const kebabName = toKebabCase(keyName);
98
+ if (!knownProperties.has(kebabName)) {
99
+ context.report({
100
+ node: prop.key,
101
+ messageId: 'unknownProperty',
102
+ data: {
103
+ name: keyName,
104
+ },
105
+ });
99
106
  }
100
107
  }
101
108
  }
102
- if (prop.value.type === 'ObjectExpression') {
103
- checkStyleObject(prop.value);
104
- }
105
109
  }
106
110
  });
107
111
  }
@@ -11,6 +11,7 @@ function getRootObject(node) {
11
11
  if (node.type === 'MemberExpression') {
12
12
  return getRootObject(node.object);
13
13
  }
14
+ return undefined;
14
15
  }
15
16
  exports.noUnusedKeys = {
16
17
  meta: {
@@ -42,12 +43,11 @@ exports.noUnusedKeys = {
42
43
  if (arg &&
43
44
  arg.type === 'ObjectExpression' &&
44
45
  node.parent.type === 'VariableDeclarator' &&
45
- 'name' in node.parent.id) {
46
+ node.parent.id.type === 'Identifier') {
46
47
  const variableName = node.parent.id.name;
47
48
  const keyMap = new Map();
48
49
  arg.properties.forEach((prop) => {
49
50
  if (prop.type === 'Property' &&
50
- prop.key &&
51
51
  prop.key.type === 'Identifier' &&
52
52
  prop.value.type === 'ObjectExpression') {
53
53
  keyMap.set(prop.key.name, prop.key);
@@ -58,22 +58,20 @@ exports.noUnusedKeys = {
58
58
  }
59
59
  },
60
60
  MemberExpression(node) {
61
- if (node.computed && node.property.type === 'Identifier') {
62
- const rootObject = getRootObject(node.object);
63
- if (rootObject && rootObject.type === 'Identifier') {
64
- const variableName = rootObject.name;
65
- dynamicallyAccessedVars.add(variableName);
66
- definedKeys.delete(variableName);
67
- }
61
+ const rootObject = getRootObject(node.object);
62
+ if (!rootObject)
68
63
  return;
69
- }
70
- if (node.property.type === 'Identifier') {
71
- const rootObject = getRootObject(node.object);
72
- if (rootObject && rootObject.type === 'Identifier') {
73
- const normalKey = `${rootObject.name}.${node.property.name}`;
74
- referencedKeys.add(normalKey);
64
+ if (node.computed) {
65
+ if (node.property.type === 'Identifier') {
66
+ dynamicallyAccessedVars.add(rootObject.name);
67
+ definedKeys.delete(rootObject.name);
75
68
  }
69
+ else if (node.property.type === 'Literal') {
70
+ referencedKeys.add(`${rootObject.name}.${node.property.value}`);
71
+ }
72
+ return;
76
73
  }
74
+ referencedKeys.add(`${rootObject.name}.${node.property.name}`);
77
75
  },
78
76
  'Program:exit'() {
79
77
  definedKeys.forEach((keyMap, variableName) => {