Extract common/util.js to utils/ (#14329)
This commit is contained in:
1 parent
83124d7fd6
commit
282a4019c7
66 files changed
+496
-499
No files matched your search
@@ -1,389 +0,0 @@
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
import {
|
||||
skip,
|
||||
skipWhitespace,
|
||||
skipSpaces,
|
||||
skipToLineEnd,
|
||||
skipEverythingButNewLine,
|
||||
} from "../utils/text/skip.js";
|
||||
import skipInlineComment from "../utils/text/skip-inline-comment.js";
|
||||
import skipTrailingComment from "../utils/text/skip-trailing-comment.js";
|
||||
import skipNewline from "../utils/text/skip-newline.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "../utils/text/get-next-non-space-non-comment-character-index.js";
|
||||
|
||||
/**
|
||||
* @typedef {{backwards?: boolean}} SkipOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @param {SkipOptions=} options
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasNewline(text, startIndex, options = {}) {
|
||||
const idx = skipSpaces(
|
||||
text,
|
||||
options.backwards ? startIndex - 1 : startIndex,
|
||||
options
|
||||
);
|
||||
const idx2 = skipNewline(text, idx, options);
|
||||
return idx !== idx2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @param {number} endIndex
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasNewlineInRange(text, startIndex, endIndex) {
|
||||
for (let i = startIndex; i < endIndex; ++i) {
|
||||
if (text.charAt(i) === "\n") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: this function doesn't ignore leading comments unlike isNextLineEmpty
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isPreviousLineEmpty(text, startIndex) {
|
||||
/** @type {number | false} */
|
||||
let idx = startIndex - 1;
|
||||
idx = skipSpaces(text, idx, { backwards: true });
|
||||
idx = skipNewline(text, idx, { backwards: true });
|
||||
idx = skipSpaces(text, idx, { backwards: true });
|
||||
const idx2 = skipNewline(text, idx, { backwards: true });
|
||||
return idx !== idx2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isNextLineEmpty(text, startIndex) {
|
||||
/** @type {number | false} */
|
||||
let oldIdx = null;
|
||||
/** @type {number | false} */
|
||||
let idx = startIndex;
|
||||
while (idx !== oldIdx) {
|
||||
// We need to skip all the potential trailing inline comments
|
||||
oldIdx = idx;
|
||||
idx = skipToLineEnd(text, idx);
|
||||
idx = skipInlineComment(text, idx);
|
||||
idx = skipSpaces(text, idx);
|
||||
}
|
||||
idx = skipTrailingComment(text, idx);
|
||||
idx = skipNewline(text, idx);
|
||||
return idx !== false && hasNewline(text, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @returns {string}
|
||||
*/
|
||||
function getNextNonSpaceNonCommentCharacter(text, startIndex) {
|
||||
const index = getNextNonSpaceNonCommentCharacterIndex(text, startIndex);
|
||||
return index === false ? "" : text.charAt(index);
|
||||
}
|
||||
|
||||
// Not using, but it's public utils
|
||||
/* c8 ignore start */
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @param {SkipOptions=} options
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasSpaces(text, startIndex, options = {}) {
|
||||
const idx = skipSpaces(
|
||||
text,
|
||||
options.backwards ? startIndex - 1 : startIndex,
|
||||
options
|
||||
);
|
||||
return idx !== startIndex;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} tabWidth
|
||||
* @param {number=} startIndex
|
||||
* @returns {number}
|
||||
*/
|
||||
function getAlignmentSize(text, tabWidth, startIndex = 0) {
|
||||
let size = 0;
|
||||
for (let i = startIndex; i < text.length; ++i) {
|
||||
if (text[i] === "\t") {
|
||||
// Tabs behave in a way that they are aligned to the nearest
|
||||
// multiple of tabWidth:
|
||||
// 0 -> 4, 1 -> 4, 2 -> 4, 3 -> 4
|
||||
// 4 -> 8, 5 -> 8, 6 -> 8, 7 -> 8 ...
|
||||
size = size + tabWidth - (size % tabWidth);
|
||||
} else {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {number} tabWidth
|
||||
* @returns {number}
|
||||
*/
|
||||
function getIndentSize(value, tabWidth) {
|
||||
const lastNewlineIndex = value.lastIndexOf("\n");
|
||||
/* c8 ignore next 3 */
|
||||
if (lastNewlineIndex === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getAlignmentSize(
|
||||
// All the leading whitespaces
|
||||
value.slice(lastNewlineIndex + 1).match(/^[\t ]*/)[0],
|
||||
tabWidth
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {'"' | "'"} Quote
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} rawContent
|
||||
* @param {Quote} preferredQuote
|
||||
* @returns {{ quote: Quote, regex: RegExp, escaped: string }}
|
||||
*/
|
||||
|
||||
function getPreferredQuote(rawContent, preferredQuote) {
|
||||
/** @type {{ quote: '"', regex: RegExp, escaped: """ }} */
|
||||
const double = { quote: '"', regex: /"/g, escaped: """ };
|
||||
/** @type {{ quote: "'", regex: RegExp, escaped: "'" }} */
|
||||
const single = { quote: "'", regex: /'/g, escaped: "'" };
|
||||
|
||||
const preferred = preferredQuote === "'" ? single : double;
|
||||
const alternate = preferred === single ? double : single;
|
||||
|
||||
let result = preferred;
|
||||
|
||||
// If `rawContent` contains at least one of the quote preferred for enclosing
|
||||
// the string, we might want to enclose with the alternate quote instead, to
|
||||
// minimize the number of escaped quotes.
|
||||
if (
|
||||
rawContent.includes(preferred.quote) ||
|
||||
rawContent.includes(alternate.quote)
|
||||
) {
|
||||
const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
|
||||
const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;
|
||||
|
||||
result = numPreferredQuotes > numAlternateQuotes ? alternate : preferred;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function printString(raw, options) {
|
||||
// `rawContent` is the string exactly like it appeared in the input source
|
||||
// code, without its enclosing quotes.
|
||||
const rawContent = raw.slice(1, -1);
|
||||
|
||||
/** @type {Quote} */
|
||||
const enclosingQuote =
|
||||
options.parser === "json" ||
|
||||
(options.parser === "json5" &&
|
||||
options.quoteProps === "preserve" &&
|
||||
!options.singleQuote)
|
||||
? '"'
|
||||
: options.__isInHtmlAttribute
|
||||
? "'"
|
||||
: getPreferredQuote(rawContent, options.singleQuote ? "'" : '"').quote;
|
||||
|
||||
// It might sound unnecessary to use `makeString` even if the string already
|
||||
// is enclosed with `enclosingQuote`, but it isn't. The string could contain
|
||||
// unnecessary escapes (such as in `"\'"`). Always using `makeString` makes
|
||||
// sure that we consistently output the minimum amount of escaped quotes.
|
||||
return makeString(
|
||||
rawContent,
|
||||
enclosingQuote,
|
||||
!(
|
||||
options.parser === "css" ||
|
||||
options.parser === "less" ||
|
||||
options.parser === "scss" ||
|
||||
options.__embeddedInHtml
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} rawText
|
||||
* @param {Quote} enclosingQuote
|
||||
* @param {boolean=} unescapeUnnecessaryEscapes
|
||||
* @returns {string}
|
||||
*/
|
||||
function makeString(rawText, enclosingQuote, unescapeUnnecessaryEscapes) {
|
||||
const otherQuote = enclosingQuote === '"' ? "'" : '"';
|
||||
|
||||
// Matches _any_ escape and unescaped quotes (both single and double).
|
||||
const regex = /\\(.)|(["'])/gs;
|
||||
|
||||
// Escape and unescape single and double quotes as needed to be able to
|
||||
// enclose `rawText` with `enclosingQuote`.
|
||||
const raw = rawText.replaceAll(regex, (match, escaped, quote) => {
|
||||
// If we matched an escape, and the escaped character is a quote of the
|
||||
// other type than we intend to enclose the string with, there's no need for
|
||||
// it to be escaped, so return it _without_ the backslash.
|
||||
if (escaped === otherQuote) {
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// If we matched an unescaped quote and it is of the _same_ type as we
|
||||
// intend to enclose the string with, it must be escaped, so return it with
|
||||
// a backslash.
|
||||
if (quote === enclosingQuote) {
|
||||
return "\\" + quote;
|
||||
}
|
||||
|
||||
if (quote) {
|
||||
return quote;
|
||||
}
|
||||
|
||||
// Unescape any unnecessarily escaped character.
|
||||
// Adapted from https://github.com/eslint/eslint/blob/de0b4ad7bd820ade41b1f606008bea68683dc11a/lib/rules/no-useless-escape.js#L27
|
||||
return unescapeUnnecessaryEscapes &&
|
||||
/^[^\n\r"'0-7\\bfnrt-vx\u2028\u2029]$/.test(escaped)
|
||||
? escaped
|
||||
: "\\" + escaped;
|
||||
});
|
||||
|
||||
return enclosingQuote + raw + enclosingQuote;
|
||||
}
|
||||
|
||||
function printNumber(rawNumber) {
|
||||
return (
|
||||
rawNumber
|
||||
.toLowerCase()
|
||||
// Remove unnecessary plus and zeroes from scientific notation.
|
||||
.replace(/^([+-]?[\d.]+e)(?:\+|(-))?0*(?=\d)/, "$1$2")
|
||||
// Remove unnecessary scientific notation (1e0).
|
||||
.replace(/^([+-]?[\d.]+)e[+-]?0+$/, "$1")
|
||||
// Make sure numbers always start with a digit.
|
||||
.replace(/^([+-])?\./, "$10.")
|
||||
// Remove extraneous trailing decimal zeroes.
|
||||
.replace(/(\.\d+?)0+(?=e|$)/, "$1")
|
||||
// Remove trailing dot.
|
||||
.replace(/\.(?=e|$)/, "")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {string} searchString
|
||||
* @returns {number}
|
||||
*/
|
||||
function getMaxContinuousCount(text, searchString) {
|
||||
const results = text.match(
|
||||
new RegExp(`(${escapeStringRegexp(searchString)})+`, "g")
|
||||
);
|
||||
|
||||
if (results === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return results.reduce(
|
||||
(maxCount, result) =>
|
||||
Math.max(maxCount, result.length / searchString.length),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {string} searchString
|
||||
* @returns {number}
|
||||
*/
|
||||
function getMinNotPresentContinuousCount(text, searchString) {
|
||||
const matches = text.match(
|
||||
new RegExp(`(${escapeStringRegexp(searchString)})+`, "g")
|
||||
);
|
||||
|
||||
if (matches === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const countPresent = new Map();
|
||||
let max = 0;
|
||||
|
||||
for (const match of matches) {
|
||||
const count = match.length / searchString.length;
|
||||
countPresent.set(count, true);
|
||||
if (count > max) {
|
||||
max = count;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 1; i < max; i++) {
|
||||
if (!countPresent.get(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
function isFrontMatterNode(node) {
|
||||
return node?.type === "front-matter";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} description
|
||||
* @returns {(node: any) => symbol}
|
||||
*/
|
||||
function createGroupIdMapper(description) {
|
||||
const groupIds = new WeakMap();
|
||||
return function (node) {
|
||||
if (!groupIds.has(node)) {
|
||||
groupIds.set(node, Symbol(description));
|
||||
}
|
||||
return groupIds.get(node);
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
getMaxContinuousCount,
|
||||
getMinNotPresentContinuousCount,
|
||||
getNextNonSpaceNonCommentCharacterIndex,
|
||||
getNextNonSpaceNonCommentCharacter,
|
||||
skip,
|
||||
skipWhitespace,
|
||||
skipSpaces,
|
||||
skipToLineEnd,
|
||||
skipEverythingButNewLine,
|
||||
skipInlineComment,
|
||||
skipTrailingComment,
|
||||
skipNewline,
|
||||
isNextLineEmpty,
|
||||
isPreviousLineEmpty,
|
||||
hasNewline,
|
||||
hasNewlineInRange,
|
||||
hasSpaces,
|
||||
getAlignmentSize,
|
||||
getIndentSize,
|
||||
getPreferredQuote,
|
||||
printString,
|
||||
printNumber,
|
||||
makeString,
|
||||
isFrontMatterNode,
|
||||
createGroupIdMapper,
|
||||
};
|
||||
export { default as isNonEmptyArray } from "../utils/is-non-empty-array.js";
|
||||
export { default as getStringWidth } from "../utils/get-string-width.js";
|
||||
+1
-1
@@ -39,7 +39,7 @@ for (const name of debugApiFunctionNames) {
|
||||
prettier.__debug = debugApis;
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
prettier.util = require("./common/util-shared.js");
|
||||
prettier.util = require("./utils/public.js");
|
||||
prettier.doc = require("./document/index.js");
|
||||
} else {
|
||||
Object.defineProperties(prettier, {
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ import { hiddenDefaults as optionsHiddenDefaults } from "./main/options.js";
|
||||
import normalizeOptions from "./main/options-normalizer.js";
|
||||
import arrayify from "./utils/arrayify.js";
|
||||
import partition from "./utils/partition.js";
|
||||
import { isNonEmptyArray } from "./common/util.js";
|
||||
import isNonEmptyArray from "./utils/is-non-empty-array.js";
|
||||
|
||||
const builtinPlugins = Object.values(languages);
|
||||
|
||||
@@ -110,6 +110,6 @@ export {
|
||||
sharedWithCli as __internal,
|
||||
debugApis as __debug,
|
||||
};
|
||||
export * as util from "./common/util-shared.js";
|
||||
export * as util from "./utils/public.js";
|
||||
export * as doc from "./document/index.js";
|
||||
export { default as version } from "./main/version.evaluate.cjs";
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isFrontMatterNode } from "../common/util.js";
|
||||
import isFrontMatter from "../utils/front-matter/is-front-matter.js";
|
||||
|
||||
const ignoredProperties = new Set([
|
||||
"raw", // front-matter
|
||||
@@ -12,7 +12,7 @@ const ignoredProperties = new Set([
|
||||
]);
|
||||
|
||||
function clean(ast, newObj, parent) {
|
||||
if (isFrontMatterNode(ast) && ast.lang === "yaml") {
|
||||
if (isFrontMatter(ast) && ast.lang === "yaml") {
|
||||
delete newObj.value;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ function clean(ast, newObj, parent) {
|
||||
// first non-front-matter comment
|
||||
if (
|
||||
parent.nodes[0] === ast ||
|
||||
(isFrontMatterNode(parent.nodes[0]) && parent.nodes[1] === ast)
|
||||
(isFrontMatter(parent.nodes[0]) && parent.nodes[1] === ast)
|
||||
) {
|
||||
/**
|
||||
* something
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { skipEverythingButNewLine } from "../utils/text/skip.js";
|
||||
import { skipEverythingButNewLine } from "../utils/skip.js";
|
||||
import isNonEmptyArray from "../utils/is-non-empty-array.js";
|
||||
import lineColumnToIndex from "../utils/line-column-to-index.js";
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {
|
||||
printNumber,
|
||||
printString,
|
||||
hasNewline,
|
||||
isFrontMatterNode,
|
||||
isNextLineEmpty,
|
||||
isNonEmptyArray,
|
||||
} from "../common/util.js";
|
||||
import printNumber from "../utils/print-number.js";
|
||||
import printString from "../utils/print-string.js";
|
||||
import hasNewline from "../utils/has-newline.js";
|
||||
import isFrontMatter from "../utils/front-matter/is-front-matter.js";
|
||||
import isNextLineEmpty from "../utils/is-next-line-empty.js";
|
||||
import isNonEmptyArray from "../utils/is-non-empty-array.js";
|
||||
import {
|
||||
join,
|
||||
line,
|
||||
@@ -1100,7 +1098,7 @@ function printNodeSequence(path, options, print) {
|
||||
!hasNewline(options.originalText, locStart(next), {
|
||||
backwards: true,
|
||||
}) &&
|
||||
!isFrontMatterNode(node)) ||
|
||||
!isFrontMatter(node)) ||
|
||||
(next.type === "css-atrule" &&
|
||||
next.name === "else" &&
|
||||
node.type !== "css-comment")
|
||||
@@ -1110,7 +1108,7 @@ function printNodeSequence(path, options, print) {
|
||||
parts.push(options.__isHTMLStyleAttribute ? line : hardline);
|
||||
if (
|
||||
isNextLineEmpty(options.originalText, locEnd(node)) &&
|
||||
!isFrontMatterNode(node)
|
||||
!isFrontMatter(node)
|
||||
) {
|
||||
parts.push(hardline);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
indent,
|
||||
ifBreak,
|
||||
} from "../document/builders.js";
|
||||
import { isNextLineEmpty, isNonEmptyArray } from "../common/util.js";
|
||||
import isNextLineEmpty from "../utils/is-next-line-empty.js";
|
||||
import isNonEmptyArray from "../utils/is-non-empty-array.js";
|
||||
import UnexpectedNodeError from "../utils/unexpected-node-error.js";
|
||||
import { insertPragma } from "./pragma.js";
|
||||
import { locStart, locEnd } from "./loc.js";
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
softline,
|
||||
} from "../document/builders.js";
|
||||
import { replaceEndOfLine } from "../document/utils.js";
|
||||
import { getPreferredQuote, isNonEmptyArray } from "../common/util.js";
|
||||
import getPreferredQuote from "../utils/get-preferred-quote.js";
|
||||
import isNonEmptyArray from "../utils/is-non-empty-array.js";
|
||||
import UnexpectedNodeError from "../utils/unexpected-node-error.js";
|
||||
import { locStart, locEnd } from "./loc.js";
|
||||
import clean from "./clean.js";
|
||||
@@ -686,7 +687,7 @@ function generateHardlines(number = 0) {
|
||||
|
||||
/* StringLiteral print helpers */
|
||||
|
||||
/** @typedef {import("../common/util.js").Quote} Quote */
|
||||
/** @typedef {import("../utils/get-preferred-quote.js").Quote} Quote */
|
||||
|
||||
/**
|
||||
* Prints a string literal with the correct surrounding quotes based on
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isFrontMatterNode } from "../common/util.js";
|
||||
import isFrontMatter from "../utils/front-matter/is-front-matter.js";
|
||||
|
||||
const ignoredProperties = new Set([
|
||||
"sourceSpan",
|
||||
@@ -18,7 +18,7 @@ function clean(ast, newNode) {
|
||||
}
|
||||
|
||||
// may be formatted by multiparser
|
||||
if (isFrontMatterNode(ast) || ast.type === "yaml" || ast.type === "toml") {
|
||||
if (isFrontMatter(ast) || ast.type === "yaml" || ast.type === "toml") {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import assert from "node:assert";
|
||||
import { isNonEmptyArray } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import {
|
||||
indent,
|
||||
join,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @typedef {import("../../common/ast-path.js").default} AstPath
|
||||
*/
|
||||
|
||||
import { isFrontMatterNode } from "../../common/util.js";
|
||||
import isFrontMatter from "../../utils/front-matter/is-front-matter.js";
|
||||
import inferParserByLanguage from "../../utils/infer-parser-by-language.js";
|
||||
import { line, hardline, join } from "../../document/builders.js";
|
||||
import { replaceEndOfLine } from "../../document/utils.js";
|
||||
@@ -144,7 +144,7 @@ function isLeadingSpaceSensitiveNode(node, options) {
|
||||
return isLeadingSpaceSensitive;
|
||||
|
||||
function _isLeadingSpaceSensitiveNode() {
|
||||
if (isFrontMatterNode(node)) {
|
||||
if (isFrontMatter(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ function isLeadingSpaceSensitiveNode(node, options) {
|
||||
}
|
||||
|
||||
function isTrailingSpaceSensitiveNode(node, options) {
|
||||
if (isFrontMatterNode(node)) {
|
||||
if (isFrontMatter(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ function isDanglingSpaceSensitiveNode(node) {
|
||||
|
||||
function forceNextEmptyLine(node) {
|
||||
return (
|
||||
isFrontMatterNode(node) ||
|
||||
isFrontMatter(node) ||
|
||||
(node.next &&
|
||||
node.sourceSpan.end &&
|
||||
node.sourceSpan.end.line + 1 < node.next.sourceSpan.start.line)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import {
|
||||
hasNewline,
|
||||
getNextNonSpaceNonCommentCharacterIndex,
|
||||
getNextNonSpaceNonCommentCharacter,
|
||||
hasNewlineInRange,
|
||||
isNonEmptyArray,
|
||||
} from "../../common/util.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import getNextNonSpaceNonCommentCharacter from "../../utils/get-next-non-space-non-comment-character.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "../../utils/get-next-non-space-non-comment-character-index.js";
|
||||
import hasNewlineInRange from "../../utils/has-newline-in-range.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import {
|
||||
addLeadingComment,
|
||||
addTrailingComment,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNonEmptyArray } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import { indent, hardline, softline } from "../../document/builders.js";
|
||||
import { mapDoc, replaceEndOfLine, cleanDoc } from "../../document/utils.js";
|
||||
import { printTemplateExpressions } from "../print/template-literal.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import tryCombinations from "../../utils/try-combinations.js";
|
||||
import getShebang from "../utils/get-shebang.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "../../utils/text/get-next-non-space-non-comment-character-index.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "../../utils/get-next-non-space-non-comment-character-index.js";
|
||||
// JSON parsers are bundled here so we can reduce package size
|
||||
import jsonParsers from "../../language-json/parser-json.js";
|
||||
import createParser from "./utils/create-parser.js";
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ifBreak,
|
||||
fill,
|
||||
} from "../../document/builders.js";
|
||||
import { hasNewline } from "../../common/util.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import {
|
||||
shouldPrintComma,
|
||||
hasComment,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isNonEmptyArray, getStringWidth } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import getStringWidth from "../../utils/get-string-width.js";
|
||||
import {
|
||||
line,
|
||||
group,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { printDanglingComments } from "../../main/comments/print.js";
|
||||
import { isNonEmptyArray } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import { hardline, indent } from "../../document/builders.js";
|
||||
import {
|
||||
hasComment,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isNonEmptyArray, createGroupIdMapper } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import createGroupIdMapper from "../../utils/create-group-id-mapper.js";
|
||||
import {
|
||||
printComments,
|
||||
printDanglingComments,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isNonEmptyArray, hasNewline } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import {
|
||||
line,
|
||||
hardline,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/** @typedef {import("../../document/builders.js").Doc} Doc */
|
||||
|
||||
import assert from "node:assert";
|
||||
import { printString, printNumber } from "../../common/util.js";
|
||||
import printString from "../../utils/print-string.js";
|
||||
import printNumber from "../../utils/print-number.js";
|
||||
import { replaceEndOfLine } from "../../document/utils.js";
|
||||
import UnexpectedNodeError from "../../utils/unexpected-node-error.js";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getNextNonSpaceNonCommentCharacter } from "../../common/util.js";
|
||||
import getNextNonSpaceNonCommentCharacter from "../../utils/get-next-non-space-non-comment-character.js";
|
||||
import { printDanglingComments } from "../../main/comments/print.js";
|
||||
import {
|
||||
line,
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
printDanglingComments,
|
||||
printCommentsSeparately,
|
||||
} from "../../main/comments/print.js";
|
||||
import { getNextNonSpaceNonCommentCharacterIndex } from "../../common/util.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "../../utils/get-next-non-space-non-comment-character-index.js";
|
||||
import {
|
||||
line,
|
||||
softline,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNonEmptyArray } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import { join, line, group, indent, ifBreak } from "../../document/builders.js";
|
||||
import { hasComment, identity, CommentCheckFlags } from "../utils/index.js";
|
||||
import { getTypeParametersGroupId } from "./type-parameters.js";
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
} from "../../document/builders.js";
|
||||
import { willBreak, replaceEndOfLine } from "../../document/utils.js";
|
||||
import UnexpectedNodeError from "../../utils/unexpected-node-error.js";
|
||||
|
||||
import { getPreferredQuote } from "../../common/util.js";
|
||||
import getPreferredQuote from "../../utils/get-preferred-quote.js";
|
||||
import {
|
||||
isJsxElement,
|
||||
rawText,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { printString, printNumber } from "../../common/util.js";
|
||||
import printString from "../../utils/print-string.js";
|
||||
import printNumber from "../../utils/print-number.js";
|
||||
import { replaceEndOfLine } from "../../document/utils.js";
|
||||
import { printDirective } from "./misc.js";
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { printComments } from "../../main/comments/print.js";
|
||||
import {
|
||||
isNextLineEmpty as isNextLineEmptyAfterIndex,
|
||||
getNextNonSpaceNonCommentCharacterIndex,
|
||||
} from "../../common/util.js";
|
||||
import isNextLineEmptyAfterIndex from "../../utils/is-next-line-empty.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "../../utils/get-next-non-space-non-comment-character-index.js";
|
||||
import pathNeedsParens from "../needs-parens.js";
|
||||
import {
|
||||
isCallExpression,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNonEmptyArray } from "../../common/util.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import UnexpectedNodeError from "../../utils/unexpected-node-error.js";
|
||||
import {
|
||||
softline,
|
||||
|
||||
@@ -7,11 +7,9 @@ import {
|
||||
ifBreak,
|
||||
hardline,
|
||||
} from "../../document/builders.js";
|
||||
import {
|
||||
hasNewlineInRange,
|
||||
hasNewline,
|
||||
isNonEmptyArray,
|
||||
} from "../../common/util.js";
|
||||
import hasNewlineInRange from "../../utils/has-newline-in-range.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import {
|
||||
shouldPrintComma,
|
||||
hasComment,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { printComments } from "../../main/comments/print.js";
|
||||
import { printString, printNumber } from "../../common/util.js";
|
||||
import printString from "../../utils/print-string.js";
|
||||
import printNumber from "../../utils/print-number.js";
|
||||
import {
|
||||
isNumericLiteral,
|
||||
isSimpleNumber,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getStringWidth, getIndentSize } from "../../common/util.js";
|
||||
import getStringWidth from "../../utils/get-string-width.js";
|
||||
import getIndentSize from "../../utils/get-indent-size.js";
|
||||
import {
|
||||
join,
|
||||
hardline,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { hasNewlineInRange } from "../../common/util.js";
|
||||
import hasNewlineInRange from "../../utils/has-newline-in-range.js";
|
||||
import {
|
||||
isJsxElement,
|
||||
isCallExpression,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
isObjectType,
|
||||
getTypeScriptMappedTypeModifier,
|
||||
} from "../utils/index.js";
|
||||
import { createGroupIdMapper } from "../../common/util.js";
|
||||
import createGroupIdMapper from "../../utils/create-group-id-mapper.js";
|
||||
import {
|
||||
printTypeAnnotationProperty,
|
||||
shouldHugType,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { printDanglingComments } from "../../main/comments/print.js";
|
||||
import { hasNewlineInRange } from "../../common/util.js";
|
||||
import hasNewlineInRange from "../../utils/has-newline-in-range.js";
|
||||
import {
|
||||
join,
|
||||
line,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// TODO(azz): anything that imports from main shouldn't be in a `language-*` dir.
|
||||
import { printDanglingComments } from "../main/comments/print.js";
|
||||
import { hasNewline } from "../common/util.js";
|
||||
import hasNewline from "../utils/has-newline.js";
|
||||
import {
|
||||
join,
|
||||
line,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import isEs5IdentifierName from "@prettier/is-es5-identifier-name";
|
||||
import {
|
||||
hasNewline,
|
||||
isNonEmptyArray,
|
||||
isNextLineEmpty as isNextLineEmptyAfterIndex,
|
||||
getStringWidth,
|
||||
} from "../../common/util.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import isNextLineEmptyAfterIndex from "../../utils/is-next-line-empty.js";
|
||||
import getStringWidth from "../../utils/get-string-width.js";
|
||||
import { locStart, locEnd, hasSameLocStart } from "../loc.js";
|
||||
import getVisitorKeys from "../traverse/get-visitor-keys.js";
|
||||
import isBlockComment from "./is-block-comment.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import collapseWhiteSpace from "collapse-white-space";
|
||||
import { isFrontMatterNode } from "../common/util.js";
|
||||
import isFrontMatter from "../utils/front-matter/is-front-matter.js";
|
||||
import { startWithPragma } from "./pragma.js";
|
||||
|
||||
const ignoredProperties = new Set([
|
||||
@@ -63,7 +63,7 @@ function clean(ast, newObj, parent) {
|
||||
parent?.type === "root" &&
|
||||
parent.children.length > 0 &&
|
||||
(parent.children[0] === ast ||
|
||||
(isFrontMatterNode(parent.children[0]) && parent.children[1] === ast)) &&
|
||||
(isFrontMatter(parent.children[0]) && parent.children[1] === ast)) &&
|
||||
ast.type === "html" &&
|
||||
startWithPragma(ast.value)
|
||||
) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getMaxContinuousCount } from "../common/util.js";
|
||||
import getMaxContinuousCount from "../utils/get-max-continuous-count.js";
|
||||
import { hardline, markAsRoot } from "../document/builders.js";
|
||||
import { replaceEndOfLine } from "../document/utils.js";
|
||||
import printFrontMatter from "../utils/front-matter/print.js";
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import collapseWhiteSpace from "collapse-white-space";
|
||||
import {
|
||||
getMinNotPresentContinuousCount,
|
||||
getMaxContinuousCount,
|
||||
getStringWidth,
|
||||
} from "../common/util.js";
|
||||
import getMinNotPresentContinuousCount from "../utils/get-min-not-present-continuous-count.js";
|
||||
import getMaxContinuousCount from "../utils/get-max-continuous-count.js";
|
||||
import getStringWidth from "../utils/get-string-width.js";
|
||||
import {
|
||||
breakParent,
|
||||
join,
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
lineSuffix,
|
||||
} from "../document/builders.js";
|
||||
import { replaceEndOfLine } from "../document/utils.js";
|
||||
import { isPreviousLineEmpty } from "../common/util.js";
|
||||
import isPreviousLineEmpty from "../utils/is-previous-line-empty.js";
|
||||
import UnexpectedNodeError from "../utils/unexpected-node-error.js";
|
||||
import { insertPragma, isPragma } from "./pragma.js";
|
||||
import { locStart } from "./loc.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNonEmptyArray } from "../common/util.js";
|
||||
import isNonEmptyArray from "../utils/is-non-empty-array.js";
|
||||
|
||||
/**
|
||||
* @param {any} value
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import assert from "node:assert";
|
||||
import { hasNewline, isNonEmptyArray } from "../../common/util.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
import createGetVisitorKeysFunction from "../create-get-visitor-keys-function.js";
|
||||
import {
|
||||
addLeadingComment,
|
||||
|
||||
@@ -7,13 +7,11 @@ import {
|
||||
join,
|
||||
label,
|
||||
} from "../../document/builders.js";
|
||||
import {
|
||||
hasNewline,
|
||||
skipNewline,
|
||||
skipSpaces,
|
||||
isPreviousLineEmpty,
|
||||
isNonEmptyArray,
|
||||
} from "../../common/util.js";
|
||||
import hasNewline from "../../utils/has-newline.js";
|
||||
import skipNewline from "../../utils/skip-newline.js";
|
||||
import { skipSpaces } from "../../utils/skip.js";
|
||||
import isPreviousLineEmpty from "../../utils/is-previous-line-empty.js";
|
||||
import isNonEmptyArray from "../../utils/is-non-empty-array.js";
|
||||
|
||||
/**
|
||||
* @typedef {import("../../common/ast-path.js").default} AstPath
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { diffArrays } from "diff";
|
||||
|
||||
import { printDocToString as printDocToStringWithoutNormalizeOptions } from "../document/printer.js";
|
||||
import { printDocToDebug } from "../document/debug.js";
|
||||
import { getAlignmentSize } from "../common/util.js";
|
||||
import getAlignmentSize from "../utils/get-alignment-size.js";
|
||||
import {
|
||||
guessEndOfLine,
|
||||
convertEndOfLineToChars,
|
||||
|
||||
+1
-1
@@ -57,6 +57,6 @@ export {
|
||||
getSupportInfo,
|
||||
debugApis as __debug,
|
||||
};
|
||||
export * as util from "./common/util-shared.js";
|
||||
export * as util from "./utils/public.js";
|
||||
export * as doc from "./document/index.js";
|
||||
export { default as version } from "./main/version.evaluate.cjs";
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @param {string} description
|
||||
* @returns {(node: any) => symbol}
|
||||
*/
|
||||
function createGroupIdMapper(description) {
|
||||
const groupIds = new WeakMap();
|
||||
return function (node) {
|
||||
if (!groupIds.has(node)) {
|
||||
groupIds.set(node, Symbol(description));
|
||||
}
|
||||
return groupIds.get(node);
|
||||
};
|
||||
}
|
||||
|
||||
export default createGroupIdMapper;
|
||||
@@ -0,0 +1,5 @@
|
||||
function isFrontMatter(node) {
|
||||
return node?.type === "front-matter";
|
||||
}
|
||||
|
||||
export default isFrontMatter;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} tabWidth
|
||||
* @param {number=} startIndex
|
||||
* @returns {number}
|
||||
*/
|
||||
function getAlignmentSize(text, tabWidth, startIndex = 0) {
|
||||
let size = 0;
|
||||
for (let i = startIndex; i < text.length; ++i) {
|
||||
if (text[i] === "\t") {
|
||||
// Tabs behave in a way that they are aligned to the nearest
|
||||
// multiple of tabWidth:
|
||||
// 0 -> 4, 1 -> 4, 2 -> 4, 3 -> 4
|
||||
// 4 -> 8, 5 -> 8, 6 -> 8, 7 -> 8 ...
|
||||
size = size + tabWidth - (size % tabWidth);
|
||||
} else {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
export default getAlignmentSize;
|
||||
@@ -0,0 +1,22 @@
|
||||
import getAlignmentSize from "./get-alignment-size.js";
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {number} tabWidth
|
||||
* @returns {number}
|
||||
*/
|
||||
function getIndentSize(value, tabWidth) {
|
||||
const lastNewlineIndex = value.lastIndexOf("\n");
|
||||
/* c8 ignore next 3 */
|
||||
if (lastNewlineIndex === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getAlignmentSize(
|
||||
// All the leading whitespaces
|
||||
value.slice(lastNewlineIndex + 1).match(/^[\t ]*/)[0],
|
||||
tabWidth
|
||||
);
|
||||
}
|
||||
|
||||
export default getIndentSize;
|
||||
@@ -0,0 +1,24 @@
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {string} searchString
|
||||
* @returns {number}
|
||||
*/
|
||||
function getMaxContinuousCount(text, searchString) {
|
||||
const results = text.match(
|
||||
new RegExp(`(${escapeStringRegexp(searchString)})+`, "g")
|
||||
);
|
||||
|
||||
if (results === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return results.reduce(
|
||||
(maxCount, result) =>
|
||||
Math.max(maxCount, result.length / searchString.length),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
export default getMaxContinuousCount;
|
||||
@@ -0,0 +1,37 @@
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {string} searchString
|
||||
* @returns {number}
|
||||
*/
|
||||
function getMinNotPresentContinuousCount(text, searchString) {
|
||||
const matches = text.match(
|
||||
new RegExp(`(${escapeStringRegexp(searchString)})+`, "g")
|
||||
);
|
||||
|
||||
if (matches === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const countPresent = new Map();
|
||||
let max = 0;
|
||||
|
||||
for (const match of matches) {
|
||||
const count = match.length / searchString.length;
|
||||
countPresent.set(count, true);
|
||||
if (count > max) {
|
||||
max = count;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 1; i < max; i++) {
|
||||
if (!countPresent.get(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
export default getMinNotPresentContinuousCount;
|
||||
File renamed without changes.
@@ -0,0 +1,13 @@
|
||||
import getNextNonSpaceNonCommentCharacterIndex from "./get-next-non-space-non-comment-character-index.js";
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @returns {string}
|
||||
*/
|
||||
function getNextNonSpaceNonCommentCharacter(text, startIndex) {
|
||||
const index = getNextNonSpaceNonCommentCharacterIndex(text, startIndex);
|
||||
return index === false ? "" : text.charAt(index);
|
||||
}
|
||||
|
||||
export default getNextNonSpaceNonCommentCharacter;
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @typedef {'"' | "'"} Quote
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} rawContent
|
||||
* @param {Quote} preferredQuote
|
||||
* @returns {{ quote: Quote, regex: RegExp, escaped: string }}
|
||||
*/
|
||||
|
||||
function getPreferredQuote(rawContent, preferredQuote) {
|
||||
/** @type {{ quote: '"', regex: RegExp, escaped: """ }} */
|
||||
const double = { quote: '"', regex: /"/g, escaped: """ };
|
||||
/** @type {{ quote: "'", regex: RegExp, escaped: "'" }} */
|
||||
const single = { quote: "'", regex: /'/g, escaped: "'" };
|
||||
|
||||
const preferred = preferredQuote === "'" ? single : double;
|
||||
const alternate = preferred === single ? double : single;
|
||||
|
||||
let result = preferred;
|
||||
|
||||
// If `rawContent` contains at least one of the quote preferred for enclosing
|
||||
// the string, we might want to enclose with the alternate quote instead, to
|
||||
// minimize the number of escaped quotes.
|
||||
if (
|
||||
rawContent.includes(preferred.quote) ||
|
||||
rawContent.includes(alternate.quote)
|
||||
) {
|
||||
const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
|
||||
const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;
|
||||
|
||||
result = numPreferredQuotes > numAlternateQuotes ? alternate : preferred;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default getPreferredQuote;
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @param {number} endIndex
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasNewlineInRange(text, startIndex, endIndex) {
|
||||
for (let i = startIndex; i < endIndex; ++i) {
|
||||
if (text.charAt(i) === "\n") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default hasNewlineInRange;
|
||||
@@ -0,0 +1,22 @@
|
||||
import { skipSpaces } from "./skip.js";
|
||||
import skipNewline from "./skip-newline.js";
|
||||
|
||||
/** @typedef {import("./skip.js").SkipOptions} SkipOptions */
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @param {SkipOptions=} options
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasNewline(text, startIndex, options = {}) {
|
||||
const idx = skipSpaces(
|
||||
text,
|
||||
options.backwards ? startIndex - 1 : startIndex,
|
||||
options
|
||||
);
|
||||
const idx2 = skipNewline(text, idx, options);
|
||||
return idx !== idx2;
|
||||
}
|
||||
|
||||
export default hasNewline;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { skipSpaces } from "./skip.js";
|
||||
|
||||
/** @typedef {import("./skip.js").SkipOptions} SkipOptions */
|
||||
|
||||
// Not using, but it's public utils
|
||||
/* c8 ignore start */
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @param {SkipOptions=} options
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasSpaces(text, startIndex, options = {}) {
|
||||
const idx = skipSpaces(
|
||||
text,
|
||||
options.backwards ? startIndex - 1 : startIndex,
|
||||
options
|
||||
);
|
||||
return idx !== startIndex;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
|
||||
export default hasSpaces;
|
||||
@@ -0,0 +1,29 @@
|
||||
import skipNewline from "./skip-newline.js";
|
||||
import { skipSpaces, skipToLineEnd } from "./skip.js";
|
||||
import skipInlineComment from "./skip-inline-comment.js";
|
||||
import skipTrailingComment from "./skip-trailing-comment.js";
|
||||
import hasNewline from "./has-newline.js";
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isNextLineEmpty(text, startIndex) {
|
||||
/** @type {number | false} */
|
||||
let oldIdx = null;
|
||||
/** @type {number | false} */
|
||||
let idx = startIndex;
|
||||
while (idx !== oldIdx) {
|
||||
// We need to skip all the potential trailing inline comments
|
||||
oldIdx = idx;
|
||||
idx = skipToLineEnd(text, idx);
|
||||
idx = skipInlineComment(text, idx);
|
||||
idx = skipSpaces(text, idx);
|
||||
}
|
||||
idx = skipTrailingComment(text, idx);
|
||||
idx = skipNewline(text, idx);
|
||||
return idx !== false && hasNewline(text, idx);
|
||||
}
|
||||
|
||||
export default isNextLineEmpty;
|
||||
@@ -0,0 +1,20 @@
|
||||
import skipNewline from "./skip-newline.js";
|
||||
import { skipSpaces } from "./skip.js";
|
||||
|
||||
// Note: this function doesn't ignore leading comments unlike isNextLineEmpty
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} startIndex
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isPreviousLineEmpty(text, startIndex) {
|
||||
/** @type {number | false} */
|
||||
let idx = startIndex - 1;
|
||||
idx = skipSpaces(text, idx, { backwards: true });
|
||||
idx = skipNewline(text, idx, { backwards: true });
|
||||
idx = skipSpaces(text, idx, { backwards: true });
|
||||
const idx2 = skipNewline(text, idx, { backwards: true });
|
||||
return idx !== idx2;
|
||||
}
|
||||
|
||||
export default isPreviousLineEmpty;
|
||||
@@ -0,0 +1,47 @@
|
||||
/** @typedef {import("./get-preferred-quote.js").Quote} Quote */
|
||||
|
||||
/**
|
||||
* @param {string} rawText
|
||||
* @param {Quote} enclosingQuote
|
||||
* @param {boolean=} unescapeUnnecessaryEscapes
|
||||
* @returns {string}
|
||||
*/
|
||||
function makeString(rawText, enclosingQuote, unescapeUnnecessaryEscapes) {
|
||||
const otherQuote = enclosingQuote === '"' ? "'" : '"';
|
||||
|
||||
// Matches _any_ escape and unescaped quotes (both single and double).
|
||||
const regex = /\\(.)|(["'])/gs;
|
||||
|
||||
// Escape and unescape single and double quotes as needed to be able to
|
||||
// enclose `rawText` with `enclosingQuote`.
|
||||
const raw = rawText.replaceAll(regex, (match, escaped, quote) => {
|
||||
// If we matched an escape, and the escaped character is a quote of the
|
||||
// other type than we intend to enclose the string with, there's no need for
|
||||
// it to be escaped, so return it _without_ the backslash.
|
||||
if (escaped === otherQuote) {
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// If we matched an unescaped quote and it is of the _same_ type as we
|
||||
// intend to enclose the string with, it must be escaped, so return it with
|
||||
// a backslash.
|
||||
if (quote === enclosingQuote) {
|
||||
return "\\" + quote;
|
||||
}
|
||||
|
||||
if (quote) {
|
||||
return quote;
|
||||
}
|
||||
|
||||
// Unescape any unnecessarily escaped character.
|
||||
// Adapted from https://github.com/eslint/eslint/blob/de0b4ad7bd820ade41b1f606008bea68683dc11a/lib/rules/no-useless-escape.js#L27
|
||||
return unescapeUnnecessaryEscapes &&
|
||||
/^[^\n\r"'0-7\\bfnrt-vx\u2028\u2029]$/.test(escaped)
|
||||
? escaped
|
||||
: "\\" + escaped;
|
||||
});
|
||||
|
||||
return enclosingQuote + raw + enclosingQuote;
|
||||
}
|
||||
|
||||
export default makeString;
|
||||
@@ -0,0 +1,18 @@
|
||||
function printNumber(rawNumber) {
|
||||
return (
|
||||
rawNumber
|
||||
.toLowerCase()
|
||||
// Remove unnecessary plus and zeroes from scientific notation.
|
||||
.replace(/^([+-]?[\d.]+e)(?:\+|(-))?0*(?=\d)/, "$1$2")
|
||||
// Remove unnecessary scientific notation (1e0).
|
||||
.replace(/^([+-]?[\d.]+)e[+-]?0+$/, "$1")
|
||||
// Make sure numbers always start with a digit.
|
||||
.replace(/^([+-])?\./, "$10.")
|
||||
// Remove extraneous trailing decimal zeroes.
|
||||
.replace(/(\.\d+?)0+(?=e|$)/, "$1")
|
||||
// Remove trailing dot.
|
||||
.replace(/\.(?=e|$)/, "")
|
||||
);
|
||||
}
|
||||
|
||||
export default printNumber;
|
||||
@@ -0,0 +1,38 @@
|
||||
import getPreferredQuote from "./get-preferred-quote.js";
|
||||
import makeString from "./make-string.js";
|
||||
|
||||
/** @typedef {import("./get-preferred-quote.js").Quote} Quote */
|
||||
|
||||
function printString(raw, options) {
|
||||
// `rawContent` is the string exactly like it appeared in the input source
|
||||
// code, without its enclosing quotes.
|
||||
const rawContent = raw.slice(1, -1);
|
||||
|
||||
/** @type {Quote} */
|
||||
const enclosingQuote =
|
||||
options.parser === "json" ||
|
||||
(options.parser === "json5" &&
|
||||
options.quoteProps === "preserve" &&
|
||||
!options.singleQuote)
|
||||
? '"'
|
||||
: options.__isInHtmlAttribute
|
||||
? "'"
|
||||
: getPreferredQuote(rawContent, options.singleQuote ? "'" : '"').quote;
|
||||
|
||||
// It might sound unnecessary to use `makeString` even if the string already
|
||||
// is enclosed with `enclosingQuote`, but it isn't. The string could contain
|
||||
// unnecessary escapes (such as in `"\'"`). Always using `makeString` makes
|
||||
// sure that we consistently output the minimum amount of escaped quotes.
|
||||
return makeString(
|
||||
rawContent,
|
||||
enclosingQuote,
|
||||
!(
|
||||
options.parser === "css" ||
|
||||
options.parser === "less" ||
|
||||
options.parser === "scss" ||
|
||||
options.__embeddedInHtml
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default printString;
|
||||
@@ -1,8 +1,6 @@
|
||||
import {
|
||||
getNextNonSpaceNonCommentCharacterIndex as getNextNonSpaceNonCommentCharacterIndexWithStartIndex,
|
||||
isPreviousLineEmpty as isPreviousLineEmptyWithStartIndex,
|
||||
isNextLineEmpty as isNextLineEmptyAfterIndex,
|
||||
} from "./util.js";
|
||||
import getNextNonSpaceNonCommentCharacterIndexWithStartIndex from "./get-next-non-space-non-comment-character-index.js";
|
||||
import isPreviousLineEmptyWithStartIndex from "./is-previous-line-empty.js";
|
||||
import isNextLineEmptyAfterIndex from "./is-next-line-empty.js";
|
||||
|
||||
// Legacy version of `getNextNonSpaceNonCommentCharacterIndex`
|
||||
/**
|
||||
@@ -84,29 +82,30 @@ export function isNextLineEmpty(text, startIndex) {
|
||||
legacyIsNextLineEmpty(...arguments);
|
||||
}
|
||||
|
||||
export { default as getMaxContinuousCount } from "./get-max-continuous-count.js";
|
||||
export { default as getStringWidth } from "./get-string-width.js";
|
||||
export { default as getAlignmentSize } from "./get-alignment-size.js";
|
||||
export { default as getIndentSize } from "./get-indent-size.js";
|
||||
export { default as skipNewline } from "./skip-newline.js";
|
||||
export { default as skipInlineComment } from "./skip-inline-comment.js";
|
||||
export { default as skipTrailingComment } from "./skip-trailing-comment.js";
|
||||
export { default as hasNewline } from "./has-newline.js";
|
||||
export { default as hasNewlineInRange } from "./has-newline-in-range.js";
|
||||
export { default as hasSpaces } from "./has-spaces.js";
|
||||
export { default as getNextNonSpaceNonCommentCharacter } from "./get-next-non-space-non-comment-character.js";
|
||||
export { default as makeString } from "./make-string.js";
|
||||
export {
|
||||
getMaxContinuousCount,
|
||||
getStringWidth,
|
||||
getAlignmentSize,
|
||||
getIndentSize,
|
||||
skip,
|
||||
skipWhitespace,
|
||||
skipSpaces,
|
||||
skipNewline,
|
||||
skipToLineEnd,
|
||||
skipEverythingButNewLine,
|
||||
skipInlineComment,
|
||||
skipTrailingComment,
|
||||
hasNewline,
|
||||
hasNewlineInRange,
|
||||
hasSpaces,
|
||||
getNextNonSpaceNonCommentCharacter,
|
||||
makeString,
|
||||
// Remove this in v4
|
||||
isNextLineEmpty as isNextLineEmptyAfterIndex,
|
||||
} from "./util.js";
|
||||
} from "./skip.js";
|
||||
export {
|
||||
addLeadingComment,
|
||||
addDanglingComment,
|
||||
addTrailingComment,
|
||||
} from "../main/comments/utils.js";
|
||||
|
||||
// TODO: Remove this in v4
|
||||
export { isNextLineEmptyAfterIndex };
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user