🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

prettier-edge

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prettier-edge

Prettier plugin for formatting AdonisJS Edge templates.

latest
Source
npmnpm
Version
1.0.0
Version published
Maintainers
1
Created
Source

prettier-plugin-edge

A Prettier plugin for AdonisJS Edge templates.

gh-workflow-image npm-image npm-downloads-image license-image node-image prettier-image

One pass formats your HTML, your Edge tags and interpolations, the JavaScript inside them, and the embedded <script> / <style> blocks.

BeforeAfter
@if(showFooter)
<footer class="border-t border-gray-200">
<div class="container mx-auto py-8">
@each(section in sections)
<h3>{{section.title}}</h3>
<ul>
@each(item in section.items)
<li><a href="{{item.href}}">{{item.label}}</a></li>
@end
</ul>
@end
</div>
</footer>
@end
@if(showFooter)
  <footer class="border-t border-gray-200">
    <div class="container mx-auto py-8">
      @each(section in sections)
        <h3>{{ section.title }}</h3>
        <ul>
          @each(item in section.items)
            <li><a href="{{ item.href }}">{{ item.label }}</a></li>
          @end
        </ul>
      @end
    </div>
  </footer>
@end

Install

npm install --save-dev prettier prettier-plugin-edge

Prettier auto-detects the plugin for .edge files when it is a project dependency — no .prettierrc changes required.

npx prettier --write "resources/views/**/*.edge"

What it formats

HTMLTag and attribute layout, indentation, attribute wrapping at printWidth, self-closing void elements.
Edge interpolations{{ … }}, {{{ … }}}, @{{ … }}, @{{{ … }}}, {{-- … --}}.
Edge tagsBlock (@if, @each, @component, @slot, @pushTo, @can, @error, …), inline (@let, @include, @inject, @vite, …), void (@!card(...)), branches (@elseif, @else), raw (@raw … @end).
Components-as-tags@card(...) … @end and @!card({...}) with arbitrarily nested object and array arguments.
Embedded <script>Prettier's JavaScript formatter.
Embedded <style>Prettier's CSS formatter.
JavaScript in {{ … }}Prettier's JavaScript formatter, with printWidth adjusted for the host indent.
Alpine.js / Livewire attrs@click="…", @click.prevent="…", @toggle-mobile-nav.window="…" — recognised as HTML attributes, not Edge tags.
Preserved verbatim@raw … @end bodies, <pre>, <textarea>, <!DOCTYPE …>, <?xml … ?>, <![CDATA[ … ]]>, conditional comments, HTML entities.

Worked examples

Dynamic attributes with embedded JavaScript
<button {{
  $props
    .merge({ type: 'button', class: ['btn', 'btn-primary'] })
    .toAttrs()
}}>
  {{{ await $slots.main() }}}
</button>

The {{ … }} body is formatted with Prettier's JavaScript formatter, and the printer glues <button {{ and }}> around the indented expression so the layout reads naturally.

Multi-line tag arguments collapse against the parens
@!input.control({
  type: 'email',
  name: 'email',
  required: true,
  placeholder: 'Subscribe to our newsletter',
})

Object and array literals at the end of a @tag(...) argument list collapse onto the closing ) rather than wrapping it onto its own line.

Long HTML attributes wrap, but the value is never split
<div
  class="container mx-auto px-5 lg:px-10 py-24 lg:border-x border-woodsmoke-900 relative"
>
  …
</div>

The plugin never wraps inside a class="…" value — Tailwind users keep their utility ordering intact.

SVG: containers and self-closing leaves
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  <path d="M12 2L2 7l10 5 10-5-10-5z" fill="currentColor" />
  <circle cx="12" cy="12" r="3" />
  <g transform="translate(4,4)">
    <rect width="16" height="16" rx="2" />
  </g>
</svg>

SVG containers and leaves are treated as block-level so they always sit on their own lines, with a space before /> when attributes fit.

