Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4ee7261
Define new plugin options
Sep 14, 2019
67c0626
Define basic tests
Shinigami92 Sep 14, 2019
0e79c6c
Modify basic sort test
Shinigami92 Sep 14, 2019
3cbee17
Implement sorting
Shinigami92 Sep 14, 2019
ff516ed
Add test case
Sep 14, 2019
5414a25
Modify compare function
Sep 14, 2019
f93656f
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 16, 2019
b044cda
Merge branch 'feature/sort-attributes' of https://github.com/prettier…
Shinigami92 Sep 16, 2019
f79116f
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 16, 2019
4237506
Only sort if more then one attribute
Shinigami92 Sep 16, 2019
d7365dd
Merge branch 'master' into feature/sort-attributes
Shinigami92 Jan 14, 2020
3aa1b4a
Format
Jan 14, 2020
b357196
Increment and reorder by option version
Jan 14, 2020
0f5d9f1
Rebuild sorting
Jan 14, 2020
ecc0c63
Restructure project
Jan 14, 2020
c268d23
Set version to 1.2.0-beta.1
Jan 14, 2020
212648e
Merge branch 'master' into feature/sort-attributes
Feb 28, 2020
9f21f5d
Improve default order
Feb 28, 2020
bd6213f
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 16, 2020
1fec4ed
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 26, 2020
678762a
Start to reimplement sorting
Shinigami92 Sep 26, 2020
93fa39f
Fix default value
Shinigami92 Sep 26, 2020
72d43a0
Sort attributes to the end
Shinigami92 Sep 26, 2020
2fc8b93
Sort with patterns
Shinigami92 Sep 26, 2020
f4995fe
Beginning take precedence over end
Shinigami92 Sep 26, 2020
279bbc3
Cleanup
Shinigami92 Sep 26, 2020
a0e768f
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 29, 2020
c83002a
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 29, 2020
64288c6
Merge branch 'master' into feature/sort-attributes
Shinigami92 Sep 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/options/attribute-sorting/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { CATEGORY_PUG } from '..';

const pugSortAttributesOption = {
since: '1.7.0',
category: CATEGORY_PUG,
type: 'path',
array: true,
default: [{ value: [] }],
description: ''
};

export const PUG_SORT_ATTRIBUTES_BEGINNING_OPTION = {
...pugSortAttributesOption,
description: 'Define a list of patterns for attributes that are sorted to the beginning.'
};

export const PUG_SORT_ATTRIBUTES_END_OPTION = {
...pugSortAttributesOption,
description: 'Define a list of patterns for attributes that are sorted at the end.'
};
68 changes: 68 additions & 0 deletions src/options/attribute-sorting/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { AttributeToken } from 'pug-lexer';

type CompareResult = -1 | 0 | 1;

function compareByIndex(leftIndex: number, rightIndex: number): CompareResult {
if (leftIndex !== -1 && rightIndex === -1) {
return -1;
}
if (leftIndex === -1 && rightIndex !== -1) {
return 1;
}
const result = leftIndex - rightIndex;
if (result <= -1) {
return -1;
}
if (result >= 1) {
return 1;
}
return 0;
}

export function compareAttributeToken(
a: AttributeToken,
b: AttributeToken,
sortAttributes: string[],
moveToEnd: boolean = false
): CompareResult {
const sortPatterns: RegExp[] = sortAttributes.map((sort) => new RegExp(sort));

const aName = a.name;
const bName = b.name;

let result: CompareResult = 0;

if (result === 0) {
let aIndex: number = moveToEnd ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
let bIndex: number = moveToEnd ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
let aFound = false;
let bFound = false;
for (let index = 0; index < sortPatterns.length; index++) {
const pattern = sortPatterns[index];
if (!aFound && pattern.test(aName)) {
aIndex = index;
aFound = true;
}
if (!bFound && pattern.test(bName)) {
bIndex = index;
bFound = true;
}
if (aFound && bFound) {
break;
}
}

result = compareByIndex(aIndex, bIndex);
}

return result;
}

