Coder Social home page Coder Social logo

niklaspor / prettier-plugin-organize-attributes Goto Github PK

View Code? Open in Web Editor NEW
197.0 2.0 12.0 217 KB

Organize your HTML attributes automatically with Prettier 🧼

License: MIT License

TypeScript 84.91% HTML 10.38% Vue 3.77% JavaScript 0.94%
prettier html organize attributes sort vue angular

prettier-plugin-organize-attributes's Introduction

prettier-plugin-organize-attributes npm

Organize your HTML attributes automatically with Prettier 🧼

npm i prettier prettier-plugin-organize-attributes -D
  • Supports Angular, Vue & HTML with 0 configuration
  • Groups are matched from top to bottom.
  • Attributes are matched against RegExps or presets.
    • A list of additional presets can be found here.
    • Attributes which are not matched are put into $DEFAULT.
    • If $DEFAULT is not specified they are appended at the end.
  • Attributes in each group can be ordered ASC and DESC by specifing attributeSort.
    • Order inside groups remains the same if attributeSort is not used.

Usage

The following files also work out of the box if the plugin is specified:

Starting with Prettier 3 auto-discovery has been removed. Configuration is required ⬇️

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"]
}

Read below for writing custom attribute orders and configurations ⤵️

Groups

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"],
  "attributeGroups": ["^class$", "^(id|name)$", "$DEFAULT", "^aria-"]
}
<!-- input -->
<div
  aria-disabled="true"
  name="myname"
  id="myid"
  class="myclass"
  src="other"
></div>
<!-- output -->
<div
  class="myclass"
  name="myname"
  id="myid"
  src="other"
  aria-disabled="true"
></div>

Sort

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"],
  "attributeGroups": ["$DEFAULT", "^data-"],
  "attributeSort": "ASC"
}
<!-- input -->
<div a="a" c="c" b="b" data-c="c" data-a="a" data-b="b"></div>
<!-- output -->
<div a="a" b="b" c="c" data-a="a" data-b="b" data-c="c"></div>

Case-Sensitivity

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"],
  "attributeGroups": ["^group-a$", "^group-b$", "^group-A$", "^group-B$"],
  "attributeIgnoreCase": false
}
<!-- input -->
<div group-b group-B group-A group-a></div>
<!-- output -->
<div group-a group-b group-A group-B></div>

Presets

HTML

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"]
}
<!-- input.html -->
<div id="id" other="other" class="style"></div>
<!-- output.html -->
<div class="style" id="id" other="other"></div>

Angular

// .prettierrc
{}
<!-- input.component.html -->
<div
  (output)="output()"
  [input]="input"
  *ngIf="ngIf"
  class="style"
  [(ngModel)]="binding"
  id="id"
  other="other"
  [@inputAnimation]="value"
  @simpleAnimation
></div>
<!-- output.component.html -->
<div
  class="style"
  id="id"
  *ngIf="ngIf"
  @simpleAnimation
  [@inputAnimation]="value"
  [(ngModel)]="binding"
  [input]="input"
  (output)="output()"
  other="other"
></div>

Angular Custom

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"],
  "attributeGroups": [
    "$ANGULAR_OUTPUT",
    "$ANGULAR_TWO_WAY_BINDING",
    "$ANGULAR_INPUT",
    "$ANGULAR_STRUCTURAL_DIRECTIVE"
  ]
}
<!-- input -->
<div
  [input]="input"
  (output)="output()"
  *ngIf="ngIf"
  other="other"
  class="style"
  [(ngModel)]="binding"
  id="id"
></div>
<!-- output -->
<div
  (output)="output()"
  [(ngModel)]="binding"
  [input]="input"
  *ngIf="ngIf"
  class="style"
  id="id"
  other="other"
></div>

Vue

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"]
}
<!-- input.vue -->
<template>
  <div other="other" class="class" v-on="whatever" v-bind="bound" id="id"></div>
</template>
<!-- output.vue -->
<template>
  <div class="class" id="id" v-on="whatever" v-bind="bound" other="other"></div>
</template>

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-attributes"],
  "attributeGroups": ["$CODE_GUIDE"]
}
<!-- input -->
<div
  other="other"
  value="value"
  type="type"
  title="title"
  src="src"
  role="role"
  name="name"
  id="id"
  href="href"
  for="for"
  data-test="test"
  class="class"
  aria-test="test"
  alt="alt"
></div>
<!-- output -->
<div
  class="class"
  id="id"
  name="name"
  data-test="test"
  src="src"
  for="for"
  type="type"
  href="href"
  value="value"
  title="title"
  alt="alt"
  role="role"
  aria-test="test"
  other="other"
></div>

prettier-plugin-organize-attributes's People

Contributors

marsibarsi avatar modkaffes avatar nickbullock avatar niklaspor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

prettier-plugin-organize-attributes's Issues

Using localeCompare may be dangerous

Hi,

My teammates and me have noticed you guys are using localeCompare to sort attributes:

group.values.sort((a, b) => getString(a).localeCompare(getString(b)));

