Files
test-repo/src/language-css/parser-postcss.js
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

732 lines
19 KiB
JavaScript
Raw Normal View History

2022-02-21 14:22:51 +08:00
import createError from "../common/parser-create-error.js";
import parseFrontMatter from "../utils/front-matter/parse.js";
import { hasPragma } from "./pragma.js";
import { locStart, locEnd } from "./loc.js";
import { calculateLoc, replaceQuotesInInlineComments } from "./loc.js";
import hasSCSSInterpolation from "./utils/has-scss-interpolation.js";
import hasStringOrFunction from "./utils/has-string-or-function.js";
import isSCSSNestedPropertyNode from "./utils/is-scss-nested-property-node.js";
import isSCSSVariable from "./utils/is-scss-variable.js";
import stringifyNode from "./utils/stringify-node.js";
import isModuleRuleName from "./utils/is-module-rule-name.js";
2017-05-28 21:06:09 -07:00
2020-07-03 03:24:27 +02:00
const getHighestAncestor = (node) => {
while (node.parent) {
node = node.parent;
}
return node;
};
2022-08-15 22:30:46 +09:00
async function parseValueNode(valueNode, options) {
2020-07-03 03:24:27 +02:00
const { nodes } = valueNode;
2017-05-28 21:06:09 -07:00
let parenGroup = {
open: null,
close: null,
groups: [],
type: "paren_group",
};
const parenGroupStack = [parenGroup];
const rootParenGroup = parenGroup;
let commaGroup = {
groups: [],
type: "comma_group",
};
const commaGroupStack = [commaGroup];
for (let i = 0; i < nodes.length; ++i) {
2017-06-02 23:11:05 +02:00
const node = nodes[i];
if (
2020-11-09 16:47:12 +08:00
options.parser === "scss" &&
node.type === "number" &&
node.unit === ".." &&
2022-09-18 17:50:14 +08:00
node.value.endsWith(".")
) {
// Work around postcss bug parsing `50...` as `50.` with unit `..`
// Set the unit to `...` to "accidentally" have arbitrary arguments work in the same way that cases where the node already had a unit work.
// For example, 50px... is parsed as `50` with unit `px...` already by postcss-values-parser.
node.value = node.value.slice(0, -1);
node.unit = "...";
}
2020-07-03 03:24:27 +02:00
if (node.type === "func" && node.value === "selector") {
node.group.groups = [
2022-08-15 22:30:46 +09:00
await parseSelector(
2020-07-03 03:24:27 +02:00
getHighestAncestor(valueNode).text.slice(
node.group.open.sourceIndex + 1,
node.group.close.sourceIndex
)
),
];
}
if (node.type === "func" && node.value === "url") {
const groups = (node.group && node.group.groups) || [];
// Create a view with any top-level comma groups flattened.
let groupList = [];
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
if (group.type === "comma_group") {
2021-01-26 09:46:14 +08:00
groupList = [...groupList, ...group.groups];
} else {
groupList.push(group);
}
}
// Stringify if the value parser can't handle the content.
if (
hasSCSSInterpolation(groupList) ||
2020-11-09 16:47:12 +08:00
(!hasStringOrFunction(groupList) &&
!isSCSSVariable(groupList[0], options))
) {
const stringifiedContent = stringifyNode({
groups: node.group.groups,
});
node.group.groups = [stringifiedContent.trim()];
}
}
2017-06-02 23:11:05 +02:00
if (node.type === "paren" && node.value === "(") {
2017-05-28 21:06:09 -07:00
parenGroup = {
2017-06-02 23:11:05 +02:00
open: node,
2017-05-28 21:06:09 -07:00
close: null,
groups: [],
type: "paren_group",
};
parenGroupStack.push(parenGroup);
commaGroup = {
groups: [],
type: "comma_group",
};
commaGroupStack.push(commaGroup);
2017-06-02 23:11:05 +02:00
} else if (node.type === "paren" && node.value === ")") {
if (commaGroup.groups.length > 0) {
2017-05-28 21:06:09 -07:00
parenGroup.groups.push(commaGroup);
}
2017-06-02 23:11:05 +02:00
parenGroup.close = node;
2017-05-28 21:06:09 -07:00
2020-08-21 09:43:24 +08:00
/* istanbul ignore next */
2017-05-28 21:06:09 -07:00
if (commaGroupStack.length === 1) {
throw new Error("Unbalanced parenthesis");
}
commaGroupStack.pop();
2022-09-18 17:50:14 +08:00
commaGroup = commaGroupStack.at(-1);
2017-05-28 21:06:09 -07:00
commaGroup.groups.push(parenGroup);
parenGroupStack.pop();
2022-09-18 17:50:14 +08:00
parenGroup = parenGroupStack.at(-1);
2017-06-02 23:11:05 +02:00
} else if (node.type === "comma") {
2017-05-28 21:06:09 -07:00
parenGroup.groups.push(commaGroup);
commaGroup = {
groups: [],
type: "comma_group",
};
commaGroupStack[commaGroupStack.length - 1] = commaGroup;
} else {
2017-06-02 23:11:05 +02:00
commaGroup.groups.push(node);
2017-05-28 21:06:09 -07:00
}
}
if (commaGroup.groups.length > 0) {
parenGroup.groups.push(commaGroup);
}
return rootParenGroup;
}
function flattenGroups(node) {
if (
node.type === "paren_group" &&
!node.open &&
!node.close &&
node.groups.length === 1
) {
return flattenGroups(node.groups[0]);
}
if (node.type === "comma_group" && node.groups.length === 1) {
return flattenGroups(node.groups[0]);
}
if (node.type === "paren_group" || node.type === "comma_group") {
return { ...node, groups: node.groups.map(flattenGroups) };
2017-05-28 21:06:09 -07:00
}
return node;
}
2020-07-03 03:24:27 +02:00
function addTypePrefix(node, prefix, skipPrefix) {
2017-05-28 21:06:09 -07:00
if (node && typeof node === "object") {
delete node.parent;
for (const key in node) {
2020-07-03 03:24:27 +02:00
addTypePrefix(node[key], prefix, skipPrefix);
if (
key === "type" &&
typeof node[key] === "string" &&
!node[key].startsWith(prefix) &&
(!skipPrefix || !skipPrefix.test(node[key]))
) {
node[key] = prefix + node[key];
2017-05-28 21:06:09 -07:00
}
}
}
return node;
}
function addMissingType(node) {
if (node && typeof node === "object") {
delete node.parent;
for (const key in node) {
addMissingType(node[key]);
}
if (!Array.isArray(node) && node.value && !node.type) {
node.type = "unknown";
}
}
return node;
}
2022-08-15 22:30:46 +09:00
async function parseNestedValue(node, options) {
2017-05-28 21:06:09 -07:00
if (node && typeof node === "object") {
for (const key in node) {
2020-07-03 03:24:27 +02:00
if (key !== "parent") {
2022-08-15 22:30:46 +09:00
await parseNestedValue(node[key], options);
2020-07-03 03:24:27 +02:00
if (key === "nodes") {
2022-08-15 22:30:46 +09:00
node.group = flattenGroups(await parseValueNode(node, options));
2020-07-03 03:24:27 +02:00
delete node[key];
}
2017-05-28 21:06:09 -07:00
}
}
2020-07-03 03:24:27 +02:00
delete node.parent;
2017-05-28 21:06:09 -07:00
}
return node;
}
2022-08-15 22:30:46 +09:00
async function parseValue(value, options) {
const Parser = await import("postcss-values-parser/lib/parser.js").then(
(m) => m.default
);
const valueParser = (source, options) => new Parser(source, options);
2022-03-28 09:41:08 +08:00
2018-05-15 00:00:45 +03:00
let result = null;
try {
result = valueParser(value, { loose: true }).parse();
} catch {
2018-05-15 00:00:45 +03:00
return {
type: "value-unknown",
2020-01-14 19:25:24 +08:00
value,
2018-05-15 00:00:45 +03:00
};
}
result.text = value;
2022-08-15 22:30:46 +09:00
const parsedResult = await parseNestedValue(result, options);
2018-05-15 00:00:45 +03:00
2020-07-03 03:24:27 +02:00
return addTypePrefix(parsedResult, "value-", /^selector-/);
2017-05-28 21:06:09 -07:00
}
2022-08-15 22:30:46 +09:00
async function parseSelector(selector) {
2018-05-15 00:00:45 +03:00
// If there's a comment inside of a selector, the parser tries to parse
// the content of the comment as selectors which turns it into complete
// garbage. Better to print the whole selector as-is and not try to parse
// and reformat it.
2020-03-10 07:14:34 +08:00
if (/\/\/|\/\*/.test(selector)) {
2018-05-15 00:00:45 +03:00
return {
type: "selector-unknown",
2020-03-10 07:14:34 +08:00
value: selector.trim(),
2018-05-15 00:00:45 +03:00
};
}
2022-08-15 22:30:46 +09:00
const SelectorProcessor = await import(
"postcss-selector-parser/dist/processor.js"
).then((m) => m.default);
const selectorParser = (processor) => new SelectorProcessor(processor);
2022-03-28 09:41:08 +08:00
2018-05-15 00:00:45 +03:00
let result = null;
try {
selectorParser((result_) => {
result = result_;
}).process(selector);
} catch {
2018-05-15 00:00:45 +03:00
// Fail silently. It's better to print it as is than to try and parse it
// Note: A common failure is for SCSS nested properties. `background:
// none { color: red; }` is parsed as a NestedDeclaration by
// postcss-scss, while `background: { color: red; }` is parsed as a Rule
// with a selector ending with a colon. See:
// https://github.com/postcss/postcss-scss/issues/39
return {
type: "selector-unknown",
value: selector,
};
}
return addTypePrefix(result, "selector-");
}
2022-08-15 22:30:46 +09:00
async function parseMediaQuery(params) {
const mediaParser = await import("postcss-media-query-parser").then(
(m) => m.default.default
);
2022-03-28 09:41:08 +08:00
2018-05-15 00:00:45 +03:00
let result = null;
try {
2022-08-15 22:30:46 +09:00
result = mediaParser(params);
} catch {
2018-05-15 00:00:45 +03:00
// Ignore bad media queries
2020-08-21 09:43:24 +08:00
/* istanbul ignore next */
2018-05-15 00:00:45 +03:00
return {
type: "selector-unknown",
value: params,
};
}
return addTypePrefix(addMissingType(result), "media-");
2017-05-28 21:06:09 -07:00
}
2021-12-07 14:15:03 +08:00
const DEFAULT_SCSS_DIRECTIVE = /(\s*)(!default).*$/;
const GLOBAL_SCSS_DIRECTIVE = /(\s*)(!global).*$/;
2018-01-12 14:12:02 +03:00
2022-08-15 22:30:46 +09:00
async function parseNestedCSS(node, options) {
2017-05-28 21:06:09 -07:00
if (node && typeof node === "object") {
delete node.parent;
2017-05-28 21:06:09 -07:00
for (const key in node) {
2022-08-15 22:30:46 +09:00
await parseNestedCSS(node[key], options);
2017-05-28 21:06:09 -07:00
}
2018-04-13 22:12:59 +03:00
if (!node.type) {
return node;
}
2017-05-28 21:06:09 -07:00
2020-08-21 09:43:24 +08:00
/* istanbul ignore next */
2018-04-13 22:12:59 +03:00
if (!node.raws) {
node.raws = {};
}
2020-11-09 16:47:12 +08:00
// Custom properties looks like declarations
if (
node.type === "css-decl" &&
typeof node.prop === "string" &&
node.prop.startsWith("--") &&
typeof node.value === "string" &&
node.value.startsWith("{")
) {
let rules;
if (node.value.trimEnd().endsWith("}")) {
2020-11-09 16:47:12 +08:00
const textBefore = options.originalText.slice(
0,
node.source.start.offset
);
const nodeText =
"a".repeat(node.prop.length) +
options.originalText.slice(
node.source.start.offset + node.prop.length,
node.source.end.offset + 1
);
const fakeContent = textBefore.replace(/[^\n]/g, " ") + nodeText;
let parse;
if (options.parser === "scss") {
parse = parseScss;
} else if (options.parser === "less") {
parse = parseLess;
} else {
parse = parseCss;
}
let ast;
try {
ast = await parse(fakeContent, { ...options });
2021-03-08 18:35:48 +08:00
} catch {
2020-11-09 16:47:12 +08:00
// noop
}
if (
ast &&
ast.nodes &&
ast.nodes.length === 1 &&
ast.nodes[0].type === "css-rule"
) {
rules = ast.nodes[0].nodes;
}
}
if (rules) {
node.value = {
type: "css-rule",
nodes: rules,
};
} else {
node.value = {
type: "value-unknown",
value: node.raws.value.raw,
};
}
return node;
}
2018-04-13 22:12:59 +03:00
let selector = "";
if (typeof node.selector === "string") {
2018-05-30 23:22:18 +03:00
selector = node.raws.selector
? node.raws.selector.scss ?? node.raws.selector.raw
2018-05-30 23:22:18 +03:00
: node.selector;
2018-04-13 22:12:59 +03:00
if (node.raws.between && node.raws.between.trim().length > 0) {
2018-02-07 13:20:13 +03:00
selector += node.raws.between;
}
2018-04-13 22:12:59 +03:00
node.raws.selector = selector;
}
let value = "";
if (typeof node.value === "string") {
2018-05-30 23:22:18 +03:00
value = node.raws.value
? node.raws.value.scss ?? node.raws.value.raw
2018-05-30 23:22:18 +03:00
: node.value;
2018-04-13 22:12:59 +03:00
value = value.trim();
2020-03-20 19:09:07 +03:00
node.raws.value = value;
2018-04-13 22:12:59 +03:00
}
let params = "";
if (typeof node.params === "string") {
2018-05-30 23:22:18 +03:00
params = node.raws.params
? node.raws.params.scss ?? node.raws.params.raw
2018-05-30 23:22:18 +03:00
: node.params;
2018-04-13 22:12:59 +03:00
if (node.raws.afterName && node.raws.afterName.trim().length > 0) {
params = node.raws.afterName + params;
}
if (node.raws.between && node.raws.between.trim().length > 0) {
params = params + node.raws.between;
}
params = params.trim();
node.raws.params = params;
}
// Ignore LESS mixin declaration
if (selector.trim().length > 0) {
2020-08-21 09:43:24 +08:00
// TODO: confirm this code is dead
/* istanbul ignore next */
if (selector.startsWith("@") && selector.endsWith(":")) {
return node;
}
2020-08-21 09:43:24 +08:00
// TODO: confirm this code is dead
/* istanbul ignore next */
2018-04-13 22:12:59 +03:00
// Ignore LESS mixins
if (node.mixin) {
2022-08-15 22:30:46 +09:00
node.selector = await parseValue(selector, options);
2018-04-13 22:12:59 +03:00
return node;
}
2018-05-15 00:00:45 +03:00
// Check on SCSS nested property
2020-11-09 16:47:12 +08:00
if (isSCSSNestedPropertyNode(node, options)) {
2018-05-15 00:00:45 +03:00
node.isSCSSNesterProperty = true;
2017-05-28 21:06:09 -07:00
}
2022-08-15 22:30:46 +09:00
node.selector = await parseSelector(selector);
2018-05-15 00:00:45 +03:00
return node;
2017-05-28 21:06:09 -07:00
}
2018-06-25 12:57:41 +03:00
if (value.length > 0) {
2018-05-15 00:00:45 +03:00
const defaultSCSSDirectiveIndex = value.match(DEFAULT_SCSS_DIRECTIVE);
2018-02-06 18:09:42 +03:00
2018-05-15 00:00:45 +03:00
if (defaultSCSSDirectiveIndex) {
2020-01-23 20:15:28 +08:00
value = value.slice(0, defaultSCSSDirectiveIndex.index);
2018-05-15 00:00:45 +03:00
node.scssDefault = true;
2018-02-06 18:09:42 +03:00
2018-05-15 00:00:45 +03:00
if (defaultSCSSDirectiveIndex[0].trim() !== "!default") {
node.raws.scssDefault = defaultSCSSDirectiveIndex[0];
2018-01-12 14:12:02 +03:00
}
2017-05-28 21:06:09 -07:00
}
2018-05-15 00:00:45 +03:00
const globalSCSSDirectiveIndex = value.match(GLOBAL_SCSS_DIRECTIVE);
if (globalSCSSDirectiveIndex) {
2020-01-23 20:15:28 +08:00
value = value.slice(0, globalSCSSDirectiveIndex.index);
2018-05-15 00:00:45 +03:00
node.scssGlobal = true;
if (globalSCSSDirectiveIndex[0].trim() !== "!global") {
node.raws.scssGlobal = globalSCSSDirectiveIndex[0];
}
}
if (value.startsWith("progid:")) {
return {
type: "value-unknown",
2020-01-14 19:25:24 +08:00
value,
2018-05-15 00:00:45 +03:00
};
}
2022-08-15 22:30:46 +09:00
node.value = await parseValue(value, options);
2017-05-28 21:06:09 -07:00
}
2020-04-08 23:02:13 +08:00
if (
2020-11-09 16:47:12 +08:00
options.parser === "less" &&
2020-04-08 23:02:13 +08:00
node.type === "css-decl" &&
value.startsWith("extend(")
) {
2020-04-30 16:58:21 +08:00
// extend is missing
if (!node.extend) {
node.extend = node.raws.between === ":";
}
// `:extend()` is parsed as value
if (node.extend && !node.selector) {
delete node.value;
2022-08-15 22:30:46 +09:00
node.selector = await parseSelector(value.slice("extend(".length, -1));
2020-04-30 16:58:21 +08:00
}
2020-04-08 23:02:13 +08:00
}
2020-03-10 07:14:34 +08:00
if (node.type === "css-atrule") {
2020-11-09 16:47:12 +08:00
if (options.parser === "less") {
2020-03-10 07:14:34 +08:00
// mixin
if (node.mixin) {
const source =
node.raws.identifier +
node.name +
node.raws.afterName +
node.raws.params;
2022-08-15 22:30:46 +09:00
node.selector = await parseSelector(source);
2020-03-10 07:14:34 +08:00
delete node.params;
return node;
}
// function
if (node.function) {
return node;
}
}
// only css support custom-selector
if (options.parser === "css" && node.name === "custom-selector") {
2021-12-07 14:15:03 +08:00
const customSelector = node.params.match(/:--\S+\s+/)[0].trim();
2020-03-10 07:14:34 +08:00
node.customSelector = customSelector;
2022-08-15 22:30:46 +09:00
node.selector = await parseSelector(
2020-03-10 07:14:34 +08:00
node.params.slice(customSelector.length).trim()
);
delete node.params;
return node;
}
2020-11-09 16:47:12 +08:00
if (options.parser === "less") {
2020-10-12 04:16:36 +03:00
// postcss-less doesn't recognize variables in some cases.
// `@color: blue;` is recognized fine, but the cases below aren't:
// `@color:blue;`
2020-03-10 07:14:34 +08:00
if (node.name.includes(":") && !node.params) {
node.variable = true;
const parts = node.name.split(":");
node.name = parts[0];
2022-08-15 22:30:46 +09:00
node.value = await parseValue(parts.slice(1).join(":"), options);
2020-03-10 07:14:34 +08:00
}
2020-10-12 04:16:36 +03:00
// `@color :blue;`
2020-03-10 07:14:34 +08:00
if (
!["page", "nest", "keyframes"].includes(node.name) &&
2020-03-10 07:14:34 +08:00
node.params &&
node.params[0] === ":"
) {
node.variable = true;
2022-08-15 22:30:46 +09:00
node.value = await parseValue(node.params.slice(1), options);
2020-10-12 04:16:36 +03:00
node.raws.afterName += ":";
2020-03-10 07:14:34 +08:00
}
// Less variable
if (node.variable) {
delete node.params;
return node;
}
}
}
2018-04-13 22:12:59 +03:00
if (node.type === "css-atrule" && params.length > 0) {
2020-01-14 23:30:18 +08:00
const { name } = node;
2018-02-22 12:49:03 +03:00
const lowercasedName = node.name.toLowerCase();
2018-02-21 21:36:09 +03:00
2018-02-22 12:49:03 +03:00
if (name === "warn" || name === "error") {
node.params = {
type: "media-unknown",
2018-02-21 21:36:09 +03:00
value: params,
};
return node;
}
2018-02-22 12:49:03 +03:00
if (name === "extend" || name === "nest") {
2022-08-15 22:30:46 +09:00
node.selector = await parseSelector(params);
delete node.params;
return node;
}
2018-02-22 12:49:03 +03:00
if (name === "at-root") {
if (/^\(\s*(?:without|with)\s*:.+\)$/s.test(params)) {
2022-08-15 22:30:46 +09:00
node.params = await parseValue(params, options);
} else {
2022-08-15 22:30:46 +09:00
node.selector = await parseSelector(params);
delete node.params;
}
return node;
}
if (isModuleRuleName(lowercasedName)) {
2020-03-10 07:14:34 +08:00
node.import = true;
delete node.filename;
2022-08-15 22:30:46 +09:00
node.params = await parseValue(params, options);
return node;
}
if (
2018-02-22 12:49:03 +03:00
[
"namespace",
"supports",
2018-02-22 12:49:03 +03:00
"if",
"else",
"for",
"each",
"while",
"debug",
"mixin",
"include",
"function",
"return",
"define-mixin",
"add-mixin",
2019-11-17 18:06:14 +08:00
].includes(name)
) {
// Remove unnecessary spaces in SCSS variable arguments
2021-12-06 21:31:51 +08:00
// Move spaces after the `...`, so we can keep the range correct
params = params.replace(/(\$\S+?)(\s+)?\.{3}/, "$1...$2");
// Remove unnecessary spaces before SCSS control, mixin and function directives
2021-12-06 21:31:51 +08:00
// Move spaces after the `(`, so we can keep the range correct
params = params.replace(/^(?!if)(\S+)(\s+)\(/, "$1($2");
2022-08-15 22:30:46 +09:00
node.value = await parseValue(params, options);
delete node.params;
return node;
}
2019-11-17 18:06:14 +08:00
if (["media", "custom-media"].includes(lowercasedName)) {
2018-02-22 12:49:03 +03:00
if (params.includes("#{")) {
// Workaround for media at rule with scss interpolation
return {
type: "media-unknown",
value: params,
};
}
2022-08-15 22:30:46 +09:00
node.params = await parseMediaQuery(params);
2018-02-22 12:49:03 +03:00
return node;
}
node.params = params;
return node;
2017-05-28 21:06:09 -07:00
}
}
2017-05-28 21:06:09 -07:00
return node;
}
2022-08-15 22:30:46 +09:00
async function parseWithParser(parse, text, options) {
const parsed = parseFrontMatter(text);
const { frontMatter } = parsed;
2018-05-14 22:17:15 -03:00
text = parsed.content;
2017-05-28 21:06:09 -07:00
let result;
2017-05-28 21:06:09 -07:00
try {
2021-03-09 13:02:12 +08:00
result = parse(text, {
// Prevent file access https://github.com/postcss/postcss/blob/4f4e2932fc97e2c117e1a4b15f0272ed551ed59d/lib/previous-map.js#L18
map: false,
});
2020-10-16 10:39:05 +08:00
} catch (error) {
const { name, reason, line, column } = error;
2020-08-21 09:43:24 +08:00
/* istanbul ignore next */
2020-10-16 10:39:05 +08:00
if (typeof line !== "number") {
throw error;
2017-05-28 21:06:09 -07:00
}
2022-08-30 10:27:11 +08:00
throw createError(`${name}: ${reason}`, {
loc: { start: { line, column } },
cause: error,
});
2017-05-28 21:06:09 -07:00
}
2018-01-24 19:44:09 +03:00
2020-11-09 16:47:12 +08:00
options.originalText = text;
2022-08-15 22:30:46 +09:00
result = await parseNestedCSS(addTypePrefix(result, "css-"), options);
2018-05-14 22:17:15 -03:00
2020-03-20 19:09:07 +03:00
calculateLoc(result, text);
if (frontMatter) {
frontMatter.source = {
startOffset: 0,
endOffset: frontMatter.raw.length,
};
2022-08-30 11:00:12 +08:00
result.frontMatter = frontMatter;
2018-01-24 19:44:09 +03:00
}
2018-05-14 22:17:15 -03:00
return result;
2017-05-28 21:06:09 -07:00
}
async function parseCss(text, options = {}) {
2022-08-15 22:30:46 +09:00
const parse = await import("postcss/lib/parse").then((m) => m.default);
return parseWithParser(parse, text, options);
2020-04-03 12:41:48 +08:00
}
async function parseLess(text, options = {}) {
2022-08-15 22:30:46 +09:00
const less = await import("postcss-less");
2022-03-28 09:41:08 +08:00
2020-04-03 12:41:48 +08:00
return parseWithParser(
2020-03-20 19:09:07 +03:00
// Workaround for https://github.com/shellscape/postcss-less/issues/145
// See comments for `replaceQuotesInInlineComments` in `loc.js`.
2022-02-21 14:22:51 +08:00
(text) => less.parse(replaceQuotesInInlineComments(text)),
2020-04-03 12:41:48 +08:00
text,
options
);
2017-05-28 21:49:41 -07:00
}
async function parseScss(text, options = {}) {
const { default: parse } = await import("postcss-scss/lib/scss-parse");
return parseWithParser(parse, text, options);
2017-05-28 21:06:09 -07:00
}
2020-04-03 12:41:48 +08:00
const postCssParser = {
2018-05-24 15:30:45 -03:00
astFormat: "postcss",
2018-06-14 09:51:18 +08:00
hasPragma,
locStart,
locEnd,
2018-05-24 15:30:45 -03:00
};
// Export as a plugin so we can reuse the same bundle for UMD loading
2022-02-21 14:22:51 +08:00
const postcssParser = {
2018-05-24 15:30:45 -03:00
parsers: {
2020-04-03 12:41:48 +08:00
css: {
...postCssParser,
parse: parseCss,
},
less: {
...postCssParser,
parse: parseLess,
},
scss: {
...postCssParser,
parse: parseScss,
},
2018-05-24 15:30:45 -03:00
},
};
2022-02-21 14:22:51 +08:00
export default postcssParser;