Skip to content

Commit

Permalink
add useLegacyConditions
Browse files Browse the repository at this point in the history
  • Loading branch information
Feverqwe committed Sep 11, 2024
1 parent 0a7da00 commit 1d316da
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/transform/liquid/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {log} from '../log';
import {NoValue, evalExp} from './evaluation';
import {tagLine} from './lexical';
import {SourceMapApi, createSourceMapApi, getLineNumber} from './sourceMap';
import legacyConditions from './legacyConditions';

interface SourceMap {
start: number;
Expand Down Expand Up @@ -248,8 +249,13 @@ export = function conditions(
settings?: {
sourceMap: Record<number, number>;
strict?: boolean;
useLegacyConditions?: boolean;
},
) {
if (settings?.useLegacyConditions) {
return legacyConditions(input, vars, path, settings);
}

const sourceMap = settings?.sourceMap || {};
const strict = settings?.strict || false;
const tagStack: IfTag[] = [];
Expand Down
4 changes: 3 additions & 1 deletion src/transform/liquid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function liquid<
conditions = true,
substitutions = true,
conditionsInCode = false,
useLegacyConditions = false,
keepNotVar = false,
withSourceMap,
} = settings || {};
Expand All @@ -89,6 +90,7 @@ function liquid<
conditions,
substitutions,
conditionsInCode,
useLegacyConditions,
keepNotVar,
withSourceMap,
});
Expand Down Expand Up @@ -116,7 +118,7 @@ function liquid<

if (conditions) {
const strict = conditions === 'strict';
output = applyConditions(output, vars, path, {sourceMap, strict});
output = applyConditions(output, vars, path, {sourceMap, strict, useLegacyConditions});
}