export function partialSort<T>(arr: T[], start: number, end: number, compareFn?: (a: T, b: T) => number): T[] {
const preSorted: T[] = arr.slice(0, start);
const postSorted: T[] = arr.slice(end);
const sorted: T[] = arr.slice(start, end).sort(compareFn);
arr.length = 0;
arr.push(...preSorted.concat(sorted).concat(postSorted));
return arr;
}
4 changes: 3 additions & 1 deletion src/options/converge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export function convergeOptions(options: ParserOptions & PugParserOptions): PugP
pugSemi: options.pugSemi ?? options.semi,
attributeSeparator: options.pugAttributeSeparator ?? options.attributeSeparator,
closingBracketPosition: options.pugClosingBracketPosition ?? options.closingBracketPosition,
commentPreserveSpaces: options.pugCommentPreserveSpaces ?? options.commentPreserveSpaces
commentPreserveSpaces: options.pugCommentPreserveSpaces ?? options.commentPreserveSpaces,
pugSortAttributesBeginning: options.pugSortAttributesBeginning,
pugSortAttributesEnd: options.pugSortAttributesEnd
};
}
8 changes: 7 additions & 1 deletion src/options/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ParserOptions } from 'prettier';
import { AttributeSeparator, ATTRIBUTE_SEPARATOR_OPTION, PUG_ATTRIBUTE_SEPARATOR_OPTION } from './attribute-separator';
import { PUG_SORT_ATTRIBUTES_BEGINNING_OPTION, PUG_SORT_ATTRIBUTES_END_OPTION } from './attribute-sorting';
import {
ClosingBracketPosition,
CLOSING_BRACKET_POSITION_OPTION,
Expand Down Expand Up @@ -46,6 +47,9 @@ export interface PugParserOptions

commentPreserveSpaces: CommentPreserveSpaces;
pugCommentPreserveSpaces: CommentPreserveSpaces | null;

pugSortAttributesBeginning: string[];
pugSortAttributesEnd: string[];
}

