Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@prettier/plugin-pug

Package Overview
Dependencies
Maintainers
12
Versions
104
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@prettier/plugin-pug - npm Package Compare versions

Comparing version 1.1.5 to 1.1.6

dist/printer.js

13

CHANGELOG.md
# Next
[diff](https://github.com/prettier/plugin-pug/compare/1.1.5...master)
[diff](https://github.com/prettier/plugin-pug/compare/1.1.6...master)
# 1.1.6
[diff](https://github.com/prettier/plugin-pug/compare/1.1.5...1.1.6)
- Improve handling of Angular attribute values ([#67], [#68])
- Restructure internal code
- Add issue templates
[#67]: https://github.com/prettier/plugin-pug/issues/67
[#68]: https://github.com/prettier/plugin-pug/issues/68
# 1.1.5

@@ -6,0 +17,0 @@

6

dist/options/index.js

@@ -23,3 +23,3 @@ "use strict";

result += input
.substring(firstNonSpace)
.slice(firstNonSpace)
.trim()

@@ -32,3 +32,3 @@ .replace(/\s\s+/g, ' ');

result = result.replace(/\s\s+/g, ' ');
if (!pipeless && input.startsWith(' ')) {
if (!pipeless && input[0] === ' ') {
result = ` ${result}`;

@@ -84,2 +84,2 @@ }

};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb3B0aW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFhLFFBQUEsWUFBWSxHQUFXLEtBQUssQ0FBQztBQVMxQyxTQUFnQiwrQkFBK0IsQ0FBQyxrQkFBMEM7SUFDekYsUUFBUSxrQkFBa0IsRUFBRTtRQUMzQixLQUFLLFFBQVE7WUFDWixPQUFPLElBQUksQ0FBQztRQUNiLEtBQUssV0FBVztZQUNmLE9BQU8sS0FBSyxDQUFDO0tBQ2Q7SUFDRCxNQUFNLElBQUksS0FBSyxDQUNkLHFEQUFxRCxrQkFBa0IsOENBQThDLENBQ3JILENBQUM7QUFDSCxDQUFDO0FBVkQsMEVBVUM7QUFFRCxTQUFnQiwyQkFBMkIsQ0FDMUMsS0FBYSxFQUNiLHFCQUE0QyxFQUM1QyxXQUFvQixLQUFLO0lBRXpCLFFBQVEscUJBQXFCLEVBQUU7UUFDOUIsS0FBSyxjQUFjLENBQUMsQ0FBQztZQUNwQixJQUFJLE1BQU0sR0FBVyxFQUFFLENBQUM7WUFDeEIsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDO1lBQ3RCLEtBQUssYUFBYSxFQUFFLGFBQWEsR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBSyxHQUFHLEVBQUUsYUFBYSxFQUFFLEVBQUU7Z0JBQ2xHLE1BQU0sSUFBSSxHQUFHLENBQUM7YUFDZDtZQUNELE1BQU0sSUFBSSxLQUFLO2lCQUNiLFNBQVMsQ0FBQyxhQUFhLENBQUM7aUJBQ3hCLElBQUksRUFBRTtpQkFDTixPQUFPLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3pCLE9BQU8sTUFBTSxDQUFDO1NBQ2Q7UUFDRCxLQUFLLFVBQVUsQ0FBQyxDQUFDO1lBQ2hCLElBQUksTUFBTSxHQUFXLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDdkMsSUFBSSxDQUFDLFFBQVEsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUN2QyxNQUFNLEdBQUcsSUFBSSxNQUFNLEVBQUUsQ0FBQzthQUN0QjtZQUNELE9BQU8sTUFBTSxDQUFDO1NBQ2Q7UUFDRCxLQUFLLFVBQVUsQ0FBQztRQUNoQjtZQUVDLE9BQU8sS0FBSyxDQUFDO0tBQ2Q7QUFDRixDQUFDO0FBL0JELGtFQStCQztBQUVZLFFBQUEsT0FBTyxHQUFHO0lBQ3RCLGtCQUFrQixFQUFFO1FBQ25CLEtBQUssRUFBRSxPQUFPO1FBQ2QsUUFBUSxFQUFFLG9CQUFZO1FBQ3RCLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLFFBQVE7UUFDakIsV0FBVyxFQUFFLHlEQUF5RDtRQUN0RSxPQUFPLEVBQUU7WUFDUjtnQkFDQyxLQUFLLEVBQUUsUUFBUTtnQkFDZixXQUFXLEVBQ1Ysc0dBQXNHO2FBQ3ZHO1lBQ0Q7Z0JBQ0MsS0FBSyxFQUFFLFdBQVc7Z0JBQ2xCLFdBQVcsRUFDVixnSEFBZ0g7YUFDakg7U0FDRDtLQUNEO0lBQ0QscUJBQXFCLEVBQUU7UUFDdEIsS0FBSyxFQUFFLE9BQU87UUFDZCxRQUFRLEVBQUUsb0JBQVk7UUFDdEIsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsVUFBVTtRQUNuQixXQUFXLEVBQUUsNENBQTRDO1FBQ3pELE9BQU8sRUFBRTtZQUNSO2dCQUNDLEtBQUssRUFBRSxVQUFVO2dCQUNqQixXQUFXLEVBQUUsMEVBQTBFO2FBQ3ZGO1lBQ0Q7Z0JBQ0MsS0FBSyxFQUFFLGNBQWM7Z0JBQ3JCLFdBQVcsRUFBRSx5RUFBeUU7YUFDdEY7WUFDRDtnQkFDQyxLQUFLLEVBQUUsVUFBVTtnQkFDakIsV0FBVyxFQUFFLGtFQUFrRTthQUMvRTtTQUNEO0tBQ0Q7Q0FDRCxDQUFDIn0=
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb3B0aW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFhLFFBQUEsWUFBWSxHQUFXLEtBQUssQ0FBQztBQVMxQyxTQUFnQiwrQkFBK0IsQ0FBQyxrQkFBMEM7SUFDekYsUUFBUSxrQkFBa0IsRUFBRTtRQUMzQixLQUFLLFFBQVE7WUFDWixPQUFPLElBQUksQ0FBQztRQUNiLEtBQUssV0FBVztZQUNmLE9BQU8sS0FBSyxDQUFDO0tBQ2Q7SUFDRCxNQUFNLElBQUksS0FBSyxDQUNkLHFEQUFxRCxrQkFBa0IsOENBQThDLENBQ3JILENBQUM7QUFDSCxDQUFDO0FBVkQsMEVBVUM7QUFFRCxTQUFnQiwyQkFBMkIsQ0FDMUMsS0FBYSxFQUNiLHFCQUE0QyxFQUM1QyxXQUFvQixLQUFLO0lBRXpCLFFBQVEscUJBQXFCLEVBQUU7UUFDOUIsS0FBSyxjQUFjLENBQUMsQ0FBQztZQUNwQixJQUFJLE1BQU0sR0FBVyxFQUFFLENBQUM7WUFDeEIsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDO1lBQ3RCLEtBQUssYUFBYSxFQUFFLGFBQWEsR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBSyxHQUFHLEVBQUUsYUFBYSxFQUFFLEVBQUU7Z0JBQ2xHLE1BQU0sSUFBSSxHQUFHLENBQUM7YUFDZDtZQUNELE1BQU0sSUFBSSxLQUFLO2lCQUNiLEtBQUssQ0FBQyxhQUFhLENBQUM7aUJBQ3BCLElBQUksRUFBRTtpQkFDTixPQUFPLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3pCLE9BQU8sTUFBTSxDQUFDO1NBQ2Q7UUFDRCxLQUFLLFVBQVUsQ0FBQyxDQUFDO1lBQ2hCLElBQUksTUFBTSxHQUFXLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDdkMsSUFBSSxDQUFDLFFBQVEsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxFQUFFO2dCQUNsQyxNQUFNLEdBQUcsSUFBSSxNQUFNLEVBQUUsQ0FBQzthQUN0QjtZQUNELE9BQU8sTUFBTSxDQUFDO1NBQ2Q7UUFDRCxLQUFLLFVBQVUsQ0FBQztRQUNoQjtZQUVDLE9BQU8sS0FBSyxDQUFDO0tBQ2Q7QUFDRixDQUFDO0FBL0JELGtFQStCQztBQUVZLFFBQUEsT0FBTyxHQUFHO0lBQ3RCLGtCQUFrQixFQUFFO1FBQ25CLEtBQUssRUFBRSxPQUFPO1FBQ2QsUUFBUSxFQUFFLG9CQUFZO1FBQ3RCLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLFFBQVE7UUFDakIsV0FBVyxFQUFFLHlEQUF5RDtRQUN0RSxPQUFPLEVBQUU7WUFDUjtnQkFDQyxLQUFLLEVBQUUsUUFBUTtnQkFDZixXQUFXLEVBQ1Ysc0dBQXNHO2FBQ3ZHO1lBQ0Q7Z0JBQ0MsS0FBSyxFQUFFLFdBQVc7Z0JBQ2xCLFdBQVcsRUFDVixnSEFBZ0g7YUFDakg7U0FDRDtLQUNEO0lBQ0QscUJBQXFCLEVBQUU7UUFDdEIsS0FBSyxFQUFFLE9BQU87UUFDZCxRQUFRLEVBQUUsb0JBQVk7UUFDdEIsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsVUFBVTtRQUNuQixXQUFXLEVBQUUsNENBQTRDO1FBQ3pELE9BQU8sRUFBRTtZQUNSO2dCQUNDLEtBQUssRUFBRSxVQUFVO2dCQUNqQixXQUFXLEVBQUUsMEVBQTBFO2FBQ3ZGO1lBQ0Q7Z0JBQ0MsS0FBSyxFQUFFLGNBQWM7Z0JBQ3JCLFdBQVcsRUFBRSx5RUFBeUU7YUFDdEY7WUFDRDtnQkFDQyxLQUFLLEVBQUUsVUFBVTtnQkFDakIsV0FBVyxFQUFFLGtFQUFrRTthQUMvRTtTQUNEO0tBQ0Q7Q0FDRCxDQUFDIn0=
{
"name": "@prettier/plugin-pug",
"version": "1.1.5",
"version": "1.1.6",
"description": "Prettier Pug Plugin",

@@ -34,15 +34,15 @@ "main": "dist/index.js",

"devDependencies": {
"@types/jest": "~24.9.0",
"@types/node": "~13.1.8",
"@types/jest": "~25.1.2",
"@types/node": "~13.7.0",
"@types/prettier": "~1.19.0",
"@typescript-eslint/eslint-plugin": "~2.17.0",
"@typescript-eslint/parser": "~2.17.0",
"@typescript-eslint/eslint-plugin": "~2.19.0",
"@typescript-eslint/parser": "~2.19.0",
"benchmark": "~2.1.4",
"eslint": "~6.8.0",
"eslint-config-prettier": "~6.9.0",
"eslint-config-prettier": "~6.10.0",
"eslint-plugin-prettier": "~3.1.2",
"jest": "~24.9.0",
"jest": "~25.1.0",
"jest-junit": "~10.0.0",
"prettier": "1.19.1",
"ts-jest": "~24.3.0",
"ts-jest": "~25.2.0",
"typescript": "~3.7.5"

@@ -49,0 +49,0 @@ },

@@ -225,1 +225,3 @@ <p align="center">

Many thanks also to [@j-f1](https://github.com/j-f1), [@lipis](https://github.com/lipis) and [@azz](https://github.com/azz) for the help in transferring this repos to the prettier orga.
Thanks to [@Peilonrayz](https://github.com/Peilonrayz), who gave me the [idea](https://codereview.stackexchange.com/a/236031/128216) to rewrite the printer into a [class](https://github.com/prettier/plugin-pug/commit/a6e3a4b776ce67f0d5d763aaf1f88c0c860c6ed3) and thus make the code a lot more maintainable.

@@ -1,15 +0,8 @@

import { Doc, FastPath, format, Options, Parser, ParserOptions, Plugin, util } from 'prettier';
import { Doc, FastPath, Options, Parser, ParserOptions, Plugin } from 'prettier';
import * as lex from 'pug-lexer';
import { AttributeToken, EndAttributesToken, Token } from 'pug-lexer';
import { DOCTYPE_SHORTCUT_REGISTRY } from './doctype-shortcut-registry';
import { Token } from 'pug-lexer';
import { createLogger, Logger, LogLevel } from './logger';
import {
formatCommentPreserveSpaces,
options as pugOptions,
PugParserOptions,
resolveAttributeSeparatorOption
} from './options';
import { options as pugOptions, PugParserOptions } from './options';
import { PugPrinter } from './printer';
const { makeString } = util;
const logger: Logger = createLogger(console);

@@ -20,67 +13,2 @@ if (process.env.NODE_ENV === 'test') {

function previousNormalAttributeToken(tokens: Token[], index: number): AttributeToken | undefined {
for (let i: number = index - 1; i > 0; i--) {
const token: Token = tokens[i];
if (token.type === 'start-attributes') {
return;
}
if (token.type === 'attribute') {
if (token.name !== 'class' && token.name !== 'id') {
return token;
}
}
}
return;
}
function printIndent(previousToken: Token, indent: string, indentLevel: number): string {
switch (previousToken?.type) {
case 'newline':
case 'outdent':
return indent.repeat(indentLevel);
case 'indent':
return indent;
}
return '';
}
function formatText(text: string, singleQuote: boolean): string {
let result: string = '';
while (text) {
const start = text.indexOf('{{');
if (start !== -1) {
result += text.slice(0, start);
text = text.substring(start + 2);
const end = text.indexOf('}}');
if (end !== -1) {
let code = text.slice(0, end);
code = code.trim();
code = format(code, { parser: 'babel', singleQuote: !singleQuote, printWidth: 9000 });
if (code.endsWith(';\n')) {
code = code.slice(0, -2);
}
result += `{{ ${code} }}`;
text = text.slice(end + 2);
} else {
result += '{{';
result += text;
text = '';
}
} else {
result += text;
text = '';
}
}
return result;
}
function unwrapLineFeeds(value: string): string {
return value.includes('\n')
? value
.split('\n')
.map((part) => part.trim())
.join('')
: value;
}
export const plugin: Plugin = {

@@ -144,622 +72,13 @@ languages: [

const tokens: Token[] = path.stack[0];
let result: string = '';
let indentLevel: number = 0;
const indent: string = useTabs ? '\t' : ' '.repeat(tabWidth);
let pipelessText: boolean = false;
let pipelessComment: boolean = false;
const alwaysUseAttributeSeparator: boolean = resolveAttributeSeparatorOption(attributeSeparator);
let possibleIdPosition: number = 0;
let possibleClassPosition: number = 0;
let previousAttributeRemapped: boolean = false;
let wrapAttributes: boolean = false;
const codeInterpolationOptions: Options = {
singleQuote: !singleQuote,
printWidth: 9000,
endOfLine: 'lf'
};
if (tokens[0]?.type === 'text') {
result += '| ';
}
for (let index: number = 0; index < tokens.length; index++) {
const token: Token = tokens[index];
const previousToken: Token | undefined = tokens[index - 1];
const nextToken: Token | undefined = tokens[index + 1];
logger.debug('[printers:pug-ast:print]:', JSON.stringify(token));
switch (token.type) {
case 'tag':
result += printIndent(previousToken, indent, indentLevel);
if (!(token.val === 'div' && (nextToken.type === 'class' || nextToken.type === 'id'))) {
result += token.val;
}
possibleIdPosition = result.length;
possibleClassPosition = result.length;
break;
case 'start-attributes':
if (nextToken?.type === 'attribute') {
previousAttributeRemapped = false;
possibleClassPosition = result.length;
result += '(';
const start: number = result.lastIndexOf('\n') + 1;
let lineLength: number = result.substring(start).length;
logger.debug(lineLength, printWidth);
let tempToken: AttributeToken | EndAttributesToken = nextToken;
let tempIndex: number = index + 1;
while (tempToken.type === 'attribute') {
lineLength += tempToken.name.length + 1 + tempToken.val.toString().length;
logger.debug(lineLength, printWidth);
tempToken = tokens[++tempIndex] as AttributeToken | EndAttributesToken;
}
if (lineLength > printWidth) {
wrapAttributes = true;
}
}
break;
case 'attribute': {
if (typeof token.val === 'string') {
const surroundedByQuotes: boolean =
(token.val.startsWith('"') && token.val.endsWith('"')) ||
(token.val.startsWith("'") && token.val.endsWith("'"));
if (surroundedByQuotes) {
if (token.name === 'class') {
// Handle class attribute
let val = token.val;
val = val.substring(1, val.length - 1);
val = val.trim();
val = val.replace(/\s\s+/g, ' ');
const classes: string[] = val.split(' ');
const specialClasses: string[] = [];
const validClassNameRegex: RegExp = /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/;
for (const className of classes) {
if (!validClassNameRegex.test(className)) {
specialClasses.push(className);
continue;
}
// Write css-class in front of attributes
const position: number = possibleClassPosition;
result = [
result.slice(0, position),
`.${className}`,
result.slice(position)
].join('');
possibleClassPosition += 1 + className.length;
result = result.replace(/div\./, '.');
}
if (specialClasses.length > 0) {
token.val = makeString(
specialClasses.join(' '),
singleQuote ? "'" : '"',
false
);
previousAttributeRemapped = false;
} else {
previousAttributeRemapped = true;
break;
}
} else if (token.name === 'id') {
// Handle id attribute
let val = token.val;
val = val.substring(1, val.length - 1);
val = val.trim();
const validIdNameRegex: RegExp = /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/;
if (!validIdNameRegex.test(val)) {
val = makeString(val, singleQuote ? "'" : '"', false);
result += `id=${val}`;
break;
}
// Write css-id in front of css-classes
const position: number = possibleIdPosition;
result = [result.slice(0, position), `#${val}`, result.slice(position)].join(
''
);
possibleClassPosition += 1 + val.length;
result = result.replace(/div#/, '#');
if (previousToken.type === 'attribute' && previousToken.name !== 'class') {
previousAttributeRemapped = true;
}
break;
}
}
}
const hasNormalPreviousToken: AttributeToken | undefined = previousNormalAttributeToken(
tokens,
index
);
if (
previousToken?.type === 'attribute' &&
(!previousAttributeRemapped || hasNormalPreviousToken)
) {
if (alwaysUseAttributeSeparator || /^(\(|\[|:).*/.test(token.name)) {
result += ',';
}
if (!wrapAttributes) {
result += ' ';
}
}
previousAttributeRemapped = false;
if (wrapAttributes) {
result += '\n';
result += indent.repeat(indentLevel + 1);
}
result += `${token.name}`;
if (typeof token.val === 'boolean') {
if (token.val !== true) {
result += `=${token.val}`;
}
} else {
let val = token.val;
if (/^((v-bind|v-on|v-slot)?:|v-model|v-on|@).*/.test(token.name)) {
// Format Vue expression
val = val.trim();
val = val.slice(1, -1);
val = format(val, {
parser: '__vue_expression' as any,
...codeInterpolationOptions
});
val = unwrapLineFeeds(val);
const quotes: "'" | '"' = singleQuote ? "'" : '"';
val = `${quotes}${val}${quotes}`;
} else if (/^(\(.*\)|\[.*\])$/.test(token.name)) {
// Format Angular action or binding
val = val.trim();
val = val.slice(1, -1);
val = format(val, {
parser: '__ng_interpolation' as any,
...codeInterpolationOptions
});
val = unwrapLineFeeds(val);
const quotes: "'" | '"' = singleQuote ? "'" : '"';
val = `${quotes}${val}${quotes}`;
} else if (/^\*.*$/.test(token.name)) {
// Format Angular directive
val = val.trim();
val = val.slice(1, -1);
val = format(val, { parser: '__ng_directive' as any, ...codeInterpolationOptions });
const quotes: "'" | '"' = singleQuote ? "'" : '"';
val = `${quotes}${val}${quotes}`;
} else if (/^(["']{{)(.*)(}}["'])$/.test(val)) {
// Format Angular interpolation
val = val.slice(3, -3);
val = val.trim();
val = val.replace(/\s\s+/g, ' ');
// val = format(val, {
// parser: '__ng_interpolation' as any,
// ...codeInterpolationOptions
// });
const quotes: "'" | '"' = singleQuote ? "'" : '"';
val = `${quotes}{{ ${val} }}${quotes}`;
} else if (/^["'](.*)["']$/.test(val)) {
val = makeString(val.slice(1, -1), singleQuote ? "'" : '"', false);
} else if (val === 'true') {
// The value is exactly true and is not quoted
break;
} else if (token.mustEscape) {
val = format(val, {
parser: '__js_expression' as any,
...codeInterpolationOptions
});
} else {
// The value is not quoted and may be js-code
val = val.trim();
val = val.replace(/\s\s+/g, ' ');
if (val.startsWith('{ ')) {
val = `{${val.substring(2, val.length)}`;
}
}
if (token.mustEscape === false) {
result += '!';
}
result += `=${val}`;
}
break;
}
case 'end-attributes':
if (wrapAttributes) {
result += '\n';
result += indent.repeat(indentLevel);
}
wrapAttributes = false;
if (result.endsWith('(')) {
// There were no attributes
result = result.substring(0, result.length - 1);
} else if (previousToken?.type === 'attribute') {
result += ')';
}
if (nextToken?.type === 'text' || nextToken?.type === 'path') {
result += ' ';
}
break;
case 'indent':
result += '\n';
result += indent.repeat(indentLevel);
indentLevel++;
break;
case 'outdent':
if (previousToken?.type !== 'outdent') {
if (token.loc.start.line - previousToken.loc.end.line > 1) {
// Insert one extra blank line
result += '\n';
}
result += '\n';
}
indentLevel--;
break;
case 'class':
switch (previousToken?.type) {
case 'newline':
case 'outdent':
case 'indent': {
const prefix = result.slice(0, result.length);
const _indent = printIndent(previousToken, indent, indentLevel);
const val = `.${token.val}`;
result = [prefix, _indent, val, result.slice(result.length)].join('');
possibleClassPosition = prefix.length + _indent.length + val.length;
break;
}
default: {
const prefix = result.slice(0, possibleClassPosition);
const val = `.${token.val}`;
result = [prefix, val, result.slice(possibleClassPosition)].join('');
possibleClassPosition = prefix.length + val.length;
break;
}
}
if (nextToken?.type === 'text') {
result += ' ';
}
break;
case 'eos':
// Remove all newlines at the end
while (result.endsWith('\n')) {
result = result.substring(0, result.length - 1);
}
// Insert one newline
result += '\n';
break;
case 'comment': {
result += printIndent(previousToken, indent, indentLevel);
if (previousToken && !['newline', 'indent', 'outdent'].includes(previousToken.type)) {
result += ' ';
}
result += '//';
if (!token.buffer) {
result += '-';
}
result += formatCommentPreserveSpaces(token.val, commentPreserveSpaces);
if (nextToken.type === 'start-pipeless-text') {
pipelessComment = true;
}
break;
}
case 'newline':
if (previousToken && token.loc.start.line - previousToken.loc.end.line > 1) {
// Insert one extra blank line
result += '\n';
}
result += '\n';
break;
case 'text': {
let val = token.val;
let needsTrailingWhitespace: boolean = false;
if (pipelessText) {
switch (previousToken?.type) {
case 'newline':
result += indent.repeat(indentLevel + 1);
break;
case 'start-pipeless-text':
result += indent;
break;
}
if (pipelessComment) {
val = formatCommentPreserveSpaces(val, commentPreserveSpaces, true);
}
} else {
if (nextToken && val.endsWith(' ')) {
switch (nextToken.type) {
case 'interpolated-code':
case 'start-pug-interpolation':
needsTrailingWhitespace = true;
break;
}
}
val = val.replace(/\s\s+/g, ' ');
switch (previousToken?.type) {
case 'newline':
result += indent.repeat(indentLevel);
if (/^ .+$/.test(val)) {
result += '|\n';
result += indent.repeat(indentLevel);
}
result += '|';
if (/.*\S.*/.test(token.val) || nextToken?.type === 'start-pug-interpolation') {
result += ' ';
}
break;
case 'indent':
result += indent;
result += '|';
if (/.*\S.*/.test(token.val)) {
result += ' ';
}
break;
case 'interpolated-code':
case 'end-pug-interpolation':
if (/^ .+$/.test(val)) {
result += ' ';
}
break;
}
val = val.trim();
val = formatText(val, singleQuote);
val = val.replace(/#(\{|\[)/g, '\\#$1');
}
if (
['tag', 'id', 'interpolation', 'call', '&attributes', 'filter'].includes(
previousToken?.type
)
) {
val = ` ${val}`;
}
result += val;
if (needsTrailingWhitespace) {
result += ' ';
}
break;
}
case 'interpolated-code':
switch (previousToken?.type) {
case 'tag':
case 'class':
case 'id':
case 'end-attributes':
result += ' ';
break;
case 'start-pug-interpolation':
result += '| ';
break;
case 'indent':
case 'newline':
case 'outdent':
result += printIndent(previousToken, indent, indentLevel);
result += '| ';
break;
}
result += token.mustEscape ? '#' : '!';
result += `{${token.val}}`;
break;
case 'code': {
result += printIndent(previousToken, indent, indentLevel);
if (!token.mustEscape && token.buffer) {
result += '!';
}
result += token.buffer ? '=' : '-';
let useSemi = semi;
if (useSemi && (token.mustEscape || token.buffer)) {
useSemi = false;
}
let val = token.val;
try {
const valBackup = val;
val = format(val, {
parser: 'babel',
...codeInterpolationOptions,
semi: useSemi,
endOfLine: 'lf'
});
val = val.slice(0, -1);
if (val.includes('\n')) {
val = valBackup;
}
} catch (error) {
logger.warn(error);
}
result += ` ${val}`;
break;
}
case 'id': {
switch (previousToken?.type) {
case 'newline':
case 'outdent':
case 'indent': {
const prefix = result.slice(0, result.length);
const _indent = printIndent(previousToken, indent, indentLevel);
const val = `#${token.val}`;
result = [prefix, _indent, val, result.slice(result.length)].join('');
possibleClassPosition = prefix.length + _indent.length + val.length;
break;
}
default: {
const prefix = result.slice(0, possibleIdPosition);
const val = `#${token.val}`;
result = [prefix, val, result.slice(possibleIdPosition)].join('');
possibleClassPosition = prefix.length + val.length;
break;
}
}
break;
}
case 'start-pipeless-text':
pipelessText = true;
result += '\n';
result += indent.repeat(indentLevel);
break;
case 'end-pipeless-text':
pipelessText = false;
pipelessComment = false;
break;
case 'doctype':
result += 'doctype';
if (token.val) {
result += ` ${token.val}`;
}
break;
case 'dot':
result += '.';
break;
case 'block':
result += printIndent(previousToken, indent, indentLevel);
result += 'block ';
if (token.mode !== 'replace') {
result += token.mode;
result += ' ';
}
result += token.val;
break;
case 'extends':
result += 'extends ';
break;
case 'path':
if (['include', 'filter'].includes(previousToken?.type)) {
result += ' ';
}
result += token.val;
break;
case 'start-pug-interpolation':
result += '#[';
break;
case 'end-pug-interpolation':
result += ']';
break;
case 'interpolation':
result += printIndent(previousToken, indent, indentLevel);
result += `#{${token.val}}`;
possibleIdPosition = result.length;
possibleClassPosition = result.length;
break;
case 'include':
result += printIndent(previousToken, indent, indentLevel);
result += 'include';
break;
case 'filter':
result += printIndent(previousToken, indent, indentLevel);
result += `:${token.val}`;
break;
case 'call': {
result += printIndent(previousToken, indent, indentLevel);
result += `+${token.val}`;
let args: string | null = token.args;
if (args) {
args = args.trim();
args = args.replace(/\s\s+/g, ' ');
result += `(${args})`;
}
possibleIdPosition = result.length;
possibleClassPosition = result.length;
break;
}
case 'mixin': {
result += printIndent(previousToken, indent, indentLevel);
result += `mixin ${token.val}`;
let args: string | null = token.args;
if (args) {
args = args.trim();
args = args.replace(/\s\s+/g, ' ');
result += `(${args})`;
}
break;
}
case 'if': {
result += printIndent(previousToken, indent, indentLevel);
const match = /^!\((.*)\)$/.exec(token.val);
logger.debug(match);
result += !match ? `if ${token.val}` : `unless ${match[1]}`;
break;
}
case 'mixin-block':
result += printIndent(previousToken, indent, indentLevel);
result += 'block';
break;
case 'else':
result += printIndent(previousToken, indent, indentLevel);
result += 'else';
break;
case '&attributes':
result += `&attributes(${token.val})`;
break;
case 'text-html': {
result += printIndent(previousToken, indent, indentLevel);
const match: RegExpExecArray | null = /^<(.*?)>(.*)<\/(.*?)>$/.exec(token.val);
logger.debug(match);
if (match) {
result += `${match[1]} ${match[2]}`;
break;
}
const entry = Object.entries(DOCTYPE_SHORTCUT_REGISTRY).find(
([key]) => key === token.val.toLowerCase()
);
if (entry) {
result += entry[1];
break;
}
result += token.val;
break;
}
case 'each':
result += printIndent(previousToken, indent, indentLevel);
result += `each ${token.val}`;
if (token.key !== null) {
result += `, ${token.key}`;
}
result += ` in ${token.code}`;
break;
case 'while':
result += printIndent(previousToken, indent, indentLevel);
result += `while ${token.val}`;
break;
case 'case':
result += printIndent(previousToken, indent, indentLevel);
result += `case ${token.val}`;
break;
case 'when':
result += printIndent(previousToken, indent, indentLevel);
result += `when ${token.val}`;
break;
case ':':
result += ': ';
possibleIdPosition = result.length;
possibleClassPosition = result.length;
break;
case 'default':
result += printIndent(previousToken, indent, indentLevel);
result += 'default';
break;
case 'else-if':
result += printIndent(previousToken, indent, indentLevel);
result += `else if ${token.val}`;
break;
case 'blockcode':
result += printIndent(previousToken, indent, indentLevel);
result += '-';
break;
case 'yield':
result += printIndent(previousToken, indent, indentLevel);
result += 'yield';
break;
case 'slash':
result += '/';
break;
default:
throw new Error('Unhandled token: ' + JSON.stringify(token));
}
}
logger.debug(result);
const printer = new PugPrinter(tokens, {
printWidth,
singleQuote,
tabWidth,
useTabs,
attributeSeparator,
commentPreserveSpaces,
semi
});
const result = printer.build();
logger.debug('[printers:pug-ast:print]:', result);
return result;

@@ -766,0 +85,0 @@ },

@@ -35,3 +35,3 @@ export const CATEGORY_PUG: string = 'Pug';

result += input
.substring(firstNonSpace)
.slice(firstNonSpace)
.trim()

@@ -44,3 +44,3 @@ .replace(/\s\s+/g, ' ');

result = result.replace(/\s\s+/g, ' ');
if (!pipeless && input.startsWith(' ')) {
if (!pipeless && input[0] === ' ') {
result = ` ${result}`;

@@ -47,0 +47,0 @@ }

@@ -0,1 +1,2 @@

/* eslint-disable @typescript-eslint/member-ordering */
declare module 'pug-lexer' {

@@ -2,0 +3,0 @@ namespace lex {

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc