Skip to content

Commit

Permalink
implement indent
Browse files Browse the repository at this point in the history
  • Loading branch information
patricklx committed Nov 2, 2023
1 parent 19bceeb commit 95aac10
Show file tree
Hide file tree
Showing 3 changed files with 455 additions and 0 deletions.
7 changes: 7 additions & 0 deletions lib/parsers/gjs-gts-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,13 @@ function preprocessGlimmerTemplates(info, code) {
n.type = `Glimmer${n.type}`;
allNodeTypes.add(n.type);
}
// ast should not contain comment nodes
for (const comment of comments) {
const parentBody = comment.parent.body || comment.parent.children;
const idx = parentBody.indexOf(comment);
parentBody.splice(idx, 1);
comment.type = code.slice(...comment.range).match(/^({{|<)!--/) ? 'Block' : 'Line';

Check failure on line 299 in lib/parsers/gjs-gts-parser.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Prefer `RegExp#test(…)` over `String#match(…)`

Check failure on line 299 in lib/parsers/gjs-gts-parser.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Prefer `RegExp#test(…)` over `String#match(…)`
}
// tokens should not contain tokens of comments
ast.tokens = ast.tokens.filter(
(t) => !comments.some((c) => c.range[0] <= t.range[0] && c.range[1] >= t.range[1])
Expand Down
178 changes: 178 additions & 0 deletions lib/rules/template-indent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
const { builtinRules } = require('eslint/use-at-your-own-risk');

const baseRule = builtinRules.get('indent');
const IGNORED_ELEMENTS = new Set(['pre', 'script', 'style', 'textarea']);

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
ERROR_MESSAGE: baseRule.meta.messages.wrongIndentation,
name: 'indent',
meta: {
type: 'layout',
docs: {
description: 'enforce consistent indentation',
// too opinionated to be recommended
extendsBaseRule: true,
recommended: true,
category: 'Ember Octane',
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-indent.md',
},
fixable: 'whitespace',
hasSuggestions: baseRule.meta.hasSuggestions,
schema: baseRule.meta.schema,
messages: baseRule.meta.messages,
},

create: (context) => {
const rules = baseRule.create(context);
const sourceCode = context.sourceCode;

function JSXElement(node) {
let closingElement;
let openingElement;
if (node.type === 'GlimmerElementNode') {
const tokens = sourceCode.getTokens(node);
const openEnd = tokens.find(t => t.value === '>');

Check failure on line 35 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Replace `t` with `(t)`

Check failure on line 35 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Replace `t` with `(t)`
const closeStart = tokens.findLast(t => t.value === '<');

Check failure on line 36 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Replace `t` with `(t)`

Check failure on line 36 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Replace `t` with `(t)`
if (!node.selfClosing) {
closingElement = {
type: 'JSXClosingElement',
parent: node,
range: [closeStart.range[0], node.range[1]],
loc: {
start: Object.assign({}, node.loc.start),
end: Object.assign({}, node.loc.end),
},
};
closingElement.loc.start = sourceCode.getLocFromIndex(closeStart.range[0]);
closingElement.name = { ...closingElement, type: 'JSXIdentifier' };
closingElement.name.range = [
closingElement.name.range[0] + 1,
closingElement.name.range[1] - 1,
];
}

openingElement = {
type: 'JSXOpeningElement',
selfClosing: node.selfClosing,
attributes: node.attributes,
parent: node,
range: [node.range[0], openEnd.range[1]],
loc: {
start: Object.assign({}, node.loc.start),
end: Object.assign({}, node.loc.end),
},
};
openingElement.loc.end = sourceCode.getLocFromIndex(openEnd.range[1]);
openingElement.name = { ...openingElement, type: 'JSXIdentifier' };
openingElement.name.range = [openingElement.name.range[0] + 1, openingElement.name.range[1] - 1];

Check failure on line 68 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Replace `openingElement.name.range[0]·+·1,·openingElement.name.range[1]·-·1` with `⏎··········openingElement.name.range[0]·+·1,⏎··········openingElement.name.range[1]·-·1,⏎········`

Check failure on line 68 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Replace `openingElement.name.range[0]·+·1,·openingElement.name.range[1]·-·1` with `⏎··········openingElement.name.range[0]·+·1,⏎··········openingElement.name.range[1]·-·1,⏎········`
}
if (node.type === 'GlimmerBlockStatement') {
const tokens = sourceCode.getTokens(node);
let openEndIdx = tokens.findIndex(t => t.value === '}');

Check failure on line 72 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Replace `t` with `(t)`

Check failure on line 72 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Replace `t` with `(t)`
while (tokens[openEndIdx + 1].value === '}') {
openEndIdx += 1;
}
const openEnd = tokens[openEndIdx];
let closeStartIdx = tokens.findLastIndex(t => t.value === '{');

Check failure on line 77 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Replace `t` with `(t)`

Check failure on line 77 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Replace `t` with `(t)`
while (tokens[closeStartIdx - 1].value === '{') {
closeStartIdx -= 1;
}
const closeStart = tokens[closeStartIdx];
closingElement = {
type: 'JSXClosingElement',
parent: node,
range: [closeStart.range[0], node.range[1]],
loc: {
start: Object.assign({}, node.loc.start),
end: Object.assign({}, node.loc.end),
},
};
closingElement.loc.start = sourceCode.getLocFromIndex(closeStart.range[0]);

openingElement = {
type: 'JSXOpeningElement',
attributes: node.params,
parent: node,
range: [node.range[0], openEnd.range[1]],
loc: {
start: Object.assign({}, node.loc.start),
end: Object.assign({}, node.loc.end),
},
};
openingElement.loc.end = sourceCode.getLocFromIndex(openEnd.range[1]);
}
return {
type: 'JSXElement',
openingElement,
closingElement,
children: node.children || node.body,
parent: node.parent,
range: node.range,
loc: node.loc,
};
}

const ignoredStack = new Set();

return Object.assign({}, rules, {
// overwrite the base rule here so we can use our KNOWN_NODES list instead
'*:exit'(node) {
// For nodes we care about, skip the default handling, because it just marks the node as ignored...
if (
!node.type.startsWith('Glimmer') ||
ignoredStack.size > 0 && !ignoredStack.has(node)

Check failure on line 124 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

Replace `ignoredStack.size·>·0·&&·!ignoredStack.has(node` with `(ignoredStack.size·>·0·&&·!ignoredStack.has(node)`

Check failure on line 124 in lib/rules/template-indent.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 20.x)

Replace `ignoredStack.size·>·0·&&·!ignoredStack.has(node` with `(ignoredStack.size·>·0·&&·!ignoredStack.has(node)`
) {
rules['*:exit'](node);
}
if (ignoredStack.has(node)) {
ignoredStack.delete(node);
}
},
'GlimmerTemplate:exit'(node) {
if (!node.parent) {
rules['Program:exit'](node);
}
},
GlimmerElementNode(node) {
if (ignoredStack.size > 0) {
return;
}
if (IGNORED_ELEMENTS.has(node.tag)) {
ignoredStack.add(node);
}
const jsx = JSXElement(node);
rules['JSXElement'](jsx);
rules['JSXOpeningElement'](jsx.openingElement);
if (jsx.closingElement) {
rules['JSXClosingElement'](jsx.closingElement);
}
},
GlimmerAttrNode(node) {
if (ignoredStack.size > 0 || !node.value) {
return;
}
rules['JSXAttribute[value]']({
...node,
type: 'JSXAttribute',
name: {
type: 'JSXIdentifier',
name: node.name,
range: [node.range[0], node.range[0] + node.name.length - 1],
},
});
},
GlimmerTemplate(node) {
if (!node.parent) {
return;
}
const jsx = JSXElement({ ...node, tag: 'template', type: 'GlimmerElementNode' });
rules['JSXElement'](jsx);
},
GlimmerBlockStatement(node) {
const body = [...node.program.body, ...(node.inverse?.body || [])];
rules['JSXElement'](JSXElement({ ...node, body }));
},
});
},
};
Loading

0 comments on commit 95aac10

Please sign in to comment.