Skip to content

Commit 906507c

Browse files
Fix linting issues in template rules
Co-authored-by: NullVoxPopuli <[email protected]>
1 parent 78d8891 commit 906507c

9 files changed

Lines changed: 105 additions & 175 deletions

lib/rules/template-no-debugger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module.exports = {
1212
fixable: null,
1313
schema: [],
1414
messages: {
15-
unexpected: 'Unexpected {{debugger}} usage.',
15+
unexpected: 'Unexpected debugger statement in template.',
1616
},
1717
},
1818

lib/rules/template-no-log.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,13 @@ module.exports = {
1212
fixable: null,
1313
schema: [],
1414
messages: {
15-
unexpected: 'Unexpected {{log}} usage.',
15+
unexpected: 'Unexpected log statement in template.',
1616
},
1717
},
1818

1919
create(context) {
2020
function checkForLog(node) {
21-
if (
22-
node.path &&
23-
node.path.type === 'GlimmerPathExpression' &&
24-
node.path.original === 'log'
25-
) {
21+
if (node.path && node.path.type === 'GlimmerPathExpression' && node.path.original === 'log') {
2622
context.report({
2723
node,
2824
messageId: 'unexpected',

lib/rules/template-no-positive-tabindex.js

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,69 @@
1+
function parseTabindexValue(attrValue) {
2+
if (!attrValue) {
3+
return null;
4+
}
5+
6+
// Handle simple text values
7+
if (attrValue.type === 'GlimmerTextNode') {
8+
const value = Number.parseInt(attrValue.chars, 10);
9+
return Number.isNaN(value) ? null : value;
10+
}
11+
12+
// Handle mustache statements with literals
13+
if (attrValue.type === 'GlimmerMustacheStatement') {
14+
const path = attrValue.path;
15+
16+
if (path.type === 'GlimmerNumberLiteral') {
17+
return Number.parseInt(path.original, 10);
18+
}
19+
if (path.type === 'GlimmerStringLiteral') {
20+
const value = Number.parseInt(path.original, 10);
21+
return Number.isNaN(value) ? null : value;
22+
}
23+
24+
// Handle conditional expressions
25+
if (
26+
path.type === 'GlimmerPathExpression' &&
27+
(path.original === 'if' || path.original === 'unless')
28+
) {
29+
return getMaxTabindexFromConditional(attrValue.params);
30+
}
31+
}
32+
33+
// Handle concat statements
34+
if (attrValue.type === 'GlimmerConcatStatement') {
35+
const parts = attrValue.parts || [];
36+
if (parts.length > 0 && parts[0].type === 'GlimmerMustacheStatement') {
37+
return parseTabindexValue(parts[0]);
38+
}
39+
}
40+
41+
return null;
42+
}
43+
44+
function getMaxTabindexFromConditional(params) {
45+
if (!params) {
46+
return null;
47+
}
48+
49+
let maxValue = Number.NEGATIVE_INFINITY;
50+
51+
// Check the conditional values (params 1 and optionally 2)
52+
for (let i = 1; i < params.length && i < 3; i++) {
53+
const param = params[i];
54+
if (param.type === 'GlimmerNumberLiteral') {
55+
maxValue = Math.max(maxValue, Number.parseInt(param.original, 10));
56+
} else if (param.type === 'GlimmerStringLiteral') {
57+
const val = Number.parseInt(param.original, 10);
58+
if (!Number.isNaN(val)) {
59+
maxValue = Math.max(maxValue, val);
60+
}
61+
}
62+
}
63+
64+
return maxValue === Number.NEGATIVE_INFINITY ? null : maxValue;
65+
}
66+
167
/** @type {import('eslint').Rule.RuleModule} */
268
module.exports = {
369
meta: {
@@ -18,64 +84,6 @@ module.exports = {
1884
},
1985

2086
create(context) {
21-
function getTabindexValue(attrValue) {
22-
if (!attrValue) {
23-
return null;
24-
}
25-
26-
// Handle simple text values
27-
if (attrValue.type === 'GlimmerTextNode') {
28-
const value = parseInt(attrValue.chars, 10);
29-
return isNaN(value) ? null : value;
30-
}
31-
32-
// Handle mustache statements
33-
if (attrValue.type === 'GlimmerMustacheStatement') {
34-
const path = attrValue.path;
35-
36-
// Handle literal values
37-
if (path.type === 'GlimmerNumberLiteral') {
38-
return parseInt(path.original, 10);
39-
}
40-
if (path.type === 'GlimmerStringLiteral') {
41-
const value = parseInt(path.original, 10);
42-
return isNaN(value) ? null : value;
43-
}
44-
45-
// Handle conditional expressions like {{if condition 0 1}}
46-
if (path.type === 'GlimmerPathExpression' &&
47-
(path.original === 'if' || path.original === 'unless')) {
48-
const params = attrValue.params || [];
49-
let maxValue = -Infinity;
50-
51-
// Check the conditional values (params 1 and optionally 2)
52-
for (let i = 1; i < params.length && i < 3; i++) {
53-
const param = params[i];
54-
if (param.type === 'GlimmerNumberLiteral') {
55-
maxValue = Math.max(maxValue, parseInt(param.original, 10));
56-
} else if (param.type === 'GlimmerStringLiteral') {
57-
const val = parseInt(param.original, 10);
58-
if (!isNaN(val)) {
59-
maxValue = Math.max(maxValue, val);
60-
}
61-
}
62-
}
63-
64-
return maxValue === -Infinity ? null : maxValue;
65-
}
66-
}
67-
68-
// Handle concat statements
69-
if (attrValue.type === 'GlimmerConcatStatement') {
70-
const parts = attrValue.parts || [];
71-
if (parts.length > 0 && parts[0].type === 'GlimmerMustacheStatement') {
72-
return getTabindexValue(parts[0]);
73-
}
74-
}
75-
76-
return null;
77-
}
78-
7987
return {
8088
GlimmerElementNode(node) {
8189
const tabindexAttr = node.attributes?.find((attr) => attr.name === 'tabindex');
@@ -84,7 +92,7 @@ module.exports = {
8492
return;
8593
}
8694

87-
const tabindexValue = getTabindexValue(tabindexAttr.value);
95+
const tabindexValue = parseTabindexValue(tabindexAttr.value);
8896

8997
if (tabindexValue === null) {
9098
// Can't determine the value, might be a variable reference

lib/rules/template-no-triple-curlies.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ module.exports = {
1313
fixable: null,
1414
schema: [],
1515
messages: {
16-
unsafe: 'Usage of triple curly brackets is unsafe. Use {{htmlSafe}} if absolutely necessary.',
16+
unsafe:
17+
'Usage of triple curly brackets is unsafe. Use htmlSafe helper if absolutely necessary.',
1718
},
1819
},
1920

lib/rules/template-require-button-type.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
function hasParentForm(node) {
2+
let current = node.parent;
3+
while (current) {
4+
if (current.type === 'GlimmerElementNode' && current.tag === 'form') {
5+
return true;
6+
}
7+
current = current.parent;
8+
}
9+
return false;
10+
}
11+
112
/** @type {import('eslint').Rule.RuleModule} */
213
module.exports = {
314
meta: {
@@ -20,17 +31,6 @@ module.exports = {
2031
create(context) {
2132
const sourceCode = context.sourceCode;
2233

23-
function hasParentForm(node) {
24-
let current = node.parent;
25-
while (current) {
26-
if (current.type === 'GlimmerElementNode' && current.tag === 'form') {
27-
return true;
28-
}
29-
current = current.parent;
30-
}
31-
return false;
32-
}
33-
3434
return {
3535
GlimmerElementNode(node) {
3636
if (node.tag !== 'button') {
@@ -46,11 +46,11 @@ module.exports = {
4646
fix(fixer) {
4747
// If inside a form, default to "submit", otherwise "button"
4848
const defaultType = hasParentForm(node) ? 'submit' : 'button';
49-
49+
5050
// Find the position to insert the attribute
5151
const openTag = sourceCode.getText(node).match(/^<button[^>]*/)[0];
5252
const insertPos = node.range[0] + openTag.length;
53-
53+
5454
return fixer.insertTextBeforeRange([insertPos, insertPos], ` type="${defaultType}"`);
5555
},
5656
});

tests/__snapshots__/recommended.js.snap

Lines changed: 12 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,25 @@
22

33
exports[`recommended rules > gjs config has the right list 1`] = `
44
[
5+
"template-no-debugger",
6+
"template-no-duplicate-attributes",
57
"template-no-let-reference",
8+
"template-no-log",
9+
"template-no-positive-tabindex",
10+
"template-no-triple-curlies",
11+
"template-require-button-type",
612
]
713
`;
814

915
exports[`recommended rules > gts config has the right list 1`] = `
1016
[
17+
"template-no-debugger",
18+
"template-no-duplicate-attributes",
1119
"template-no-let-reference",
20+
"template-no-log",
21+
"template-no-positive-tabindex",
22+
"template-no-triple-curlies",
23+
"template-require-button-type",
1224
]
1325
`;
1426

@@ -86,90 +98,3 @@ exports[`recommended rules > has the right list 1`] = `
8698
"use-ember-data-rfc-395-imports",
8799
]
88100
`;
89-
90-
exports[`recommended rules gjs config has the right list 1`] = `
91-
[
92-
"template-no-let-reference",
93-
]
94-
`;
95-
96-
exports[`recommended rules gts config has the right list 1`] = `
97-
[
98-
"template-no-let-reference",
99-
]
100-
`;
101-
102-
exports[`recommended rules has the right list 1`] = `
103-
[
104-
"avoid-leaking-state-in-ember-objects",
105-
"avoid-using-needs-in-controllers",
106-
"classic-decorator-hooks",
107-
"classic-decorator-no-classic-methods",
108-
"closure-actions",
109-
"jquery-ember-run",
110-
"new-module-imports",
111-
"no-actions-hash",
112-
"no-arrow-function-computed-properties",
113-
"no-assignment-of-untracked-properties-used-in-tracking-contexts",
114-
"no-at-ember-render-modifiers",
115-
"no-attrs-in-components",
116-
"no-attrs-snapshot",
117-
"no-capital-letters-in-routes",
118-
"no-classic-classes",
119-
"no-classic-components",
120-
"no-component-lifecycle-hooks",
121-
"no-computed-properties-in-native-classes",
122-
"no-controller-access-in-routes",
123-
"no-deeply-nested-dependent-keys-with-each",
124-
"no-deprecated-router-transition-methods",
125-
"no-duplicate-dependent-keys",
126-
"no-ember-super-in-es-classes",
127-
"no-ember-testing-in-module-scope",
128-
"no-empty-glimmer-component-classes",
129-
"no-function-prototype-extensions",
130-
"no-get-with-default",
131-
"no-get",
132-
"no-global-jquery",
133-
"no-implicit-injections",
134-
"no-incorrect-calls-with-inline-anonymous-functions",
135-
"no-incorrect-computed-macros",
136-
"no-invalid-debug-function-arguments",
137-
"no-invalid-dependent-keys",
138-
"no-invalid-test-waiters",
139-
"no-jquery",
140-
"no-legacy-test-waiters",
141-
"no-mixins",
142-
"no-new-mixins",
143-
"no-noop-setup-on-error-in-before",
144-
"no-observers",
145-
"no-old-shims",
146-
"no-on-calls-in-components",
147-
"no-pause-test",
148-
"no-private-routing-service",
149-
"no-restricted-resolver-tests",
150-
"no-runloop",
151-
"no-settled-after-test-helper",
152-
"no-shadow-route-definition",
153-
"no-side-effects",
154-
"no-string-prototype-extensions",
155-
"no-test-and-then",
156-
"no-test-import-export",
157-
"no-test-module-for",
158-
"no-test-support-import",
159-
"no-test-this-render",
160-
"no-tracked-properties-from-args",
161-
"no-try-invoke",
162-
"no-unnecessary-route-path-option",
163-
"no-volatile-computed-properties",
164-
"prefer-ember-test-helpers",
165-
"require-computed-macros",
166-
"require-computed-property-dependencies",
167-
"require-return-from-computed",
168-
"require-super-in-lifecycle-hooks",
169-
"require-tagless-components",
170-
"require-valid-css-selector-in-test-helpers",
171-
"routes-segments-snake-case",
172-
"use-brace-expansion",
173-
"use-ember-data-rfc-395-imports",
174-
]
175-
`;

tests/lib/rules/template-no-debugger.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ ruleTester.run('template-no-debugger', rule, {
3737
</template>`,
3838
output: null,
3939
errors: [{
40-
message: 'Unexpected {{debugger}} usage.',
40+
message: 'Unexpected debugger statement in template.',
4141
type: 'GlimmerMustacheStatement',
4242
}],
4343
},
@@ -49,7 +49,7 @@ ruleTester.run('template-no-debugger', rule, {
4949
</template>`,
5050
output: null,
5151
errors: [{
52-
message: 'Unexpected {{debugger}} usage.',
52+
message: 'Unexpected debugger statement in template.',
5353
type: 'GlimmerMustacheStatement',
5454
}],
5555
},
@@ -61,7 +61,7 @@ ruleTester.run('template-no-debugger', rule, {
6161
</template>`,
6262
output: null,
6363
errors: [{
64-
message: 'Unexpected {{debugger}} usage.',
64+
message: 'Unexpected debugger statement in template.',
6565
type: 'GlimmerBlockStatement',
6666
}],
6767
},

0 commit comments

Comments
 (0)