if (substitutions) {
Expand Down
252 changes: 252 additions & 0 deletions src/transform/liquid/legacyConditions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
import {bold} from 'chalk';

import {log} from '../log';

import evalExp from './evaluation';
import {tagLine} from './lexical';
import {getPreparedLeftContent, removeIndentBlock} from './utils';
import {createSourceMapApi, getLineNumber} from './sourceMap';

type Options = {
firstLineNumber: number;
lastLineNumber: number;
resFirstLineNumber: number;
resLastLineNumber: number;
linesTotal: number;
sourceMap: Record<number, number>;
};

function changeSourceMap({
firstLineNumber,
lastLineNumber,
resFirstLineNumber,
resLastLineNumber,
linesTotal,
sourceMap,
}: Options) {
if (!sourceMap) {
return;
}

const {getSourceMapValue, moveLines, removeLines} = createSourceMapApi(sourceMap);

let offsetRestLines;
if (resFirstLineNumber) {
// Move condition's content to the top
const offsetContentLines = firstLineNumber - resFirstLineNumber;
moveLines({
start: resFirstLineNumber,
end: resLastLineNumber - 1,
offset: offsetContentLines,
withReplace: true,
});

// Remove the rest lines of the condition block
removeLines({start: firstLineNumber, end: resFirstLineNumber - 1});
removeLines({start: resLastLineNumber, end: lastLineNumber});

// Calculate an offset of the rest lines
offsetRestLines = getSourceMapValue(resLastLineNumber - 1) - lastLineNumber;
} else {
// Remove the whole condition block
removeLines({start: firstLineNumber, end: lastLineNumber});

// Calculate offset of the rest lines
offsetRestLines = firstLineNumber - lastLineNumber - 1;
}

// Offset the rest lines
moveLines({start: lastLineNumber + 1, end: linesTotal, offset: offsetRestLines});
}

function getElseProp<B extends keyof Elses>({elses}: {elses: Elses[]}, propName: B, index = 0) {
if (!elses.length || index >= elses.length) {
return undefined;
}

return elses[index][propName];
}

type Opts = {
ifTag: Tag;
vars: Record<string, unknown>;
content: string;
match: RegExpExecArray;
lastIndex: number;
sourceMap: Record<number, number>;
linesTotal: number;
};

function inlineConditions({ifTag, vars, content, match, lastIndex, sourceMap, linesTotal}: Opts) {
let res = '';
const firstLineNumber = getLineNumber(content, ifTag.startPos);
const lastLineNumber = getLineNumber(content, lastIndex);
let resFirstLineNumber = 0;
let resLastLineNumber = 0;

if (evalExp(ifTag.condition, vars)) {
const ifRawLastIndex = ifTag.startPos + ifTag.ifRaw.length;
const contentLastIndex = getElseProp(ifTag, 'startPos') || match.index;

res = content.substring(ifRawLastIndex, contentLastIndex);
resFirstLineNumber = getLineNumber(content, ifRawLastIndex + 1);
resLastLineNumber = getLineNumber(content, contentLastIndex + 1);
} else {
ifTag.elses.some(({condition, startPos, raw}, index) => {
const isTruthy = !condition || evalExp(condition, vars);

if (isTruthy) {
const elseRawLastIndex = startPos + raw.length;
const contentLastIndex = getElseProp(ifTag, 'startPos', index + 1) || match.index;

res = content.substring(elseRawLastIndex, contentLastIndex);
resFirstLineNumber = getLineNumber(content, elseRawLastIndex + 1);
resLastLineNumber = getLineNumber(content, contentLastIndex + 1);

return true;
}

return false;
});
}

changeSourceMap({
firstLineNumber,
lastLineNumber,
resFirstLineNumber,
resLastLineNumber,
linesTotal,
sourceMap,
});

const preparedLeftContent = getPreparedLeftContent({
content,
tagStartPos: ifTag.startPos,
tagContent: res,
});

let shift = 0;
if (
res === '' &&
preparedLeftContent[preparedLeftContent.length - 1] === '\n' &&
content[lastIndex] === '\n'
) {
shift = 1;
}

if (res !== '') {
if (res[0] === '\n') {
res = res.substring(1);
}

res = removeIndentBlock(res);

if (res[res.length - 1] === '\n') {
res = res.slice(0, -1);
}
}

const leftPart = preparedLeftContent + res;

return {
result: leftPart + content.substring(lastIndex + shift),
idx: leftPart.length,
};
}

type Elses = {startPos: number; raw: string; condition?: string};

type Tag = {
isOpen: Boolean;
condition: string;
startPos: number;
ifRaw: string;
elses: Elses[];
};

export = function legacyConditions(
originInput: string,
vars: Record<string, unknown>,
path?: string,
settings?: {
sourceMap: Record<number, number>;
},
) {
const sourceMap = settings?.sourceMap || {};

const R_LIQUID = /({%-?([\s\S]*?)-?%})/g;

let match;
const tagStack: Tag[] = [];
let input = originInput;
let linesTotal = originInput.split('\n').length;

while ((match = R_LIQUID.exec(input)) !== null) {
if (!match[1]) {
continue;
}

const tagMatch = match[2].trim().match(tagLine);
if (!tagMatch) {
continue;
}

const [type, args] = tagMatch.slice(1);

switch (type) {
case 'if':
tagStack.push({
isOpen: true,
condition: args,
startPos: match.index,
ifRaw: match[1],
elses: [],
});
break;
case 'else':
tagStack[tagStack.length - 1].elses.push({
startPos: match.index,
raw: match[1],
});
break;
case 'elsif':
tagStack[tagStack.length - 1].elses.push({
condition: args,
startPos: match.index,
raw: match[1],
});
break;
case 'endif': {
const ifTag = tagStack.pop();

if (!ifTag) {
log.error(
`If block must be opened before close${path ? ` in ${bold(path)}` : ''}`,
);
break;
}

const {idx, result} = inlineConditions({
ifTag,
vars,
content: input,
match,
lastIndex: R_LIQUID.lastIndex,
sourceMap,
linesTotal,
});
R_LIQUID.lastIndex = idx;
input = result;
linesTotal = result.split('\n').length;

break;
}
}
}

if (tagStack.length !== 0) {
log.error(`Condition block must be closed${path ? ` in ${bold(path)}` : ''}`);
}

return input;
};
1 change: 1 addition & 0 deletions src/transform/liquid/services/argv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type ArgvSettings = {
substitutions?: boolean;
keepNotVar?: boolean;
withSourceMap?: boolean;
useLegacyConditions?: boolean;
};

let _argv: ArgvSettings;
Expand Down

0 comments on commit 1d316da

Please sign in to comment.