unocss-preset-weapp
Version:
the unocss preset for wechat miniprogram (uniapp, taro)
175 lines (168 loc) • 6.05 kB
JavaScript
;
const pluginutils = require('@rollup/pluginutils');
const utils$1 = require('unplugin-transform-class/utils');
const utils = require('unplugin-attributify-to-class/utils');
const variantsRE = /^(?!.*\[[^:]+:.+\]$)((?:.+:)?!?)(.*)$/;
const elementRE = /(<\w[\w:.$-]*\s)((?:'[^>']*'|"[^>"]*"|`[^>`]*`|\{[^>}]*\}|[^>]*?)*)/g;
const valuedAttributeRE = /(\?|(?!\d|-{2}|-\d)[\w\u00A0-\uFFFF-:%]+)(?:=("[^"]*|'[^']*))?/g;
const splitterRE = /[\s'"`;>]+/;
function autocompleteExtractorAttributify(options) {
return {
name: "weapp-attributify",
extract: ({ content, cursor }) => {
const matchedElements = content.matchAll(elementRE);
let attrs;
let elPos = 0;
for (const match of matchedElements) {
const [, prefix, content2] = match;
const currentPos2 = match.index + prefix.length;
if (cursor > currentPos2 && cursor <= currentPos2 + content2.length) {
elPos = currentPos2;
attrs = content2;
break;
}
}
if (!attrs)
return null;
const matchedAttributes = attrs.matchAll(valuedAttributeRE);
let attrsPos = 0;
let attrName;
let attrValues;
for (const match of matchedAttributes) {
const [matched, name, rawValues] = match;
const currentPos2 = elPos + match.index;
if (cursor > currentPos2 && cursor <= currentPos2 + matched.length) {
attrsPos = currentPos2;
attrName = name;
attrValues = rawValues?.slice(1);
break;
}
}
if (!attrName)
return null;
if (attrName === "class" || attrName === "className" || attrName === ":class")
return null;
const hasPrefix = !!options?.prefix && attrName.startsWith(options.prefix);
if (options?.prefixedOnly && !hasPrefix)
return null;
const attrNameWithoutPrefix = hasPrefix ? attrName.slice(options.prefix.length) : attrName;
if (attrValues === void 0) {
return {
extracted: attrNameWithoutPrefix,
resolveReplacement(suggestion) {
const startOffset = hasPrefix ? options.prefix.length : 0;
return {
start: attrsPos + startOffset,
end: attrsPos + attrName.length,
replacement: suggestion
};
}
};
}
const attrValuePos = attrsPos + attrName.length + 2;
let matchSplit = splitterRE.exec(attrValues);
let currentPos = 0;
let value;
while (matchSplit) {
const [matched] = matchSplit;
if (cursor > attrValuePos + currentPos && cursor <= attrValuePos + currentPos + matchSplit.index) {
value = attrValues.slice(currentPos, currentPos + matchSplit.index);
break;
}
currentPos += matchSplit.index + matched.length;
matchSplit = splitterRE.exec(attrValues.slice(currentPos));
}
if (value === void 0)
value = attrValues.slice(currentPos);
const [, variants = "", body] = value.match(variantsRE) || [];
return {
extracted: `${variants}${attrNameWithoutPrefix}-${body}`,
transformSuggestions(suggestions) {
return suggestions.filter((v) => v.startsWith(`${variants}${attrNameWithoutPrefix}-`)).map((v) => variants + v.slice(variants.length + attrNameWithoutPrefix.length + 1));
},
resolveReplacement(suggestion) {
return {
start: currentPos + attrValuePos,
end: currentPos + attrValuePos + value.length,
replacement: variants + suggestion.slice(variants.length + attrNameWithoutPrefix.length + 1)
};
}
};
}
};
}
function presetWeappAttributify(options) {
return {
name: "unocss-preset-weapp-attributify",
autocomplete: {
extractors: [autocompleteExtractorAttributify(options)]
}
};
}
function transformer(options = {}) {
const idFilter = pluginutils.createFilter(
options.include || [/\.vue$/, /\.vue\?vue/],
options.exclude || [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/]
);
const extractor = utils.extractorAttributify(options);
return {
name: "transformer-weapp-attributify",
idFilter,
enforce: "pre",
transform(code) {
const newCode = extractor(code.toString());
code.overwrite(0, code.original.length, newCode);
}
};
}
function extractorAttributify(options = {}) {
return {
transformerAttributify: () => transformer(options),
presetWeappAttributify: () => presetWeappAttributify(options)
};
}
const transformerAttributify = transformer;
const defaultOptions = {
classTags: true,
include: [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/]
};
function transformerClass(options = {}) {
options = {
...defaultOptions,
...options
};
const idFilter = pluginutils.createFilter(
options.include,
options.exclude
);
const vueFilter = pluginutils.createFilter(
[/\.vue$/, /\.vue\?vue/]
);
return {
name: "transformer-weapp-class",
idFilter,
enforce: "pre",
transform(code, id) {
let newCode = utils$1.transformCode(code.toString(), options.transformRules);
if (options.classTags) {
const classNames = utils$1.getClass(code.toString());
const injectStr = Array.from(new Set(classNames.map((x) => x[1]).filter((x) => x).flatMap((x) => x.split(" ")))).join(" ");
if (vueFilter(id))
newCode = newCode.replace("<template>", `<template>
<!-- ${injectStr} -->
`);
else
newCode = `/* ${injectStr} */
${newCode}`;
}
code.overwrite(0, code.original.length, newCode);
}
};
}
exports.defaultRules = utils$1.defaultRules;
exports.defaultAttributes = utils.defaultAttributes;
exports.defaultIgnoreNonValuedAttributes = utils.defaultIgnoreNonValuedAttributes;
exports.extractorAttributify = extractorAttributify;
exports.transformerAttributify = transformerAttributify;
exports.transformerClass = transformerClass;