eslint-plugin-jsonc
Version:
ESLint plugin for JSON, JSONC and JSON5 files.
174 lines (173 loc) • 5.98 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.fixForSorting = fixForSorting;
const eslint_utils_1 = require("@eslint-community/eslint-utils");
function* fixForSorting(fixer, sourceCode, target, to) {
const targetInfo = calcTargetInfo(sourceCode, target);
const toPrevInfo = getPrevElementInfo(sourceCode, to);
if (toPrevInfo.comma &&
toPrevInfo.last.range[1] <= toPrevInfo.comma.range[0]) {
yield fixer.removeRange(toPrevInfo.comma.range);
}
let insertRange = [
toPrevInfo.last.range[1],
toPrevInfo.last.range[1],
];
const toBeforeNextToken = sourceCode.getTokenAfter(toPrevInfo.last, {
includeComments: true,
});
if (toBeforeNextToken.loc.start.line - toPrevInfo.last.loc.end.line > 1) {
const offset = sourceCode.getIndexFromLoc({
line: toBeforeNextToken.loc.start.line - 1,
column: 0,
});
insertRange = [offset, offset];
}
yield fixer.insertTextAfterRange(insertRange, targetInfo.insertCode);
for (const removeRange of targetInfo.removeRanges) {
yield fixer.removeRange(removeRange);
}
}
function calcTargetInfo(sourceCode, target) {
const nodeEndIndex = target.node
? getLastTokenOfNode(sourceCode, target.node).range[1]
: target.after.range[0];
const endInfo = getElementEndInfo(sourceCode, target);
const prevInfo = getPrevElementInfo(sourceCode, target);
let insertCode;
const removeRanges = [];
if (prevInfo.comma && prevInfo.last.range[1] <= prevInfo.comma.range[0]) {
insertCode = `${sourceCode.text.slice(prevInfo.last.range[1], prevInfo.comma.range[0])}${sourceCode.text.slice(prevInfo.comma.range[1], nodeEndIndex)}`;
removeRanges.push([prevInfo.last.range[1], prevInfo.comma.range[0]], [prevInfo.comma.range[1], nodeEndIndex]);
}
else {
insertCode = sourceCode.text.slice(prevInfo.last.range[1], nodeEndIndex);
removeRanges.push([prevInfo.last.range[1], nodeEndIndex]);
}
const hasTrailingComma = endInfo.comma && endInfo.comma.range[1] <= endInfo.last.range[1];
if (!hasTrailingComma) {
insertCode += ",";
if (prevInfo.comma) {
removeRanges.push(prevInfo.comma.range);
}
}
insertCode += sourceCode.text.slice(nodeEndIndex, endInfo.last.range[1]);
removeRanges.push([nodeEndIndex, endInfo.last.range[1]]);
return {
insertCode,
removeRanges,
};
}
function getFirstTokenOfNode(sourceCode, node) {
let token = sourceCode.getFirstToken(node);
let target = token;
while ((target = sourceCode.getTokenBefore(token)) &&
(0, eslint_utils_1.isOpeningParenToken)(target)) {
token = target;
}
return token;
}
function getLastTokenOfNode(sourceCode, node) {
let token = sourceCode.getLastToken(node);
let target = token;
while ((target = sourceCode.getTokenAfter(token)) &&
(0, eslint_utils_1.isClosingParenToken)(target)) {
token = target;
}
return token;
}
function getElementEndInfo(sourceCode, target) {
const afterToken = target.node
? sourceCode.getTokenAfter(getLastTokenOfNode(sourceCode, target.node))
: target.after;
if ((0, eslint_utils_1.isNotCommaToken)(afterToken)) {
return {
comma: null,
nextElement: null,
last: getLastTokenWithTrailingComments(sourceCode, target),
};
}
const comma = afterToken;
const nextElement = sourceCode.getTokenAfter(afterToken);
if ((0, eslint_utils_1.isCommaToken)(nextElement)) {
return {
comma,
nextElement: null,
last: comma,
};
}
if ((0, eslint_utils_1.isClosingBraceToken)(nextElement) || (0, eslint_utils_1.isClosingBracketToken)(nextElement)) {
return {
comma,
nextElement: null,
last: getLastTokenWithTrailingComments(sourceCode, target),
};
}
const node = target.node;
if (node && node.loc.end.line === nextElement.loc.start.line) {
return {
comma,
nextElement,
last: comma,
};
}
if (node &&
node.loc.end.line < comma.loc.start.line &&
comma.loc.end.line < nextElement.loc.start.line) {
return {
comma,
nextElement,
last: comma,
};
}
return {
comma,
nextElement,
last: getLastTokenWithTrailingComments(sourceCode, target),
};
}
function getLastTokenWithTrailingComments(sourceCode, target) {
if (!target.node) {
return sourceCode.getTokenBefore(target.after, {
includeComments: true,
});
}
const node = target.node;
let last = getLastTokenOfNode(sourceCode, node);
let after;
while ((after = sourceCode.getTokenAfter(last, {
includeComments: true,
})) &&
((0, eslint_utils_1.isCommentToken)(after) || (0, eslint_utils_1.isCommaToken)(after)) &&
node.loc.end.line === after.loc.end.line) {
last = after;
}
return last;
}
function getPrevElementInfo(sourceCode, target) {
const beforeToken = target.node
? sourceCode.getTokenBefore(getFirstTokenOfNode(sourceCode, target.node))
: target.before;
if ((0, eslint_utils_1.isNotCommaToken)(beforeToken)) {
return {
comma: null,
prevElement: null,
last: beforeToken,
};
}
const comma = beforeToken;
const prevElement = sourceCode.getTokenBefore(beforeToken);
if ((0, eslint_utils_1.isCommaToken)(prevElement)) {
return {
comma,
prevElement: null,
last: comma,
};
}
const endInfo = getElementEndInfo(sourceCode, { node: prevElement });
return {
comma: endInfo.comma,
prevElement,
last: endInfo.last,
};
}
;