It took me a while to figure out why prettier sorts the HTML attributes differently on different machines (localeCompare uses the locale stored in the OS).

You should maybe consider changing the compare method :)

Thank you!

Option to ignore angular "prefixes"

Hi,

we can write angular inputs now as simple attributes, e.g.

<app-user canDelete="true">

instead of

<app-user [canDelete]="true">

But because of the sorting attributes that belong together (just by name) are separated apart. Therefore it would be great to have an option to just ingore the "Prefixes" like [, (, *

Add support for Lit's `html` template literals

Hello, thanks for making this neat plugin :)
Tested it on bare HTML, works awesome!

I'd like to know if there is anyway to format attributes inside html templates literals, from Lit Custom Elements specifically.

Prettier is already taking effect for me here, without additional configuration (AFAIK), following the .prettierrc

Sample of what can be sorted:

render() {
		return html`
			<sl-card>
				<sl-button-group>
					<sl-button
						class=${classMap({
							'stop-button': true,
							'is-stopped': kl.currentTime === 0,
						})}
						pill
						size="large"
						@click=${() => kl.stop()}
					>
						<sl-icon name=${'stop-fill'}></sl-icon>
 
// ...

Not strictly related, but this: https://github.com/43081j/postcss-lit is allowing Stylelint to handle css template literals, useful for CSS-in-JS folks too, I guess.

[Feature Request] Support for single file components

This plugin works great if the HTML is in it's own file! But now with Standalone Components, Single File components are coming to the forefront a bit more now (and they are clean for small components). Unfortunately this plugin does not work with components that use template strings for the HTML template like so:

import { NgIf, NgOptimizedImage } from '@angular/common';
import { Component, Input } from '@angular/core';
import { HttpsPipe } from '@trellis/shared/util/formatting';
import { nanoId } from '@trellis/shared/util/id';
import { SafeHtmlModule } from '@trellis/shared/util/web/formatting';

@Component({
    selector: 'display',
    template: `
        <div class="w-100 aspect-ratio"></div>
    `,
    standalone: true,
})
export class MyComponent {
}

aspect-ratio should be before w-100 but the plugin must not recognize single file components and HTML template strings.

[Feature Request] Add attribute sorting for Laravel components

Hi there! I'm currently working with Laravel and observed that the attributes aren't sorted when using Laravel blade components. For instance...

<x-component-name name="name" :label="$phpProperty" wire:model="livewire.property" />

Could we organize these attributes? Also, it would be helpful if the configuration file allowed us to organize and set a specific order for these attributes.

Allow configuration of regex for angular components

In my project I use additional naming for angular components like xy.view.html or xy.dialog.html
It would be great if there was the possibility to add additional suffixes that will be recognized as angular components.

Incompatibility with prettier-plugin-tailwindcss

Hey!

When used with prettier-plugin-tailwindcss module, it makes it stop working. The attributes are properly organized, but the class names inside the class attribute don't move.

Would be nice to fix it, we can't use the module otherwise (or have to choose one or the other) :(

I tried on a brand new project using the lastest versions.

Here is the prettier config:

{
    "trailingComma": "all",
    "tabWidth": 4,
    "semi": true,
    "singleQuote": true,
    "bracketSpacing": true,
    "bracketSameLine": false,
    "printWidth": 1000,
    "vueIndentScriptAndStyle": true,
    "singleAttributePerLine": false,
    "plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-organize-attributes"],
    "attributeGroups": ["^(:|v-)is$", "^v-for$", "^v-(if|else-if|else|show|cloak)$", "^v-(once|pre|memo)$", "^:?id$", "^:?key$", "^:?ref$", "^(v-)?slot$", "^#", "^v-model$", "^v-(?!bind|on|html|text)", "^class$", "^(v-bind)?:class$", "^((v-bind)?:)?(?!data-|v-|:|@|#)", "$DEFAULT", "^((v-bind)?:)?data-", "^v-bind$", "^v-on", "^@", "^v-html$", "^v-text$"]
}

If I remove prettier-plugin-organize-attributes, the tailwind one works.

Error is thrown: TypeError: options.groups.flatMap is not a function

Got an error in the pipeline:

An unhandled exception occurred: Cannot create property 'currentNode' on string 'TypeError: options.groups.flatMap is not a function
--
233 | at Object.miniorganize (/codebuild/output/src716443509/src/node_modules/prettier-plugin-organize-attributes/lib/organize.js:26:35)
234 | at transformNode (/codebuild/output/src716443509/src/node_modules/prettier-plugin-organize-attributes/lib/index.js:54:33)
235 | at _a.forEach (/codebuild/output/src716443509/src/node_modules/prettier-plugin-organize-attributes/lib/index.js:62:85)
236 | at Array.forEach (<anonymous>)
237 | at transformNode (/codebuild/output/src716443509/src/node_modules/prettier-plugin-organize-attributes/lib/index.js:62:66)
238 | at transformRootNode (/codebuild/output/src716443509/src/node_modules/prettier-plugin-organize-attributes/lib/index.js:48:5)
239 | at Object.parse (/codebuild/output/src716443509/src/node_modules/prettier-plugin-organize-attributes/lib/index.js:30:40)
240 | at Object.parse (/codebuild/output/src716443509/src/node_modules/prettier/index.js:13625:19)
241 | at coreFormat (/codebuild/output/src716443509/src/node_modules/prettier/index.js:14899:14)
242 | at format (/codebuild/output/src716443509/src/node_modules/prettier/index.js:15131:14)'

Unfortunately I can't provide the html for the file it was linting. Hopefully the issue can be solved without it!

Angular Material & i18n

I use Angular Material and if I use your plugin than I would like to have all the Angular Material attributes at the beginning, e.g.

<button mat-button color="warn">Warn</button>

Should move mat- at the beginning. Same in <th mat-header-cell...

I'm not really clear about the other attributes, e.g. matTooltip, matSuffix (in mat-button), matBadge, etc. But preferably after the mat- group.

Definitely I want to have all i18n at the very ending. Sorted by the optional additional arguments, e.g. i18n-matTooltip="@@tooltip"

Do you have a config example?

Add support for "lwc" parser

In addition to "vue", "angular" and "html" there is also "lwc" parser, refer to https://prettier.io/docs/en/options.html

I got it working by adding one line of code. Without this change the plugin makes no changes to my LWCs

export const parsers = {
  html: wrapParser(prettierParsers.html),
  lwc: wrapParser(prettierParsers.lwc), // Add this to make it work
  vue: wrapParser(prettierParsers.vue),
  angular: wrapParser(prettierParsers.angular),
};

Add option to group when attribute no has value

Would it be possible to add an option to group attributes when they don't have a value? This would be useful for Angular.

Example:
<app-selector> class="some-class" id="anId" formControlName="someControl" appDisableControl required [(ngModel)]="someModel" </app-selector>

Would be very helpful to choose where appDisableControl and required were placed in the list.

Thanks

Error: options.attributeGroups is not iterable

This plugin looks interesting. But I can't get it to use in it's basic form however. Am I doing something wrong?

I'm using VSCode and I've setup prettier to format on save. With the below configuration I'm getting error:

["ERROR" - 15:46:36] Error formatting document.
TypeError: options.attributeGroups is not iterable
    at transformRootNode (/Users/jorn/dev/aem/ui.apps/node_modules/prettier-plugin-organize-attributes/src/index.ts:67:30)
    at Object.parse (/Users/jorn/dev/aem/ui.apps/node_modules/prettier-plugin-organize-attributes/src/index.ts:55:5)
    at Object.parse (/Users/jorn/dev/aem/ui.apps/node_modules/prettier/index.js:7334:23)
    at coreFormat (/Users/jorn/dev/aem/ui.apps/node_modules/prettier/index.js:8645:18)
    at formatWithCursor2 (/Users/jorn/dev/aem/ui.apps/node_modules/prettier/index.js:8837:18)
    at /Users/jorn/dev/aem/ui.apps/node_modules/prettier/index.js:37229:12
    at Object.format (/Users/jorn/dev/aem/ui.apps/node_modules/prettier/index.js:37243:12)
    at t.PrettierMainThreadInstance.format (/Users/jorn/.vscode/extensions/esbenp.prettier-vscode-10.1.0/dist/extension.js:1:18023)
    at t.default.format (/Users/jorn/.vscode/extensions/esbenp.prettier-vscode-10.1.0/dist/extension.js:1:16114)
    at t.PrettierEditProvider.provideEdits (/Users/jorn/.vscode/extensions/esbenp.prettier-vscode-10.1.0/dist/extension.js:1:12672)
    at U.provideDocumentFormattingEdits (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:104:44948)

.prettierrc

{
    "plugins": ["prettier-plugin-organize-attributes"],
    "useTabs": false,
    "tabWidth": 4,
    "singleQuote": true,
    "printWidth": 120,
    "trailingComma": "all",
    "singleAttributePerLine": true,
    "bracketSameLine": true
}

Even when I do provide attributeGroups as documented I get this error. Eg:

{
    "plugins": ["prettier-plugin-organize-attributes"],
    "attributeGroups": ["^class$", "^(id|name)$", "$DEFAULT", "^aria-"],
    "useTabs": false,
    "tabWidth": 4,
    "singleQuote": true,
    "printWidth": 120,
    "trailingComma": "all",
    "singleAttributePerLine": true,
    "bracketSameLine": true
}

It looks like it breaks on https://github.com/NiklasPor/prettier-plugin-organize-attributes/blob/50a0c4f8809c34b351a400011b7734701285b5e9/src/index.ts#L67C33-L67C33

Add ability to ignore a file

Hello,

Could it be possible to add a feature to ignore a file so imports will not be ordered ?
For instance, in my project we used previously "prettier-plugin-organize-imports", and they added a feature later to ignore a file from being formatted by the plugin, by adding the following comment :

// organize-imports-ignore

Full explaination could be found here, and related commit also here, that consists only of having an if condition to check if the file constains that comment.

Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.