Skip to content

Commit

Permalink
Add support for Glimmer / Handlebars (#83)
Browse files Browse the repository at this point in the history
* Add Glimmer / Handlebars support

* Update Glimmer tests

* Add test case

* Update glimmer parsing

* Remove nested transform fn

* Rewrite using visitors

* Only make on pass over the Glimmer AST

* Cleanup code a bit

Co-authored-by: Brad Cornes <hello@bradley.dev>
  • Loading branch information
thecrypticace and bradlc committed Jul 7, 2022
1 parent bc08a56 commit 91ac55d
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 5 deletions.
49 changes: 44 additions & 5 deletions src/index.js
Expand Up @@ -3,6 +3,7 @@ import prettierParserHTML from 'prettier/parser-html'
import prettierParserPostCSS from 'prettier/parser-postcss'
import prettierParserBabel from 'prettier/parser-babel'
import prettierParserEspree from 'prettier/parser-espree'
import prettierParserGlimmer from 'prettier/parser-glimmer'
import prettierParserMeriyah from 'prettier/parser-meriyah'
import prettierParserFlow from 'prettier/parser-flow'
import prettierParserTypescript from 'prettier/parser-typescript'
Expand Down Expand Up @@ -234,6 +235,43 @@ function transformHtml(attributes, computedAttributes = []) {
return transform
}

function transformGlimmer(ast, { env }) {
visit(ast, {
AttrNode(attr, parent, key, index, meta) {
let attributes = ['class']

if (attributes.includes(attr.name) && attr.value) {
meta.sortTextNodes = true
}
},

TextNode(node, parent, key, index, meta) {
if (!meta.sortTextNodes) {
return
}

let siblings = parent?.type === 'ConcatStatement' ? {
prev: parent.parts[index - 1],
next: parent.parts[index + 1],
} : null

node.chars = sortClasses(node.chars, {
env,
ignoreFirst: siblings?.prev && !/^\s/.test(node.chars),
ignoreLast: siblings?.next && !/\s$/.test(node.chars),
})
},

StringLiteral(node, parent, key, index, meta) {
if (!meta.sortTextNodes) {
return
}

node.value = sortClasses(node.value, { env })
},
})
}

function sortStringLiteral(node, { env }) {
let result = sortClasses(node.value, { env })
let didChange = result !== node.value
Expand Down Expand Up @@ -364,6 +402,7 @@ export const printers = {

export const parsers = {
html: createParser(prettierParserHTML.parsers.html, transformHtml(['class'])),
glimmer: createParser(prettierParserGlimmer.parsers.glimmer, transformGlimmer),
lwc: createParser(prettierParserHTML.parsers.lwc, transformHtml(['class'])),
angular: createParser(
prettierParserHTML.parsers.angular,
Expand Down Expand Up @@ -442,13 +481,13 @@ function transformSvelte(ast, { env, changes }) {

// https://lihautan.com/manipulating-ast-with-javascript/
function visit(ast, callbackMap) {
function _visit(node, parent, key, index) {
function _visit(node, parent, key, index, meta = {}) {
if (typeof callbackMap === 'function') {
if (callbackMap(node, parent, key, index) === false) {
if (callbackMap(node, parent, key, index, meta) === false) {
return
}
} else if (node.type in callbackMap) {
if (callbackMap[node.type](node, parent, key, index) === false) {
if (callbackMap[node.type](node, parent, key, index, meta) === false) {
return
}
}
Expand All @@ -459,11 +498,11 @@ function visit(ast, callbackMap) {
if (Array.isArray(child)) {
for (let j = 0; j < child.length; j++) {
if (child[j] !== null) {
_visit(child[j], node, keys[i], j)
_visit(child[j], node, keys[i], j, {...meta})
}
}
} else if (typeof child?.type === 'string') {
_visit(child, node, keys[i], i)
_visit(child, node, keys[i], i, {...meta})
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions tests/test.js
Expand Up @@ -130,8 +130,31 @@ let vue = [
],
]

let glimmer = [
t`<div class='${yes}'></div>`,
t`<!-- <div class='${no}'></div> -->`,
t`<div class='${yes} {{"${yes}"}}'></div>`,
t`<div class='${yes} {{"${yes}"}} ${yes}'></div>`,
t`<div class='${yes} {{"${yes}"}} {{if someVar "${yes}" "${yes}"}}'></div>`,
t`<div class='${yes} {{"${yes}"}} {{if someVar "${yes}" "${yes}"}}' {{if someVar "attr='${no}'" "attr='${no}'"}}></div>`,
[
`<div class='md:inline flex sm:block{{someVar}}'></div>`,
`<div class='flex md:inline sm:block{{someVar}}'></div>`,
],
[
`<div class='sm:p-0 p-0 {{someVar}}sm:block md:inline flex'></div>`,
`<div class='p-0 sm:p-0 {{someVar}}sm:block flex md:inline'></div>`,
],
t`<div not-class='${no}'></div>`,
["<div class=' sm:p-0 p-0 '></div>", "<div class='p-0 sm:p-0'></div>"],
t`<div class></div>`,
t`<div class=''></div>`,
t`{{link 'Some page' href=person.url class='${no}'}}`,
]

let tests = {
html,
glimmer,
lwc: html,
vue: [...vue, t`<div :class="\`${yes} \${someVar} ${yes} \${'${yes}'}\`"></div>`],
angular: [
Expand Down

0 comments on commit 91ac55d

Please sign in to comment.