Options

Standard Prettier options
OptionDefaultNotes
printWidth80Drives HTML attribute wrapping and embedded-JS layout.
tabWidth2Indent unit.
useTabsfalseIndent character.
singleQuotefalsePropagates to embedded JS. HTML attribute quoting is controlled by edgeAttributeQuotes.
endOfLine"lf"
bracketSameLinefalseWhen true, the closing > of a multi-line opening tag glues to the last attribute.
singleAttributePerLinefalseWhen true, every HTML attribute is placed on its own line.
Edge-specific options
OptionDefaultNotes
edgeMustacheSpacing10 or 1 space inside {{ … }}, {{{ … }}}, @{{ … }}, {{-- … --}}.
edgeAttributeQuotes"double"One of "double", "single", "preserve". "preserve" keeps the source quote per attribute.
edgeBlankLinesInBlocks1Maximum blank lines preserved between block-level siblings.

Example .prettierrc:

{
  "printWidth": 100,
  "singleQuote": true,
  "bracketSameLine": true,
  "edgeAttributeQuotes": "preserve",
  "edgeBlankLinesInBlocks": 2
}

See docs/adr/0008-options-surface.md for the rationale and the list of Prettier options deliberately ignored.

Editor integration

Most Prettier IDE integrations pick the plugin up automatically once it is installed. In VS Code the standard Prettier extension is enough — point editor.defaultFormatter at it for .edge files.

// .vscode/settings.json
{
  "[edge]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  }
}

Status

Early release. Validated against two production AdonisJS sites — 256 of 256 templates round-trip cleanly. Files that fail to parse are written back unchanged, never corrupted.

The plugin owns its HTML printer end-to-end; it does not delegate to Prettier's html parser. HTML semantics — entity preservation, boolean attributes, <!DOCTYPE>, CDATA, conditional comments, processing instructions, SVG self-closing — are handled in this codebase. See docs/adr/0001-pipeline-shape.md for why.

Roadmap

  • Additional ecosystem tags as user reports surface them.
  • Public edgeKnownBlockTags / edgeKnownInlineTags config, if community templates show a real need.

How it works

The pipeline runs in this order, each stage scoped to one job:

StageWhat it does
preprocessStrip <script>/<style>/<pre>/<textarea> bodies and <?xml … ?> PIs into a side table; mask Alpine.js attributes; extract multi-line tag args.
edge-lexTokenize Edge constructs via edge-lexer.
edge-parseWalk the token stream and replace each Edge construct with an HTML stand-in; the original node lives in a side table.
parse-htmlParse the masked HTML with angular-html-parser.
spliceWalk the HTML AST and substitute Edge nodes back in by stand-in id, producing one mixed tree.
restorePull the raw-text bodies and processing instructions from the side table back onto their nodes.
prepareAsync pre-pass: format every JS expression, <script>, and <style> body via prettier.format(…).
printWalk the mixed AST and emit a Prettier doc using group/indent/hardline/softline/line builders.

The architecture decisions are documented as ADRs under docs/adr/.

Development

npm test                                                  # 75 unit + corpus fixtures
UPDATE_SNAPSHOTS=1 npm test                               # regenerate expected.edge files
EDGE_SMOKE_DIRS=/path/to/views npm test                   # parse-only check against real templates
EDGE_DEBUG_PARSE=1 npm test                               # log parse errors instead of swallowing

Fixtures live under test/fixtures/:

  • units/<category>/<name>/{input,expected}.edge — focused cases. Optional options.json overrides Prettier options.
  • corpus/<project>/<file>.edge — whole real-world files. Each one is asserted to parse cleanly and be idempotent. A sibling <file>.expected.edge makes the baseline frozen.

To add a new test case, drop a file in the right place and run UPDATE_SNAPSHOTS=1 npm test. Review the diff in the generated expected.edge before committing.

License

MIT

Keywords

prettier

FAQs

Package last updated on 28 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts