{% endunless %}
diff --git a/package.json b/package.json
index 6e00685..bf7e44e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "esthetic",
- "version": "0.5.6-beta.1",
+ "version": "0.6.1-beta.1",
"license": "MIT",
"homepage": "https://æsthetic.dev",
"author": "ΝΙΚΟΛΑΣ ΣΑΒΒΙΔΗΣ ",
diff --git a/src/comments/block.ts b/src/comments/block.ts
index da8d6c1..f815b48 100644
--- a/src/comments/block.ts
+++ b/src/comments/block.ts
@@ -1,113 +1,101 @@
-import { WrapComment } from 'types/index';
+import { Comments } from 'types';
import { parse } from 'parse/parser';
import * as rx from 'lexical/regex';
import { cc as ch } from 'lexical/codes';
+import { Comm } from 'lexical/enum';
import { NWL, NIL, WSP } from 'chars';
-import { sanitizeComment, ws, is, not } from 'utils/helpers';
+import { charEsc, ws, is, not, liquidEsc } from 'utils/helpers';
/**
- * Wrap Comment Block
+ * Comment Block Parser
*
- * Beautification and handling for block style comments.
- * Traversal lexing for all comment identified sequences.
+ * Beautification and handling for block style comments. This is used
+ * across all lexers and will determine the comment type and how it
+ * should be dealt with. Liquid line type comment (e.g: `{% # %}`) will
+ * also pass through here as these comment can span multiple lines.
+ *
+ * The function contains a series of functions and will return a string
+ * token ([0]) and the new index position ([1]). The string token will
+ * be populated in the parse table.
*/
-export function commentBlock (config: WrapComment): [string, number] {
+export function commentBlock (chars: string[], config: Comments): [string, number] {
/* -------------------------------------------- */
/* CONSTANTS */
/* -------------------------------------------- */
/**
- * Deconstructed Rules
+ * Delimiter handling for markup HTML comments
*/
- const { rules } = parse;
+ enum Delimiters { Force, Inline, Preserve }
/**
- * The composed output structure
+ * Deconstructed Config
*/
- const build: string[] = [];
+ const { start, begin, lexer, end } = config;
/**
- * An additional composed structure
+ * Deconstructed Parse
*/
- const store: string[] = [];
+ const { rules, data } = parse;
/**
- * Sanatized opening delimiter sequence
+ * The composed output structure
*/
- const sanitize = config.begin.replace(rx.CharEscape, sanitizeComment);
+ const build: string[] = [];
/**
- * Whether or not we are dealing with a Liquid comment
+ * The type of block comment we are handling
*/
- const isLiquid = is(config.begin[0], ch.LCB) && is(config.begin[1], ch.PER);
+ const type = comment();
/**
- * Whether or not we are dealing with a Liquid Line comment
+ * Sanatized opening delimiter sequence
*/
- const isLiquidLine = isLiquid === false ? false : config.chars
- .slice(config.start + 2, config.chars.indexOf('%}', config.start + 2))
- .join(NIL)
- .trimStart()
- .charCodeAt(0) === ch.HSH;
+ const sanitize = begin.replace(rx.CharEscape, charEsc) + ((type === Comm.LiquidLine) ? '\\s*#\\s*' : '\\s*');
/**
* Regular expression for ignore comment starters
*/
- const regexIgnore = new RegExp(`^(${sanitize}\\s*esthetic-ignore-start)`);
+ const ignoreStart: RegExp = new RegExp(`^(${sanitize}esthetic-ignore-start)`);
/**
- * Regular expression start type comment blocks
+ * Regular expression for ignore comment next
*/
- const regexStart = new RegExp(`(${sanitize}\\s*)`);
- /**
- * Liquid ending expression
- */
- const regexEnder: RegExp = isLiquid
- ? new RegExp(`\\s*${config.ender.replace(rx.LiquidDelimiters, i => is(i, ch.LCB) ? '{%-?\\s*' : '\\s*-?%}')}$`)
- : new RegExp(config.ender.replace(rx.CharEscape, sanitizeComment));
-
- /* -------------------------------------------- */
- /* LEXICAL SCOPES */
- /* -------------------------------------------- */
+ const ignoreNext: RegExp = new RegExp(`^(${sanitize}esthetic-ignore-next)`);
/**
- * Starting index offset of the comment
+ * Regular Expression CRLF
*/
- let a = config.start;
- let b = 0;
- let c = 0;
- let d = 0;
-
- /**
- * Newlines store reference
- */
- let lines: string[] = [];
+ const regexCRLF: RegExp = new RegExp(parse.crlf, 'g');
/**
- * Lines Length store reference
+ * Regular expression start type comment blocks
*/
- let lsize = 0;
+ const regexStart: RegExp = new RegExp(`(${sanitize})`);
/**
- * Iterator `b` line
+ * Liquid ending expression
*/
- let bline = NIL;
+ const regexEnder: RegExp = (type === Comm.LiquidBlock || type === Comm.LiquidLine)
+ ? new RegExp(`\\s*${config.ender.replace(rx.LiquidDelimiters, liquidEsc)}$`)
+ : new RegExp(config.ender.replace(rx.CharEscape, charEsc));
- /**
- * Whether or not empty line is contained
- */
- let emptyLine = false;
+ /* -------------------------------------------- */
+ /* LEXICAL SCOPES */
+ /* -------------------------------------------- */
/**
- * Whether or not bullet point lines are contained
+ * Starting index offset of the comment, i.e: value of `config.start`
*/
- let bulletLine = false;
+ let a = start;
/**
- * Whether or not numbered lines are contained
+ * Before comment index offset `a` used in the `parseComment` which will indexes before comment
*/
- let numberLine = false;
+ let b = 0;
+ let c = 0;
+ let d = 0;
/**
* The generated output token
@@ -124,409 +112,779 @@ export function commentBlock (config: WrapComment): [string, number] {
*/
let term = config.ender.charAt(tlen);
- /**
- * Terminator wrap length
- */
- let twrap = 0;
-
/* -------------------------------------------- */
/* FUNCTIONS */
/* -------------------------------------------- */
/**
- * Parse Empty Newlines
+ * Comment Type
*
- * Detects new lines and populates the `store[]` store build.
+ * Returns a enum reference which informs upon the type of comment
*/
- function parseEmptyLines () {
+ function comment () {
+
+ if (is(begin[0], ch.LCB) && is(begin[1], ch.PER)) {
+
+ return chars
+ .slice(start + begin.length, chars.indexOf('%}', start + 2))
+ .join(NIL)
+ .trimStart()
+ .charCodeAt(0) === ch.HSH ? Comm.LiquidLine : Comm.LiquidBlock;
+ }
+
+ return begin === '/*' ? Comm.Block : Comm.Markup;
+
+ }
+
+ function delimiters () {
+
+ if (type !== Comm.Markup) return false;
- if (rx.EmptyLine.test(lines[b + 1]) || lines[b + 1] === NIL) {
+ if (rules.markup.commentDelimiters === 'consistent') {
- do b = b + 1;
- while (b < lsize && (rx.EmptyLine.test(lines[b + 1]) || lines[b + 1] === NIL));
+ return is(output.slice(4).replace(rx.WhitespaceLead, NIL), ch.NWL)
+ ? [ Delimiters.Force, Delimiters.Force ]
+ : [ Delimiters.Inline, Delimiters.Inline ];
+
+ } else if (rules.markup.commentDelimiters === 'force') {
+
+ return [ Delimiters.Force, Delimiters.Force ];
+
+ } else if (rules.markup.commentDelimiters === 'inline' || rules.markup.commentDelimiters === 'inline-align') {
+
+ return [ Delimiters.Inline, Delimiters.Inline ];
+
+ } else if (rules.markup.commentDelimiters === 'preserve') {
+
+ const delim: Delimiters[] = [];
+
+ if (is(output.slice(4).replace(rx.WhitespaceLead, NIL), ch.NWL)) {
+ delim.push(Delimiters.Force);
+ } else {
+ delim.push(Delimiters.Inline);
+ }
+
+ if (output.slice(output.lastIndexOf(NWL) + 1).trimStart() === config.ender) {
+ delim.push(Delimiters.Force);
+ } else {
+ delim.push(Delimiters.Inline);
+ }
+
+ return delim;
}
- if (b < lsize - 1) store.push(NIL);
+ }
+
+ function parseInlineComment (): [string, number] {
+
+ if (type === Comm.Markup && rules.markup.preserveComment === false) {
- };
+ if (rules.markup.commentDelimiters === 'consistent') {
+
+ if (is(output.slice(4).replace(rx.WhitespaceLead, NIL), ch.NWL)) {
+ if (rules.markup.commentIndent) {
+ output = output.replace(/^$/, '\n-->');
+ } else {
+ output = output.replace(/^$/, '\n-->');
+ }
+ } else {
+ output = output.replace(/^$/, ' -->');
+ }
+
+ } else if (rules.markup.commentDelimiters === 'force') {
+
+ if (rules.markup.commentIndent) {
+ output = output.replace(/^$/, '\n-->');
+ } else {
+ output = output.replace(/^$/, '\n-->');
+ }
+
+ } else if (rules.markup.commentDelimiters === 'inline' || rules.markup.commentDelimiters === 'inline-align') {
+
+ output = output.replace(/^$/, ' -->');
+
+ } else {
+
+ if (is(output.slice(4).replace(rx.WhitespaceLead, NIL), ch.NWL)) {
+ if (rules.markup.commentIndent) {
+ output = output.replace(/^$/, '\n-->');
+ } else {
+ output = output.replace(/\s*-->$/, '\n-->');
+ }
+ } else {
+ output = output.replace(/\s*-->$/, ' -->');
+ }
+
+ }
+
+ }
+
+ return [ output, a ];
+
+ }
/**
- * Ignore Comment
+ * Ignore Comment Next
*
- * Detects and traverses an ignore control type comment.
+ * Handles the `esthetic-ignore-next` ignore comment.
+ * Ensures the leading whitespace is included in the
+ * token comment.
*/
- function parseIgnoreComment (): [string, number] {
+ function parseIgnoreNext (): [string, number] {
- let ender = NWL;
-
- a = a + 1;
+ /* -------------------------------------------- */
+ /* LEXICAL SCOPES */
+ /* -------------------------------------------- */
- do {
+ /**
+ * Spacing before used for ignores
+ */
+ let before = NIL;
- build.push(config.chars[a]);
+ /**
+ * Comment output as a string
+ */
+ let output = build.join(NIL).replace(rx.WhitespaceEnd, NIL);
- // Supports comment start/end comment ignores using Liquid
- // tags. We don't have any knowledge of the comment formation
- // upon parse, this will re-assign the terminator
- //
- if (build.slice(build.length - 19).join(NIL) === 'esthetic-ignore-end') {
+ /* -------------------------------------------- */
+ /* BEGIN */
+ /* -------------------------------------------- */
- if (isLiquid) {
+ // The following logic will obtain before line reference
+ // because inline comment ignores will be preserved (excluded)
+ // from formatting. Only when the previous entry of the parse
+ // table exists and has more than 1 lines will this logic incur.
+ //
+ if ((parse.count > -1 && data.lines[parse.count] > 0)) {
- const d = config.chars.indexOf('{', a);
+ b = chars.lastIndexOf(NWL, parse.iterator) + 1;
- if (is(config.chars[d + 1], ch.PER)) {
+ if (b > 0) {
- const ender = config.chars.slice(d, config.chars.indexOf('}', d + 1) + 1).join(NIL);
- if (regexEnder.test(ender)) config.ender = ender;
+ before = chars.slice(b, parse.iterator).join(NIL);
- }
+ if (before.trim() === NIL) {
+ output = before + output;
+ } else {
+ before = before.slice(0, before.search(rx.NonSpace));
+ output = before + output;
}
- a = a + 1;
- break;
}
- a = a + 1;
+ }
- } while (a < config.end);
+ return [ output, a ];
- b = a;
+ }
+
+ /**
+ * Ignore Comment Block
+ *
+ * Detects and traverses an ignore control type comment.
+ * This function is handles `esthetic-ignore-start` and
+ * `esthetic-ignore-end` comment blocks.
+ */
+ function parseIgnoreBlock (): [string, number] {
+
+ /* -------------------------------------------- */
+ /* LEXICAL SCOPES */
+ /* -------------------------------------------- */
+
+ /**
+ * Comment ender delimiter reference
+ */
+ let ender = NWL;
- tlen = config.begin.length - 1;
- term = config.begin.charAt(tlen);
+ /* -------------------------------------------- */
+ /* TRAVERSE */
+ /* -------------------------------------------- */
+
+ a = a + 1;
do {
- // Script OR Style Comment Blocks
- if (config.begin === '/*' && is(config.chars[b - 1], ch.FWS) && (
- is(config.chars[b], ch.ARS) ||
- is(config.chars[b], ch.FWS))) break;
+ build.push(chars[a]);
- // Markup Comment Blocks
+ // Liquid comment block
+ //
+ // Supports comment start/end comment ignores using Liquid
+ // tags. We don't have any knowledge of the comment formation
+ // upon parse, this will re-assign the terminator
+ //
+ // We check the last 5 characters before applying a join and
+ // checking if the ignore comment has reached the end.
+ //
if (
- config.begin !== '/*' &&
- config.chars[b] === term &&
- config.chars.slice(b - tlen, b + 1).join(NIL) === config.begin) break;
+ chars[a - 3] === '-' &&
+ chars[a - 2] === 'e' &&
+ chars[a - 1] === 'n' &&
+ chars[a] === 'd') {
+
+ if (build.slice(build.length - 19).join(NIL) === 'esthetic-ignore-end') {
+ if (type === Comm.LiquidBlock) {
+ const delim = chars.indexOf('{', a) + 1;
+ if (is(chars[delim], ch.PER)) {
+ const endcomm = chars.slice(d, chars.indexOf('}', delim) + 1).join(NIL);
+ if (regexEnder.test(endcomm)) config.ender = endcomm;
+ }
+ }
- b = b - 1;
+ a = a + 1;
+ break;
+ }
+ }
+
+ a = a + 1;
+ } while (a < end);
+
+ b = a;
+ tlen = begin.length - 1;
+ term = begin.charAt(tlen);
- } while (b > config.start);
+ do {
+ if (type === Comm.Block && is(chars[b - 1], ch.FWS) && is(chars[b], ch.ARS)) break;
+ if (chars[b] === term && chars.slice(b - tlen, b + 1).join(NIL) === begin) break;
+ b = b - 1;
+ } while (b > start);
- if (config.begin === '/*' && is(config.chars[b], ch.ARS)) {
- ender = '\u002a/';
- } else if (config.begin !== '/*') {
+ if (type === Comm.Block && is(chars[b], ch.ARS)) {
+ ender = '*/';
+ } else if (begin !== '/*') {
ender = config.ender;
}
tlen = ender.length - 1;
term = ender.charAt(tlen);
- if (ender !== NWL || config.chars[a] !== NWL) {
-
+ if (not(ender, ch.NWL) || not(chars[a], ch.NWL)) {
do {
-
- build.push(config.chars[a]);
-
- if (ender === NWL && config.chars[a + 1] === NWL) break;
- if (config.chars[a] === term && config.chars.slice(a - tlen, a + 1).join(NIL) === ender) break;
-
+ build.push(chars[a]);
+ if (is(ender, ch.NWL) && is(chars[a + 1], ch.NWL)) break;
+ if (chars[a] === term && chars.slice(a - tlen, a + 1).join(NIL) === ender) break;
a = a + 1;
-
- } while (a < config.end);
-
+ } while (a < end);
}
- if (config.chars[a] === NWL) a = a - 1;
+ if (is(chars[a], ch.NWL)) a = a - 1;
output = build.join(NIL).replace(rx.WhitespaceEnd, NIL);
+ if (ws(chars[parse.iterator - 1])) {
+ const last = chars.lastIndexOf(NWL, parse.iterator);
+ if (last > -1) output = chars.slice(last + 1, parse.iterator).join(NIL) + output;
+ }
+
return [ output, a ];
}
- do {
+ /**
+ * Preserve Comment
+ *
+ * A series of conditionals to determine whether or not
+ * the comment should be preserved or returned early without
+ * out an additional handling.
+ */
+ function parsePreserve (): boolean {
- build.push(config.chars[a]);
+ // Preserve when comment is last token
+ //
+ if (a === end) return true;
- if (is(config.chars[a], ch.NWL)) parse.lineOffset = parse.lines(a, parse.lineOffset);
+ // Preserve comments based on rules
+ //
if (
- config.chars[a] === term &&
- config.chars.slice(a - tlen, a + 1).join(NIL) === config.ender) break;
+ (type === Comm.LiquidBlock && rules.liquid.preserveComment) ||
+ (type === Comm.LiquidLine && rules.liquid.preserveComment) ||
+ (type === Comm.Markup && rules.markup.preserveComment) ||
+ (type === Comm.Block && lexer === 'style' && rules.style.preserveComment) ||
+ (type === Comm.Block && lexer === 'script' && rules.script.preserveComment)) return true;
+
+ // Preserve when wrap is not exceeded and no newlines exist
+ //
+ if (
+ type !== Comm.LiquidBlock &&
+ type !== Comm.LiquidLine &&
+ output.length <= rules.wrap &&
+ output.indexOf(NWL) < 0) return true;
- a = a + 1;
+ // Preserve Liquid block comments when inline
+ if (
+ rules.wrap < 1 &&
+ type === Comm.LiquidBlock &&
+ rx.LiquidCommentNewline.test(output) === false) return true;
- } while (a < config.end);
-
- output = build.join(NIL);
-
- if (regexIgnore.test(output) === true) return parseIgnoreComment();
-
- if (((
- isLiquid === true &&
- rules.liquid.preserveComment
- ) || (
- isLiquid === false &&
- rules.markup.preserveComment
- ) || (
- parse.lexer === 'style' &&
- rules.style.preserveComment
- ) || (
- parse.lexer === 'script' &&
- rules.style.preserveComment
- )) || (
- (
- (
- rules.wrap < 1 && (
- /comment\s*%}\n/.test(output) === false
- )
- ) ||
- a === config.end || (
- output.length <= rules.wrap &&
- output.indexOf(NWL) < 0
- )
- )
- ) || (
- config.begin === '/*' &&
- output.indexOf(NWL) > 0 &&
- output.replace(NWL, NIL).indexOf(NWL) > 0 &&
- /\n(?!\s*\*)/.test(output) === false
- )) {
-
- if (isLiquidLine) {
-
- lines = output.replace(/\r\n/g, NWL).split(NWL);
-
- for (let i = 1, l = lines.length - 1; i < l; i++) {
- if (not(lines[i].trimStart(), ch.HSH) && lines[i].trimStart() !== '') {
- lines[i] = '# ' + lines[i].trimStart();
- }
- }
+ // Preserve Liquid line comments when no newlines exist
+ //
+ if (
+ rules.wrap < 1 &&
+ type === Comm.LiquidLine &&
+ rx.Newline.test(output) === false) return true;
- return [ lines.join(parse.crlf), a ];
- }
+ // Preserve when wrap is not exceeded and now newlines exist
+ if (
+ rules.wrap > 0 &&
+ output.length <= rules.wrap &&
+ output.slice(5, -4).indexOf(NWL) < 0) return true;
- return [ output, a ];
+ // Preserve when innner comment contents does not contain newlines
+ if (
+ rules.wrap < 1 &&
+ type !== Comm.LiquidBlock &&
+ type !== Comm.LiquidLine &&
+ output.slice(5, -4).indexOf(NWL) < 0) return true;
- }
+ // Preserve Style and Script Comment Blocks
+ if (
+ type === Comm.Block &&
+ output.indexOf(NWL) > 0 &&
+ output.replace(NWL, NIL).indexOf(NWL) > 0 &&
+ rx.CommBlockNewline.test(output) === false) return true;
- b = config.start;
+ // Additional Processing is required
+ //
+ return false;
- if (b > 0 && not(config.chars[b - 1], ch.NWL) && ws(config.chars[b - 1])) {
- do b = b - 1;
- while (b > 0 && not(config.chars[b - 1], ch.NWL) && ws(config.chars[b - 1]));
}
/**
- * Whitespace reference
+ * Parse Comment
+ *
+ * Determines and decontructs comment newline occurances.
+ * Assigns various lexical scopes in the process. Next function
+ * we will handle special character occurances.
*/
- const space = config.chars.slice(b, config.start).join(NIL);
- const spaceLine = new RegExp(NWL + space, 'g');
+ function parseComment (): [string, number] {
+
+ /* -------------------------------------------- */
+ /* LEXICAL CONTEXT */
+ /* -------------------------------------------- */
+
+ /**
+ * Comment contents split on newlines
+ */
+ let lines: string[] = [];
+
+ /* -------------------------------------------- */
+ /* LEXICAL SCOPES */
+ /* -------------------------------------------- */
+
+ /**
+ * The length of `lines[]`
+ */
+ let lsize: number = 0;
+
+ /* -------------------------------------------- */
+ /* BEGIN */
+ /* -------------------------------------------- */
+
+ b = start;
+
+ if (b > 0 && not(chars[b - 1], ch.NWL) && ws(chars[b - 1])) {
+ do b = b - 1;
+ while (b > 0 && not(chars[b - 1], ch.NWL) && ws(chars[b - 1]));
+ }
+
+ /**
+ * Newline + Whitespace match
+ */
+ const before = new RegExp(`\n${chars.slice(b, start).join(NIL)}`, 'g');
+
+ lines = output
+ .replace(regexCRLF, NWL)
+ .replace(before, NWL)
+ .split(NWL);
+
+ lsize = lines.length;
+ lines[0] = lines[0].replace(regexStart, NIL);
+ lines[lsize - 1] = lines[lsize - 1].replace(regexEnder, NIL);
+
+ // When less than 2 the comment is comprised in a single
+ // line and thus we need to determine handling based on
+ // wrap length, so we will split on every whitespace
+ //
+ if (lsize < 2) lines = lines[0].split(WSP);
+ if (lines[0] === NIL) {
+ lines[0] = begin;
+ } else {
+ lines.splice(0, 0, begin);
+ }
- lines = output.replace(/\r\n/g, NWL).replace(spaceLine, NWL).split(NWL);
- lsize = lines.length;
- lines[0] = lines[0].replace(regexStart, NIL);
- lines[lsize - 1] = lines[lsize - 1].replace(regexEnder, NIL);
+ lsize = lines.length;
- if (lsize < 2) lines = lines[0].split(WSP);
+ return parseSpecials(lines, lsize);
- if (lines[0] === NIL) {
- lines[0] = config.begin;
- } else {
- lines.splice(0, 0, config.begin);
}
- lsize = lines.length;
+ /**
+ * Parse Specials
+ *
+ * Detects special character structures within the comment and
+ * formats them accordingly. This includes numbers, dash lists
+ * and empty lines. Next function concludes the parse operations.
+ */
+ function parseSpecials (lines: string[], lsize: number): [string, number] {
- let nl = NIL;
- let bw = lsize - 1;
+ /* -------------------------------------------- */
+ /* CONSTANTS */
+ /* -------------------------------------------- */
- while (bw--) if (lines[bw] === NIL) nl += NWL; else break;
- if (nl !== NIL) nl = nl.slice(0, rules.preserveLine);
+ /**
+ * An additional composed structure
+ */
+ const lexed: string[] = [];
- b = 0;
+ /* -------------------------------------------- */
+ /* LEXICAL SCOPES */
+ /* -------------------------------------------- */
- do {
+ /**
+ * Terminator wrap length
+ */
+ let twrap: number = 0;
- bline = (b < lsize - 1) ? lines[b + 1].replace(rx.WhitespaceLead, NIL) : NIL;
+ /**
+ * Replaced string stripped of whitespace and newlines
+ */
+ let strip: string;
- if (rx.EmptyLine.test(lines[b]) === true || lines[b] === NIL) {
+ /**
+ * Before Line reference
+ */
+ let before: string;
- parseEmptyLines();
+ /**
+ * Whether or not empty line is contained
+ */
+ let emptyLine: boolean = false;
- } else {
+ /**
+ * Whether or not bullet point lines are contained
+ */
+ let bulletLine: boolean = false;
- const strip = lines[b].replace(rx.WhitespaceLead, NIL);
+ /**
+ * Whether or not numbered lines are contained
+ */
+ let numberLine: boolean = false;
- if (rules.wrap > 0 && strip.length > rules.wrap && strip.indexOf(WSP) > rules.wrap) {
+ /* -------------------------------------------- */
+ /* TRAVERSE */
+ /* -------------------------------------------- */
- lines[b] = strip;
+ b = 0;
- c = lines[b].indexOf(WSP);
+ do {
- store.push(lines[b].slice(0, c));
- lines[b] = lines[b].slice(c + 1);
+ before = NIL;
- b = b - 1;
+ if (b < lsize - 1) before = lines[b + 1].replace(rx.SpaceLead, NIL);
- } else {
+ if (rx.EmptyLine.test(lines[b]) === true || lines[b] === NIL) {
- if (b < 1) {
- twrap = rules.wrap - (config.begin.length + 1);
- } else {
- twrap = rules.wrap;
+ if (lines[b + 1] === NIL || rx.EmptyLine.test(lines[b + 1])) {
+ do b = b + 1;
+ while (b < lsize && (lines[b + 1] === NIL || rx.EmptyLine.test(lines[b + 1])));
}
- if (config.begin === '/*' && lines[b].indexOf('/*') !== 0) {
- lines[b] = ' ';
- } else {
- lines[b] = lines[b]
- .replace(rx.WhitespaceLead, NIL)
- .replace(rx.WhitespaceEnd, NIL)
- .replace(rx.SpacesGlob, WSP);
- }
+ if (b < lsize - 1) lexed.push(NIL);
+
+ } else {
+
+ strip = lines[b].replace(rx.SpaceLead, NIL);
- d = lines[b].replace(rx.WhitespaceLead, NIL).indexOf(WSP);
- c = lines[b].length;
+ if (
+ rules.wrap > 0 &&
+ strip.length > rules.wrap &&
+ strip.indexOf(WSP) > rules.wrap) {
- if (c > twrap && d > 0 && d < twrap) {
+ lines[b] = strip;
- c = twrap;
+ c = lines[b].indexOf(WSP);
- do {
- c = c - 1;
- if (ws(lines[b].charAt(c)) && c <= rules.wrap) break;
- } while (c > 0);
+ lexed.push(lines[b].slice(0, c));
+ lines[b] = lines[b].slice(c + 1);
- if (rx.CommNumberLine.test(lines[b]) && rx.CommNumberLine.test(lines[b + 1]) === false) {
+ b = b - 1;
- lines.splice(b + 1, 0, '1. ');
+ } else {
+ if (b < 1) {
+ twrap = rules.wrap - (begin.length + 1);
+ } else {
+ twrap = rules.wrap;
}
- if (rx.EmptyLine.test(lines[b + 1]) === true || lines[b + 1] === NIL) {
+ if (type === Comm.Block && lines[b].indexOf('/*') !== 0) {
- store.push(lines[b].slice(0, c));
- lines[b] = lines[b].slice(c + 1);
- emptyLine = true;
- b = b - 1;
+ lines[b] = ' ' + lines[b]
+ .replace(rx.SpaceLead, NIL)
+ .replace(rx.SpaceEnd, NIL)
+ .replace(rx.SpacesGlob, WSP);
- } else if (rx.CommBulletLine.test(lines[b + 1])) {
+ } else {
- store.push(lines[b].slice(0, c));
- lines[b] = lines[b].slice(c + 1);
- bulletLine = true;
- b = b - 1;
+ lines[b] = lines[b]
+ .replace(rx.SpaceLead, NIL)
+ .replace(rx.SpaceEnd, NIL)
+ .replace(rx.SpacesGlob, WSP);
+ }
- } else if (rx.CommNumberLine.test(lines[b + 1])) {
+ d = lines[b].replace(rx.WhitespaceLead, NIL).indexOf(WSP);
+ c = lines[b].length;
- store.push(lines[b].slice(0, c));
- lines[b] = lines[b].slice(c + 1);
- numberLine = true;
- b = b - 1;
+ if (c > twrap && d > 0 && d < twrap) {
- } else if (lines[b].replace(rx.WhitespaceLead, NIL).indexOf(WSP) < rules.wrap) {
+ c = twrap;
+
+ do {
+ c = c - 1;
+ if (ws(lines[b].charAt(c)) && c <= rules.wrap) break;
+ } while (c > 0);
+
+ if (rx.CommNumberLine.test(lines[b]) === true && rx.CommNumberLine.test(lines[b + 1]) === false) {
+
+ lines.splice(b + 1, 0, '1. ');
- if (lines[b].length > rules.wrap) {
- lines[b + 1] = lines[b].slice(c + 1) + parse.crlf + lines[b + 1];
- } else {
- lines[b + 1] = lines[b].slice(c + 1) + WSP + lines[b + 1];
}
- }
+ if (rx.EmptyLine.test(lines[b + 1]) === true || lines[b + 1] === NIL) {
+
+ lexed.push(lines[b].slice(0, c));
+ lines[b] = lines[b].slice(c + 1);
+ emptyLine = true;
+ b = b - 1;
+
+ } else if (rx.CommBulletLine.test(lines[b + 1])) {
+
+ lexed.push(lines[b].slice(0, c));
+ lines[b] = lines[b].slice(c + 1);
+ bulletLine = true;
+ b = b - 1;
+
+ } else if (rx.CommNumberLine.test(lines[b + 1])) {
+
+ lexed.push(lines[b].slice(0, c));
+ lines[b] = lines[b].slice(c + 1);
+ numberLine = true;
+ b = b - 1;
+
+ } else if (lines[b].replace(rx.SpaceLead, NIL).indexOf(WSP) < rules.wrap) {
+
+ if (lines[b].length > rules.wrap) {
+ lines[b + 1] = `${lines[b].slice(c + 1)}${parse.crlf}${lines[b + 1]}`;
+ } else {
+ lines[b + 1] = `${lines[b].slice(c + 1)} ${lines[b + 1]}`;
+ }
+
+ }
+
+ if (
+ emptyLine === false &&
+ bulletLine === false &&
+ numberLine === false) lines[b] = lines[b].slice(0, c);
+
+ } else if (lines[b + 1] !== undefined && (
+ (
+ lines[b].length + before.indexOf(WSP) > rules.wrap &&
+ before.indexOf(WSP) > 0
+ ) || (
+ lines[b].length + before.length > rules.wrap &&
+ before.indexOf(WSP) < 0
+ )
+ )) {
+
+ lexed.push(lines[b]);
+
+ // PATCH 10/06/2023
+ //
+ // When wrap was set to `0` Liquid comments were not formatting correctly
+ // which essentially led comment indentation being ignored. This ensures
+ // that even when wrap is 0 that the comment content will still be passed.
+ //
+ if (rules.wrap > 0) b = b + 1;
- if (emptyLine === false && bulletLine === false && numberLine === false) {
- lines[b] = lines[b].slice(0, c);
+ emptyLine = true;
+
+ } else if (
+ b > 0 &&
+ lines[b + 1] !== undefined &&
+ lines[b + 1] !== NIL &&
+ lines[b + 1].indexOf(WSP) < 0 &&
+ rx.EmptyLine.test(lines[b + 1]) === false &&
+ rx.CommLineChars.test(lines[b + 1]) === false
+ ) {
+
+ // LIQUID COMMENTS ARE AUGMENTED HERE
+
+ lines[b + 1] = `${lines[b]} ${lines[b + 1]}`;
+ emptyLine = true;
+
+ } else {
+
+ lexed.push(lines[b]);
+ emptyLine = true;
}
- } else if (lines[b + 1] !== undefined && (
- (
- lines[b].length + bline.indexOf(WSP) > rules.wrap &&
- bline.indexOf(WSP) > 0
- ) || (
- lines[b].length + bline.length > rules.wrap &&
- bline.indexOf(WSP) < 0
- )
- )) {
-
- store.push(lines[b]);
-
- // PATCH 10/06/2023
- //
- // When wrap was set to `0` Liquid comments were not formatting correctly
- // which essentially led comment indentation being ignored. This ensures
- // that even when wrap is 0 that the comment content will still be passed.
- //
- if (rules.wrap !== 0) b = b + 1;
-
- emptyLine = true;
-
- } else if (
- b > 0 &&
- lines[b + 1] !== undefined &&
- lines[b + 1] !== NIL &&
- lines[b + 1].indexOf(WSP) < 0 &&
- rx.EmptyLine.test(lines[b + 1]) === false &&
- rx.CommLineChars.test(lines[b + 1]) === false
- ) {
-
- // LIQUID COMMENTS ARE AUGMENTED HERE
-
- lines[b + 1] = `${lines[b]} ${lines[b + 1]}`;
- emptyLine = true;
+ bulletLine = false;
+ numberLine = false;
+ }
+ }
- } else {
+ b = b + 1;
+
+ } while (b < lsize);
+
+ /* -------------------------------------------- */
+ /* PARSE COMPLETE */
+ /* -------------------------------------------- */
- store.push(lines[b]);
+ const delims = delimiters();
- emptyLine = true;
+ if (lexed && lexed.length > 0) {
+ if (delims) {
+
+ if (delims[0] === Delimiters.Inline) {
+ if (rules.markup.commentIndent) {
+ if (rules.markup.commentDelimiters === 'inline-align') {
+ output = `${lexed[0]} ${lexed.slice(1).join(parse.crlf + ' ')}`;
+ } else {
+ output = `${lexed[0]} ${lexed.slice(1).join(parse.crlf + ' ')}`;
+ }
+ } else {
+ output = `${lexed[0]} ${lexed.slice(1).join(parse.crlf)}`;
+ }
+ } else {
+ if (rules.markup.commentIndent) {
+ output = `${lexed[0] + NWL} ${lexed.slice(1).join(parse.crlf + ' ')}`;
+ } else {
+ output = `${lexed[0] + NWL} ${lexed.slice(1).join(parse.crlf)}`;
+ }
}
- bulletLine = false;
- numberLine = false;
- }
- }
+ if (delims[1] === Delimiters.Inline) {
+ output += ` ${config.ender}`;
+ } else {
+ output += NWL + config.ender;
+ }
- b = b + 1;
+ } else {
- } while (b < lsize);
+ if (lexed[lexed.length - 1].length > rules.wrap - (config.ender.length + 1)) {
+ lexed.push(config.ender);
+ } else if (type === Comm.LiquidBlock) {
+ lexed.push(config.ender);
+ } else {
+ lexed[lexed.length - 1] = `${lexed[lexed.length - 1]} ${config.ender}`;
+ }
- if (store.length > 0) {
+ if (type === Comm.LiquidLine) {
+ for (let i = 1, s = lexed.length - 1; i < s; i++) {
+ if (not(lexed[i], ch.HSH) && lexed[i] !== NIL) lexed[i] = `# ${lexed[i]}`;
+ }
+ }
- if (store[store.length - 1].length > rules.wrap - (config.ender.length + 1)) {
+ output = lexed.join(parse.crlf);
- store.push(config.ender);
+ }
} else {
- store.push(nl + config.ender);
+ if (delims) {
- // store[store.length - 1] = `${store[store.length - 1]} ${config.ender}`;
+ if (delims[0] === Delimiters.Inline) {
- }
+ if (rules.markup.commentIndent) {
+ if (rules.markup.commentDelimiters === 'inline-align') {
+ output = `${lines[0]} ${lines.slice(1).join(parse.crlf + ' ')}`;
+ } else {
+ output = `${lines[0]} ${lines.slice(1).join(parse.crlf + ' ')}`;
+ }
+ } else {
+ output = `${lines[0]} ${lines.slice(1).join(parse.crlf)}`;
+ }
- if (isLiquidLine) {
- for (let i = 1, l = store.length - 1; i < l; i++) {
- if (not(store[i], ch.HSH) && store[i] !== '') {
- store[i] = '# ' + store[i];
+ } else {
+
+ if (rules.markup.commentIndent) {
+ output = `${lines[0] + NWL} ${lines.slice(1).join(parse.crlf + ' ')}`;
+ } else {
+ output = lines.join(parse.crlf);
+ }
+ }
+
+ if (delims[1] === Delimiters.Inline) {
+ output += ` ${config.ender}`;
+ } else {
+ output += NWL + config.ender;
}
+
+ } else {
+
+ lsize = lines.length - 1;
+ lines[lsize] = lines[lsize] + config.ender;
+ output = lines.join(parse.crlf);
+
}
- }
- output = store.join(parse.crlf);
+ }
- } else {
+ return [ output, a ];
- lines[lines.length - 1] = lines[lines.length - 1] + config.ender;
- output = lines.join(parse.crlf);
}
/* -------------------------------------------- */
- /* RETURN COMMENT */
+ /* LEXING */
+ /* -------------------------------------------- */
+
+ do {
+
+ build.push(chars[a]);
+
+ // Newline Increments
+ //
+ if (is(chars[a], ch.NWL)) parse.lineOffset = parse.lines(a, parse.lineOffset);
+
+ // Comment Token
+ //
+ if (chars[a] === term && chars.slice(a - tlen, a + 1).join(NIL) === config.ender) {
+ output = build.join(NIL);
+ break;
+ }
+
+ a = a + 1;
+ } while (a < end);
+
+ /* -------------------------------------------- */
+ /* PARSE IGNORE */
+ /* -------------------------------------------- */
+
+ if (ignoreStart.test(output)) return parseIgnoreBlock();
+ if (ignoreNext.test(output)) return parseIgnoreNext();
+
+ /* -------------------------------------------- */
+ /* PARSE PRESERVE */
+ /* -------------------------------------------- */
+
+ if (parsePreserve()) return parseInlineComment();
+
+ /* -------------------------------------------- */
+ /* PARSE COMMENT */
/* -------------------------------------------- */
- return [ output, a ];
+ return parseComment();
}
diff --git a/src/esthetic.ts b/src/esthetic.ts
index cd7be31..96d16de 100644
--- a/src/esthetic.ts
+++ b/src/esthetic.ts
@@ -18,12 +18,8 @@ export const esthetic = new class Esthetic {
constructor () {
- if (config.env === 'node') {
- config.cwd = process.cwd();
- }
-
+ if (config.env === 'node') config.cwd = process.cwd();
if (config.env === 'browser') {
-
// @ts-expect-error
if (!('esthetic' in window)) {
// @ts-expect-error
@@ -125,7 +121,7 @@ export const esthetic = new class Esthetic {
for (const cb of this.events.error) cb(parse.error);
return source;
} else {
- if (config.throwErrors) throw parse.error;
+ if (config.throwErrors) throw new Error(parse.error);
return source;
}
}
@@ -142,7 +138,6 @@ export const esthetic = new class Esthetic {
});
if (fn === false) return source;
-
}
}
@@ -186,9 +181,7 @@ export const esthetic = new class Esthetic {
}
}
- const timing = action === null
- ? null
- : this.stats = action(parse.count);
+ const timing = action === null ? null : this.stats = action(parse.count);
if (this.events.parse.length > 0) {
for (const cb of this.events.parse) {
diff --git a/src/format/markup.ts b/src/format/markup.ts
index 14185b2..a1d62e2 100644
--- a/src/format/markup.ts
+++ b/src/format/markup.ts
@@ -1,9 +1,9 @@
import type { Types } from 'types/index';
-import * as rx from 'lexical/regex';
import { cc } from 'lexical/codes';
import { WSP, NIL, NWL } from 'chars';
-import { is, isBoolean, isLast, isLastAt, isNumber, isUndefined, not, repeatChar, ws } from 'utils/helpers';
+import { is, isBoolean, isLast, isLastAt, isNumber, isUndefined, not, ws } from 'utils/helpers';
import { parse } from 'parse/parser';
+import * as rx from 'lexical/regex';
/* -------------------------------------------- */
/* MARKUP BEAUTIFICATION */
@@ -24,12 +24,11 @@ import { parse } from 'parse/parser';
export function markup () {
- const { rules } = parse;
-
/* -------------------------------------------- */
/* DESTRUCTED RULES */
/* -------------------------------------------- */
+ const { rules } = parse;
const { lineBreakValue } = rules.markup;
/* -------------------------------------------- */
@@ -41,6 +40,11 @@ export function markup () {
*/
let a = parse.start;
+ /**
+ * Holds the last level
+ */
+ let p: number;
+
/**
* Comment starting positions
*/
@@ -92,6 +96,18 @@ export function markup () {
*/
const jsx = rules.language === 'jsx' || rules.language === 'tsx';
+ /**
+ * Dendentation Tags
+ */
+ const dedent: Set = new Set(rules.liquid.dedentTagList);
+
+ /**
+ * Padded Tags - NOT YET SUPPORTED
+ *
+ * const padded: Set = new Set(rules.liquid.paddedTagList);
+ *
+ */
+
/**
* Delimiter forcing references
*/
@@ -135,6 +151,20 @@ export function markup () {
}
+ /**
+ * Is Stack
+ *
+ * Check whether the token type at specific index
+ * equals the provided name. Returns a truthy.
+ *
+ * > Use `isNotType` for false comparisons.
+ */
+ function isStack (index: number, name: string) {
+
+ return data.stack[index] === name;
+
+ }
+
/**
* Is Token
*
@@ -169,7 +199,7 @@ export function markup () {
* Applies a new line character plus the correct
* amount of identation for the given line of code
*/
- function nl (tabs: number, newlines = true) {
+ function nl (tabs: number, newlines = true, spaces = true) {
const linesout = [];
const pres = rules.preserveLine + 1;
@@ -186,7 +216,7 @@ export function markup () {
} while (index < total);
}
- if (tabs > 0) {
+ if (tabs > 0 && spaces) {
index = 0;
@@ -218,23 +248,40 @@ export function markup () {
*/
const line = data.lines[a + 1];
- if (isType(a, 'comment') && (
+ const isHTML = not(data.token[a][1], cc.PER) && (
+ rules.markup.commentIndent === true &&
(
- is(data.token[a][1], cc.PER) &&
- rules.liquid.preserveComment === false
- ) || (
- not(data.token[a][1], cc.PER) &&
- rules.markup.preserveComment === false
+ rules.markup.commentDelimiters === 'inline' ||
+ (
+ rules.markup.commentDelimiters === 'consistent' &&
+ /
- //
- //
- //
- // Even though the div tag in the example is invalid, esthetic will
- // exclude the region. Using the parse.iterator reference assigned
- // within parseComments we determine the starting point of the beginning
- // token, basically consuming this portion:
- //
- // -->
- //
- //
" of
- // the ignore comment and the starting div "<" delimiter is consumed and
- // now the begins reference points to "<" which from here we can use the
- // tags[] array length to obtain starting token.
- //
- const begins = parse.iterator + b.slice(parse.iterator, a).join(NIL).search(rx.NonSpace);
+ } else {
- /**
- * Obtain the indentation spaces
- */
- let spacer = indent(begins);
+ // Update Parse Table Record (this is singleton or void)
+ //
+ record.types = 'ignore';
+ record.token = token = source.slice(from, a + 1);
- // Edge case to ensure the correct amount of indentation is applied
- // in situations where token is place inline, eg:
- //
- // foo
- //
- // In this situation the
tag is forced and aligned to the starting
- // point of the "
- //
- //
- if (spacer === NIL) {
- if (data.token[parse.count].search(rx.NonSpace) > 0) {
- spacer = u.repeatChar(data.token[parse.count].search(rx.NonSpace));
- } else {
- spacer = NIL;
- }
- }
+ }
- attrs = [];
- token = spacer + b.slice(begins, a - tags.length + 1).join(NIL) + tags.join(NIL);
+ attrs = [];
+ ignore = false;
- record.types = 'ignore';
- record.token = token;
+ push(record);
- } else if (ltype === 'liquid_ignore') {
+ }
- if (!parse.is('types', 'ignore')) data.types[parse.count] = 'ignore';
+ /**
+ * Parse Ignore
+ *
+ * Additional logic required to find the end of a tag when it contains
+ * a `data-esthetic-ignore` attribute annotation. The function also
+ * handles `esthetic-ignore-next` ignore comments placed above tag regions.
+ *
+ */
+ function parseIgnore (): ReturnType {
- // Similar to regular ignores, we need to obtain the offset spacing
- // to ensure indentation of the first token following the ignore comment
- // We can obtain the starting point index using the following subtraction
- // and addition. The ending result will point to the {{ or {% location.
- //
- token = indent(a - token.length - tags.length + 1, token) + tags.join(NIL);
- ltype = 'ignore';
+ // Parse Preserve
+ //
+ // We will first detect any preserved structures and pass it on
+ // these types infer ignores that respect indentation and are rule based.
+ //
+ if (
+ ltype === 'script_preserve' ||
+ ltype === 'json_preserve' ||
+ ltype === 'style_preserve') {
+
+ record.types = 'start';
+ record.stack = ltype === 'style_preserve' ? 'style' : 'script';
+
+ parseAttribute();
+
+ a = a + 1;
+ attrs = [];
+
+ return parseIgnoreToken(`${tname}>`, Languages.HTML);
+
+ }
- record.types = 'ignore';
- record.token = token;
+ // if (embed === false) return parseSingleton();
- } else {
+ // Ignore Next
+ //
+ // When the previous token type is ignore_next we need to determine
+ // the next token and exclude it from formatting.
+ //
+ if (data.types[parse.count] === 'ignore_next') {
- if (ltype.startsWith('liquid_')) {
+ if (ltype === 'liquid_start') {
- // TODO
+ return parseIgnoreNext(`end${tname}`, TokenType.LiquidEndTag);
- } else {
+ } else if (ltype === 'liquid') {
- record.types = 'start';
+ if (grammar.liquid.tags.has(tname)) {
+ ltype = 'liquid_start';
+ return parseIgnoreNext(`end${tname}`, TokenType.LiquidEndTag);
+ } else {
+ return parseIgnoreNext(end, end === '}}' ? TokenType.LiquidOutput : TokenType.LiquidSingular);
+ }
- // Parse the attributes
- //
- parseAttribute(true);
+ } else if (grammar.html.voids.has(tname)) {
- // Get Closing Token
- //
- const close = tags.lastIndexOf('<');
- const inner = tags.slice(0, close).join(NIL);
+ return parseIgnoreNext(end, TokenType.MarkupVoid);
- if (!rx.NonSpace.test(inner)) {
+ } else if (u.is(end, cc.RAN)) {
- // The inner content of the tag contains nothing
- // We will instead just push the ender token
- //
- push(record, [
- {
- lexer: 'markup',
- types: 'end',
- token: tags.slice(close).join(NIL).trim()
- }
- ]);
+ return parseIgnoreNext(`${tname}>`, TokenType.MarkupEnd);
- } else {
+ }
- // The inner content contains something other
- // than whitespace or newlines, so we add it and
- // also push the ender token
- //
- push(record, [
- {
- lexer: 'markup',
- types: ltype,
- token: inner
- },
- {
- lexer: 'markup',
- types: 'end',
- token: tags
- .slice(close)
- .join(NIL)
- .trim()
- }
- ]);
- }
+ // TODO: PARSE WARNINGS
+ // We will add a parse warning here in the future
- embed = false;
- language = html;
+ ignore = false;
+ preserve = false;
- return parseScript();
+ return parseSingleton();
- }
+ } else if (ignored.has(tname)) {
- }
+ return parseIgnoreToken(`end${tname}`, Languages.Liquid);
}
@@ -1263,7 +1467,7 @@ export function markup (input?: string) {
* Parse exts
*
* Determines whether or not the token contains an external region
- * like that of ``, `') {
- if (end === '' });
- parse.external('css', output);
+ } else {
- push(record, { token: '-->' });
+ parse.external(language, output);
- } else {
+ record.token = end;
+ record.types = 'end';
- parse.external(language, output);
+ a = a - 1;
- }
+ }
- break;
+ break;
- }
}
+
}
} else if (
@@ -4395,9 +4624,11 @@ export function markup (input?: string) {
if (name === 'style' && end === ' 0 && parse.pairs.has(parse.stack.index)) {
+ if (parse.stack.index in parse.pairs) {
- console.log(parse.pairs);
-
- const pair = parse.pairs.get(parse.stack.index);
+ const pair = parse.pairs[parse.stack.index];
if (pair.type === Languages.HTML) {
-
SyntacticError(ParseError.MissingHTMLEndTag, pair);
-
}
-
}
}
diff --git a/src/lexers/script.ts b/src/lexers/script.ts
index 4399d76..759fae2 100644
--- a/src/lexers/script.ts
+++ b/src/lexers/script.ts
@@ -572,8 +572,7 @@ export function script () {
if (wtest > -1) word();
- comment = commentBlock({
- chars: c,
+ comment = commentBlock(c, {
end: b,
lexer: 'script',
begin: '/*',
diff --git a/src/lexers/style.ts b/src/lexers/style.ts
index e2dd158..5f7f669 100644
--- a/src/lexers/style.ts
+++ b/src/lexers/style.ts
@@ -1387,13 +1387,12 @@ export function style () {
} else {
- comm = commentBlock({
- chars: b,
+ comm = commentBlock(b, {
start: a,
end: c,
lexer: 'style',
begin: '/*',
- ender: '\u002a/'
+ ender: '*/'
});
ltoke = comm[0];
diff --git a/src/lexical/enum.ts b/src/lexical/enum.ts
index 01435c2..060c77a 100644
--- a/src/lexical/enum.ts
+++ b/src/lexical/enum.ts
@@ -25,6 +25,41 @@ export const enum Beautifiers {
Style,
}
+export const enum Comm {
+ /**
+ * Markup Comment type
+ *
+ * ```html
+ *
+ * ```
+ */
+ Markup = 1,
+ /**
+ * Liquid Comment Block
+ *
+ * ```liquid
+ * {% comment %} {% endcomment %}
+ * ```
+ */
+ LiquidBlock,
+ /**
+ * Liquid Comment Line
+ *
+ * ```liquid
+ * {% # %}
+ * ```
+ */
+ LiquidLine,
+ /**
+ * JavaScript/CSS Comment Block
+ *
+ * ```js
+ * /* *
+ * ```
+ */
+ Block
+}
+
export enum LogLevel {
/**
* Disables logs, only parse errors will show.
diff --git a/src/lexical/errors.ts b/src/lexical/errors.ts
index fa50068..d7317ab 100644
--- a/src/lexical/errors.ts
+++ b/src/lexical/errors.ts
@@ -15,7 +15,12 @@ export const enum ErrorTypes {
export const enum ParseWarn {
- LiquidHangingComma = 201
+ /**
+ * Invalid esthetic-ignore-next code token expression
+ */
+ InvalidIgnoreNext = 201,
+
+ LiquidHangingComma
}
export const enum ParseError {
@@ -74,6 +79,23 @@ export const enum ParseError {
*
+
`,
- liquid`{% # 2 newlines following comment are respected %}
+ html`
- 2 NEWLINES FOLLOWING COMMENT
+ 2 NEWLINES FOLLOWING COMMENT
@@ -32,10 +152,10 @@ test('HTML Ignore Comment Next - Newlines and indentation', async t => {
`,
- liquid`{% # 3 newlines following comment are respected %}
+ html`
- 3 NEWLINES FOLLOWING COMMENT
+ 3 NEWLINES FOLLOWING COMMENT
@@ -46,28 +166,32 @@ test('HTML Ignore Comment Next - Newlines and indentation', async t => {
`,
- liquid`{% # Apply newline forced when comment on same line %}
+ html`
- 1 NEWLINE IS FORCED FOLLOW COMMENT
+ 1 NEWLINE IS FORCED FOLLOW COMMENT
-
`,
- liquid`{% # Respect Spacing of contained ignore content %}
+ html`
@@ -99,17 +223,20 @@ test('HTML Ignore Comment Next - Newlines and indentation', async t => {
`,
- liquid`{% # Respecting ignored indentation and newlines %}
+ html`
-
-
CONTENT BEFORE WILL FORMAT
-
+
+
+ CONTENT BEFORE WILL FORMAT
+
+
@@ -129,16 +256,20 @@ test('HTML Ignore Comment Next - Newlines and indentation', async t => {
-
+
- FORMAT WILL BE APPLIED HERE
+ FORMAT WILL BE APPLIED HERE
-
-
FORMAT WILL RESPECT
-
FORMAT WILL RESPECT
-
FORMAT WILL RESPECT
-
FORMAT WILL RESPECT
-
+
+
FORMAT WILL RESPECT
+
+ FORMAT WILL RESPECT
+
+
+ FORMAT WILL RESPECT
+
+
FORMAT WILL RESPECT
+
@@ -158,18 +289,19 @@ test('HTML Ignore Comment Next - Newlines and indentation', async t => {
-
+
`
]
)(
{
- language: 'liquid'
+ language: 'html'
}
)(function (source, rules, label) {
@@ -178,20 +310,20 @@ test('HTML Ignore Comment Next - Newlines and indentation', async t => {
t.snapshot(input, label);
});
-
});
-test('HTML Ignore Comment Next - Edge cases', async t => {
+test('HTML Ignore Comment Next - Edge cases', t => {
- await forSample(
+ forSample(
[
- liquid`{% # Extraneous spacing and newlines following the ignore comment %}
+ html`
-
-
CONTENT BEFORE FORMAT
-
+
+
+ CONTENT BEFORE FORMAT
+
@@ -208,18 +340,20 @@ test('HTML Ignore Comment Next - Edge cases', async t => {
>
-
+
`,
- liquid`{% # Invalid characters in following start tag %}
+ html`
-
-
CONTENT BEFORE FORMAT
-
+
+
+ CONTENT BEFORE FORMAT
+
+
@@ -230,19 +364,18 @@ test('HTML Ignore Comment Next - Edge cases', async t => {
p >
-
+
-
+
`
]
)(
{
- language: 'liquid'
+ language: 'html'
}
)(function (source, rules, label) {
@@ -254,17 +387,19 @@ test('HTML Ignore Comment Next - Edge cases', async t => {
});
-test('HTML Ignore Comment Next - Followed by Markup', async t => {
+test('HTML Ignore Comment Next - Followed by Markup', t => {
- await forSample(
+ forSample(
[
- liquid`{% # HTML structure within before and after content %}
+ html`
-
-
CONTENT BEFORE FORMAT
-
+
+
+ CONTENT BEFORE FORMAT
+
+
@@ -281,16 +416,17 @@ test('HTML Ignore Comment Next - Followed by Markup', async t => {
-