export const options = {
Expand All @@ -61,5 +65,7 @@ export const options = {
closingBracketPosition: CLOSING_BRACKET_POSITION_OPTION,
pugClosingBracketPosition: PUG_CLOSING_BRACKET_POSITION_OPTION,
commentPreserveSpaces: COMMENT_PRESERVE_SPACES_OPTION,
pugCommentPreserveSpaces: PUG_COMMENT_PRESERVE_SPACES_OPTION
pugCommentPreserveSpaces: PUG_COMMENT_PRESERVE_SPACES_OPTION,
pugSortAttributesBeginning: PUG_SORT_ATTRIBUTES_BEGINNING_OPTION,
pugSortAttributesEnd: PUG_SORT_ATTRIBUTES_END_OPTION
};
34 changes: 33 additions & 1 deletion src/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
import { DOCTYPE_SHORTCUT_REGISTRY } from './doctype-shortcut-registry';
import { createLogger, Logger, LogLevel } from './logger';
import { AttributeSeparator, resolveAttributeSeparatorOption } from './options/attribute-separator';
import { compareAttributeToken, partialSort } from './options/attribute-sorting/utils';
import { ClosingBracketPosition, resolveClosingBracketPositionOption } from './options/closing-bracket-position';
import { CommentPreserveSpaces, formatCommentPreserveSpaces } from './options/comment-preserve-spaces';
import { ArrowParens } from './options/common';
Expand Down Expand Up @@ -87,6 +88,8 @@ export interface PugPrinterOptions {
readonly attributeSeparator: AttributeSeparator;
readonly closingBracketPosition: ClosingBracketPosition;
readonly commentPreserveSpaces: CommentPreserveSpaces;
readonly pugSortAttributesBeginning: string[];
readonly pugSortAttributesEnd: string[];
}

export class PugPrinter {
Expand Down Expand Up @@ -124,7 +127,7 @@ export class PugPrinter {
private pipelessText: boolean = false;
private pipelessComment: boolean = false;

public constructor(private readonly tokens: ReadonlyArray<Token>, private readonly options: PugPrinterOptions) {
public constructor(private tokens: Token[], private readonly options: PugPrinterOptions) {
this.indentString = options.pugUseTabs ? '\t' : ' '.repeat(options.pugTabWidth);
this.quotes = this.options.pugSingleQuote ? "'" : '"';
this.otherQuotes = this.options.pugSingleQuote ? '"' : "'";
Expand Down Expand Up @@ -458,6 +461,35 @@ export class PugPrinter {
if (this.currentLineLength > this.options.pugPrintWidth) {
this.wrapAttributes = true;
}

if (this.options.pugSortAttributesEnd.length > 0) {
const startAttributesIndex: number = this.tokens.indexOf(token);
const endAttributesIndex: number = tempIndex;
if (endAttributesIndex - startAttributesIndex > 2) {
this.tokens = partialSort(this.tokens, startAttributesIndex + 1, endAttributesIndex, (a, b) =>
compareAttributeToken(
a as AttributeToken,
b as AttributeToken,
this.options.pugSortAttributesEnd,
true
)
);
}
}

if (this.options.pugSortAttributesBeginning.length > 0) {
const startAttributesIndex: number = this.tokens.indexOf(token);
const endAttributesIndex: number = tempIndex;
if (endAttributesIndex - startAttributesIndex > 2) {
this.tokens = partialSort(this.tokens, startAttributesIndex + 1, endAttributesIndex, (a, b) =>
compareAttributeToken(
a as AttributeToken,
b as AttributeToken,
this.options.pugSortAttributesBeginning
)
);
}
}
}
return result;
}
Expand Down
3 changes: 3 additions & 0 deletions tests/options/sortAttributes/formatted.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
span.a.b(style="background: #000")
img(src="logo.png", alt="Logo")
div(v-for="value in values", :key="value.key", @click="doSomething(value)")
59 changes: 59 additions & 0 deletions tests/options/sortAttributes/sort-attributes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { format } from 'prettier';
import { AttributeToken } from 'pug-lexer';
import { compareAttributeToken } from '../../../src/options/attribute-sorting/utils';
import { plugin } from './../../../src/index';

function createAttributeToken(name: string): AttributeToken {
return {
name,
val: 'dummy',
mustEscape: false,
type: 'attribute',
loc: {
start: { line: 0, column: 0 },
end: { line: 0, column: 0 }
}
};
}

describe('Options', () => {
describe('sortAttributes', () => {
test('should sort attributes', () => {
const expected: string = readFileSync(resolve(__dirname, 'formatted.pug'), 'utf8');
const code: string = readFileSync(resolve(__dirname, 'unformatted.pug'), 'utf8');
const actual: string = format(code, {
parser: 'pug' as any,
plugins: [plugin],
// @ts-ignore
pugSortAttributesBeginning: ['v-for', ':key', 'src', 'alt'],
// @ts-ignore
pugSortAttributesEnd: ['@click']
});

expect(actual).toBe(expected);
});
});

describe('sort utilities', () => {
test('compare 1', () => {
const expected: ReadonlyArray<string> = ['v-for', ':key', 'src', 'alt'];
const code: string[] = ['alt', ':key', 'v-for', 'src'];
const actual: string[] = code.sort((a, b) =>
compareAttributeToken(createAttributeToken(a), createAttributeToken(b), ['v-for', ':key', 'src', 'alt'])
);

expect(actual).toStrictEqual(expected);
});
test('compare 2', () => {
const expected: ReadonlyArray<string> = ['v-for', ':key', 'src', 'alt', '@click', ':disabled'];
const code: string[] = ['v-for', ':disabled', ':key', '@click', 'src', 'alt'];
const actual: string[] = code.sort((a, b) =>
compareAttributeToken(createAttributeToken(a), createAttributeToken(b), ['@click', ':disabled'], true)
);

expect(actual).toStrictEqual(expected);
});
});
});
3 changes: 3 additions & 0 deletions tests/options/sortAttributes/unformatted.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
span(style="background: #000", class="a b")
img(alt="Logo", src="logo.png")
div(v-for="value in values", @click="doSomething(value)", :key="value.key")