-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added prettier-plugin for inline hbs
- Loading branch information
Matthew Edwards
committed
Jun 15, 2021
1 parent
bbe4b18
commit 6496f59
Showing
20 changed files
with
773 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
packages/@glimmerx/babel-plugin-component-templates/test/ | ||
packages/@glimmerx/babel-plugin-component-templates/test/ | ||
packages/@glimmerx/@glimmerx/prettier-plugin-component-templates/test/fixtures/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
packages/@glimmerx/prettier-plugin-component-templates/.prettierignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
test/__fixtures__/**/* |
47 changes: 47 additions & 0 deletions
47
packages/@glimmerx/prettier-plugin-component-templates/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# prettier-plugin-glimmer-experimental | ||
|
||
## Background | ||
|
||
[Prettier](https://prettier.io/docs/en/index.html) is an opinionated code formatter. In Prettier `>2.0` there is support for `*.hbs` glimmer files, but does not support the experimental syntaxes that `glimmerx` components are authored in. | ||
|
||
## Introduction | ||
|
||
This plugin extends the internal printers to add an embedded syntax for glimmer template in an `hbs` TaggedTemplateExpressions. | ||
|
||
## Installation and Usage | ||
|
||
```bash | ||
yarn add -D @glimmerx/prettier-plugin-component-templates | ||
``` | ||
|
||
Once added prettier will discover and use the plugin to format any `hbs` tagged template expression. | ||
|
||
## Development | ||
|
||
Generate a test case, add it to the tests file, | ||
|
||
- Add `PRETTIER_DEBUG=true` to the environment when running the plugin in order to get complete stack traces on errors. | ||
- To generate a new output file you can: | ||
``` | ||
yarn prettier --plugin ./index.js ./test/fixtures/extension-gjs/code.gjs > ./test/fixtures/extension-gjs/output.gjs | ||
``` | ||
|
||
### Testing | ||
|
||
Run all tests: | ||
|
||
``` | ||
yarn test | ||
``` | ||
|
||
Using the plugin on a single fixture file: | ||
|
||
``` | ||
PRETTIER_DEBUG=true --inspect-brk node node_modules/.bin/prettier --plugin ./index.js ./test/fixtures/extension-gjs/code.gjs | ||
``` | ||
|
||
Some caveats, the `.prettierignore` file will be respected, so please ensure that is commented out in repo root. | ||
|
||
## TODO | ||
|
||
- [ ] Add support for `<template>` tag semantics. |
142 changes: 142 additions & 0 deletions
142
packages/@glimmerx/prettier-plugin-component-templates/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
const babelParsers = require('prettier/parser-babel').parsers; | ||
const typescriptParsers = require('prettier/parser-typescript').parsers; | ||
|
||
const { esTree } = require('./lib/util'); | ||
|
||
const { | ||
builders: { group, indent, softline, concat, hardline }, | ||
utils: { mapDoc, stripTrailingHardline }, | ||
} = require('prettier').doc; | ||
|
||
const comments = require('./lib/comments'); | ||
|
||
function formatHbs(path, print, textToDoc, options) { | ||
const node = path.getValue(); | ||
|
||
const placeholderPattern = 'PRETTIER_HTML_PLACEHOLDER_(\\d+)_IN_JS'; | ||
const placeholders = node.expressions.map((_, i) => `PRETTIER_HTML_PLACEHOLDER_${i}_IN_JS`); | ||
|
||
const text = node.quasis | ||
.map((quasi, index, quasis) => | ||
index === quasis.length - 1 ? quasi.value.raw : quasi.value.raw + placeholders[index] | ||
) | ||
.join(''); | ||
|
||
const expressionDocs = path.map(print, 'expressions'); | ||
|
||
if (expressionDocs.length === 0 && text.trim().length === 0) { | ||
return '``'; | ||
} | ||
|
||
const contentDoc = mapDoc( | ||
stripTrailingHardline(textToDoc(text, { parser: 'glimmer' })), | ||
(doc) => { | ||
const placeholderRegex = new RegExp(placeholderPattern, 'g'); | ||
const hasPlaceholder = typeof doc === 'string' && placeholderRegex.test(doc); | ||
|
||
if (!hasPlaceholder) { | ||
return doc; | ||
} | ||
|
||
let parts = []; | ||
|
||
const components = doc.split(placeholderRegex); | ||
for (let i = 0; i < components.length; i++) { | ||
const component = components[i]; | ||
|
||
if (i % 2 === 0) { | ||
if (component) { | ||
parts.push(component); | ||
} | ||
continue; | ||
} | ||
|
||
const placeholderIndex = +component; | ||
|
||
parts.push( | ||
concat([ | ||
'${', | ||
group(concat([indent(concat([softline, expressionDocs[placeholderIndex]])), softline])), | ||
'}', | ||
]) | ||
); | ||
} | ||
|
||
return concat(parts); | ||
} | ||
); | ||
|
||
return group(concat(['`', indent(concat([hardline, group(contentDoc)])), softline, '`'])); | ||
} | ||
|
||
function isHbs(path) { | ||
return path.match( | ||
(node) => { | ||
return node.type === 'TemplateLiteral'; | ||
}, | ||
(node, name) => { | ||
return ( | ||
node.type === 'TaggedTemplateExpression' && | ||
node.tag.type === 'Identifier' && | ||
node.tag.name === 'hbs' && | ||
name === 'quasi' | ||
); | ||
} | ||
); | ||
} | ||
|
||
function embed(path, print, textToDoc, options) { | ||
if (isHbs(path)) { | ||
return formatHbs(path, print, textToDoc, options); | ||
} | ||
|
||
return esTree(options).embed(path, print, textToDoc, options); | ||
} | ||
|
||
function print(path, options, print) { | ||
return esTree(options).print(path, options, print); | ||
} | ||
|
||
const languages = [ | ||
{ | ||
name: 'glimmer-experimental', | ||
group: 'JavaScript', | ||
parsers: ['babel', 'babel-ts', 'typescript'], // Which parsers do we want to support? | ||
extensions: ['.gjs', '.js', '.ts'], | ||
vscodeLanguageIds: ['javascript'], | ||
}, | ||
]; | ||
|
||
const parsers = { | ||
babel: { | ||
...babelParsers.babel, | ||
astFormat: 'esTree', | ||
parse(text, parsers, options) { | ||
const ast = babelParsers.babel.parse(text, parsers, options); | ||
return ast; | ||
}, | ||
}, | ||
// babel-ts? | ||
typescript: { | ||
...typescriptParsers.typescript, | ||
astFormat: 'esTree', | ||
parse(text, parsers, options) { | ||
const ast = typescriptParsers.typescript.parse(text, parsers, options); | ||
return ast; | ||
}, | ||
}, | ||
}; | ||
|
||
const printers = { | ||
esTree: { | ||
embed, | ||
print, | ||
...comments, | ||
}, | ||
}; | ||
|
||
module.exports = { | ||
languages, | ||
parsers, | ||
printers, | ||
}; |
77 changes: 77 additions & 0 deletions
77
packages/@glimmerx/prettier-plugin-component-templates/lib/comments.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
const { esTree } = require('./util'); | ||
|
||
function canAttachComment(node) { | ||
return ( | ||
node.type && | ||
!isBlockComment(node) && | ||
!isLineComment(node) && | ||
node.type !== 'EmptyStatement' && | ||
node.type !== 'TemplateElement' && | ||
node.type !== 'Import' && | ||
// `babel-ts` don't have similar node for `class Foo { bar() /* bat */; }` | ||
node.type !== 'TSEmptyBodyFunctionExpression' | ||
); | ||
} | ||
|
||
function isBlockComment(comment) { | ||
return ( | ||
comment.type === 'Block' || | ||
comment.type === 'CommentBlock' || | ||
// `meriyah` | ||
comment.type === 'MultiLine' | ||
); | ||
} | ||
|
||
function isLineComment(comment) { | ||
return ( | ||
comment.type === 'Line' || | ||
comment.type === 'CommentLine' || | ||
// `meriyah` has `SingleLine`, `HashbangComment`, `HTMLOpen`, and `HTMLClose` | ||
comment.type === 'SingleLine' || | ||
comment.type === 'HashbangComment' || | ||
comment.type === 'HTMLOpen' || | ||
comment.type === 'HTMLClose' | ||
); | ||
} | ||
|
||
function printComment(path, options) { | ||
return esTree(options).printComment(path, options); | ||
} | ||
|
||
const handleComments = { | ||
avoidAstMutation: true, | ||
ownLine: function (context) { | ||
const options = context.options; | ||
return esTree(options).handleComments.ownLine(context); | ||
}, | ||
endOfLine: function (context) { | ||
const options = context.options; | ||
return esTree(options).handleComments.endOfLine(context); | ||
}, | ||
remaining: function (context) { | ||
const options = context.options; | ||
return esTree(options).handleComments.remaining(context); | ||
}, | ||
}; | ||
|
||
function getCommentChildNodes(node, options) { | ||
return esTree(options).getCommentChildNodes(node, options); | ||
} | ||
|
||
function massageAstNode(node, options) { | ||
return esTree(options).massageAstNode(node, options); | ||
} | ||
|
||
function willPrintOwnComments(path, options) { | ||
return esTree(options).willPrintOwnComments(path, options); | ||
} | ||
|
||
module.exports = { | ||
canAttachComment, | ||
handleComments, | ||
isBlockComment, | ||
getCommentChildNodes, | ||
massageAstNode, | ||
willPrintOwnComments, | ||
printComment, | ||
}; |
7 changes: 7 additions & 0 deletions
7
packages/@glimmerx/prettier-plugin-component-templates/lib/util.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
function esTree(options) { | ||
return options.plugins[0].printers.estree; | ||
} | ||
|
||
module.exports = { | ||
esTree, | ||
}; |
27 changes: 27 additions & 0 deletions
27
packages/@glimmerx/prettier-plugin-component-templates/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "@glimmerx/prettier-plugin-component-templates", | ||
"version": "0.0.1", | ||
"description": "A prettier formatter for glimmer component templates", | ||
"main": "index.js", | ||
"repository": "https://github.com/glimmerjs/glimmer-experimental", | ||
"author": "Matt Edwards <[email protected]>", | ||
"license": "MIT", | ||
"private": false, | ||
"files": [ | ||
"index.js", | ||
"lib/**/*" | ||
], | ||
"scripts": { | ||
"test": "mocha" | ||
}, | ||
"devDependencies": { | ||
"chai": "^4.3.4", | ||
"esm": "^3.2.25", | ||
"mocha": "^7.1.1", | ||
"prettier": "^2.3.0" | ||
}, | ||
"volta": { | ||
"node": "12.10.0", | ||
"yarn": "1.22.4" | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
packages/@glimmerx/prettier-plugin-component-templates/test/fixtures/basic/code.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Component, { hbs } from '@glimmerx/component'; | ||
|
||
export default class Page extends Component { | ||
static template = hbs` | ||
<html> | ||
<head> | ||
<title>Hello World</title> | ||
</head> | ||
<body> | ||
<h1>Goodbye Moon</h1> | ||
</body> | ||
</html> | ||
`; | ||
} |
14 changes: 14 additions & 0 deletions
14
packages/@glimmerx/prettier-plugin-component-templates/test/fixtures/basic/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Component, { hbs } from '@glimmerx/component'; | ||
|
||
export default class Page extends Component { | ||
static template = hbs` | ||
<html> | ||
<head> | ||
<title>Hello World</title> | ||
</head> | ||
<body> | ||
<h1>Goodbye Moon</h1> | ||
</body> | ||
</html> | ||
`; | ||
} |
28 changes: 28 additions & 0 deletions
28
packages/@glimmerx/prettier-plugin-component-templates/test/fixtures/extension-gjs/code.gjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import Component, { hbs } from '@glimmerx/component'; | ||
import { AssetStyle, url } from 'some-external-library'; | ||
import Page from './Page'; | ||
|
||
export default class Layout extends Component { | ||
static template = hbs` | ||
<Page @arg1={{@arg1}} @arg2={{@arg1}} @arg2={{@arg1}} @arg3={{@arg1}} @arg4={{@arg1}} @arg5={{@arg1}}> | ||
<:head> | ||
<AssetStyle @path="stylesheets/layout"/> | ||
<title>Hello Layout</title> | ||
<meta name="asset-url" id="ui-icons/static/images/sprite-asset" content={{url path="ui-icons/static/images/icons.svg"}}> | ||
<script src={{url "ui-icons/static/javascripts/icons.js"}} async></script> | ||
</:head> | ||
<:content> | ||
<p> | ||
Haxx0r ipsum ip machine code ctl-c epoch socket Leslie Lamport worm null gc. False system fork wombat gcc stdio.h case interpreter stack trace buffer fatal unix ddos port. Packet sniffer pragma fopen stack mountain dew leet. | ||
</p> | ||
<p> | ||
Public giga highjack sudo linux fork root public protocol James T. Kirk leapfrog float suitably small values shell. Mutex fatal void char exception tarball Starcraft brute force. Try catch warez port interpreter error true else afk sql foad January 1, 1970. | ||
</p> | ||
<p> Hello </p> | ||
<p> | ||
Thread bit headers salt float race condition wannabee memory leak bytes regex packet warez snarf malloc deadlock overflow. Afk baz double flood d00dz semaphore all your base are belong to us ssh. Injection daemon segfault highjack function access gobble int exception ascii James T. Kirk printf class *.* mega foad shell bar for Linus Torvalds. | ||
</p> | ||
</:content> | ||
</Page> | ||
`; | ||
} |
Oops, something went wrong.