rDrama/node_modules/tailwindcss/lib/jit/lib/expandTailwindAtRules.js
2021-12-13 22:28:32 +00:00

246 lines
No EOL
8.6 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = expandTailwindAtRules;
var sharedState = _interopRequireWildcard(require("./sharedState"));
var _generateRules = require("./generateRules");
var _bigSign = _interopRequireDefault(require("../../util/bigSign"));
var _cloneNodes = _interopRequireDefault(require("../../util/cloneNodes"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
let env = sharedState.env;
let contentMatchCache = sharedState.contentMatchCache;
const PATTERNS = ["([^<>\"'`\\s]*\\['[^<>\"'`\\s]*'\\])", // `content-['hello']` but not `content-['hello']']`
'([^<>"\'`\\s]*\\["[^<>"\'`\\s]*"\\])', // `content-["hello"]` but not `content-["hello"]"]`
'([^<>"\'`\\s]*\\[[^<>"\'`\\s]+\\])', // `fill-[#bada55]`
'([^<>"\'`\\s]*[^<>"\'`\\s:])' // `px-1.5`, `uppercase` but not `uppercase:`
].join('|');
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g');
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g;
const builtInExtractors = {
DEFAULT: content => {
let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [];
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [];
return [...broadMatches, ...innerMatches];
}
};
const builtInTransformers = {
DEFAULT: content => content,
svelte: content => content.replace(/(?:^|\s)class:/g, ' ')
};
function getExtractor(tailwindConfig, fileExtension) {
let extractors = tailwindConfig && tailwindConfig.purge && tailwindConfig.purge.extract || {};
const purgeOptions = tailwindConfig && tailwindConfig.purge && tailwindConfig.purge.options || {};
if (typeof extractors === 'function') {
extractors = {
DEFAULT: extractors
};
}
if (purgeOptions.defaultExtractor) {
extractors.DEFAULT = purgeOptions.defaultExtractor;
}
for (let {
extensions,
extractor
} of purgeOptions.extractors || []) {
for (let extension of extensions) {
extractors[extension] = extractor;
}
}
return extractors[fileExtension] || extractors.DEFAULT || builtInExtractors[fileExtension] || builtInExtractors.DEFAULT;
}
function getTransformer(tailwindConfig, fileExtension) {
let transformers = tailwindConfig && tailwindConfig.purge && tailwindConfig.purge.transform || {};
if (typeof transformers === 'function') {
transformers = {
DEFAULT: transformers
};
}
return transformers[fileExtension] || transformers.DEFAULT || builtInTransformers[fileExtension] || builtInTransformers.DEFAULT;
} // Scans template contents for possible classes. This is a hot path on initial build but
// not too important for subsequent builds. The faster the better though — if we can speed
// up these regexes by 50% that could cut initial build time by like 20%.
function getClassCandidates(content, extractor, contentMatchCache, candidates, seen) {
for (let line of content.split('\n')) {
line = line.trim();
if (seen.has(line)) {
continue;
}
seen.add(line);
if (contentMatchCache.has(line)) {
for (let match of contentMatchCache.get(line)) {
candidates.add(match);
}
} else {
let extractorMatches = extractor(line).filter(s => s !== '!*');
let lineMatchesSet = new Set(extractorMatches);
for (let match of lineMatchesSet) {
candidates.add(match);
}
contentMatchCache.set(line, lineMatchesSet);
}
}
}
function buildStylesheet(rules, context) {
let sortedRules = rules.sort(([a], [z]) => (0, _bigSign.default)(a - z));
let returnValue = {
base: new Set(),
components: new Set(),
utilities: new Set(),
variants: new Set()
};
for (let [sort, rule] of sortedRules) {
if (sort >= context.minimumScreen) {
returnValue.variants.add(rule);
continue;
}
if (sort & context.layerOrder.base) {
returnValue.base.add(rule);
continue;
}
if (sort & context.layerOrder.components) {
returnValue.components.add(rule);
continue;
}
if (sort & context.layerOrder.utilities) {
returnValue.utilities.add(rule);
continue;
}
}
return returnValue;
}
function expandTailwindAtRules(context) {
return root => {
let layerNodes = {
base: null,
components: null,
utilities: null,
variants: null
}; // Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
root.walkAtRules('tailwind', rule => {
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule;
}
});
if (Object.values(layerNodes).every(n => n === null)) {
return root;
} // ---
// Find potential rules in changed files
let candidates = new Set(['*']);
let seen = new Set();
env.DEBUG && console.time('Reading changed files');
for (let {
content,
extension
} of context.changedContent) {
let transformer = getTransformer(context.tailwindConfig, extension);
let extractor = getExtractor(context.tailwindConfig, extension);
getClassCandidates(transformer(content), extractor, contentMatchCache, candidates, seen);
} // ---
// Generate the actual CSS
let classCacheCount = context.classCache.size;
env.DEBUG && console.time('Generate rules');
let rules = (0, _generateRules.generateRules)(candidates, context);
env.DEBUG && console.timeEnd('Generate rules'); // We only ever add to the classCache, so if it didn't grow, there is nothing new.
env.DEBUG && console.time('Build stylesheet');
if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
for (let rule of rules) {
context.ruleCache.add(rule);
}
context.stylesheetCache = buildStylesheet([...context.ruleCache], context);
}
env.DEBUG && console.timeEnd('Build stylesheet');
let {
base: baseNodes,
components: componentNodes,
utilities: utilityNodes,
variants: screenNodes
} = context.stylesheetCache; // ---
// Replace any Tailwind directives with generated CSS
if (layerNodes.base) {
layerNodes.base.before((0, _cloneNodes.default)([...baseNodes], layerNodes.base.source));
layerNodes.base.remove();
}
if (layerNodes.components) {
layerNodes.components.before((0, _cloneNodes.default)([...componentNodes], layerNodes.components.source));
layerNodes.components.remove();
}
if (layerNodes.utilities) {
layerNodes.utilities.before((0, _cloneNodes.default)([...utilityNodes], layerNodes.utilities.source));
layerNodes.utilities.remove();
}
if (layerNodes.variants) {
layerNodes.variants.before((0, _cloneNodes.default)([...screenNodes], layerNodes.variants.source));
layerNodes.variants.remove();
} else {
root.append((0, _cloneNodes.default)([...screenNodes], root.source));
} // ---
if (env.DEBUG) {
console.log('Potential classes: ', candidates.size);
console.log('Active contexts: ', sharedState.contextSourcesMap.size);
console.log('Content match entries', contentMatchCache.size);
} // Clear the cache for the changed files
context.changedContent = []; // Cleanup any leftover @layer atrules
root.walkAtRules('layer', rule => {
if (Object.keys(layerNodes).includes(rule.params)) {
rule.remove();
}
});
};
}