Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			554 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			554 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| Object.defineProperty(exports, "__esModule", {
 | |
|     value: true
 | |
| });
 | |
| Object.defineProperty(exports, "default", {
 | |
|     enumerable: true,
 | |
|     get: function() {
 | |
|         return expandApplyAtRules;
 | |
|     }
 | |
| });
 | |
| const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
 | |
| const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
 | |
| const _generateRules = require("./generateRules");
 | |
| const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName"));
 | |
| const _applyImportantSelector = require("../util/applyImportantSelector");
 | |
| const _pseudoElements = require("../util/pseudoElements");
 | |
| function _interop_require_default(obj) {
 | |
|     return obj && obj.__esModule ? obj : {
 | |
|         default: obj
 | |
|     };
 | |
| }
 | |
| /** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */ function extractClasses(node) {
 | |
|     /** @type {Map<string, Set<string>>} */ let groups = new Map();
 | |
|     let container = _postcss.default.root({
 | |
|         nodes: [
 | |
|             node.clone()
 | |
|         ]
 | |
|     });
 | |
|     container.walkRules((rule)=>{
 | |
|         (0, _postcssselectorparser.default)((selectors)=>{
 | |
|             selectors.walkClasses((classSelector)=>{
 | |
|                 let parentSelector = classSelector.parent.toString();
 | |
|                 let classes = groups.get(parentSelector);
 | |
|                 if (!classes) {
 | |
|                     groups.set(parentSelector, classes = new Set());
 | |
|                 }
 | |
|                 classes.add(classSelector.value);
 | |
|             });
 | |
|         }).processSync(rule.selector);
 | |
|     });
 | |
|     let normalizedGroups = Array.from(groups.values(), (classes)=>Array.from(classes));
 | |
|     let classes = normalizedGroups.flat();
 | |
|     return Object.assign(classes, {
 | |
|         groups: normalizedGroups
 | |
|     });
 | |
| }
 | |
| let selectorExtractor = (0, _postcssselectorparser.default)();
 | |
| /**
 | |
|  * @param {string} ruleSelectors
 | |
|  */ function extractSelectors(ruleSelectors) {
 | |
|     return selectorExtractor.astSync(ruleSelectors);
 | |
| }
 | |
| function extractBaseCandidates(candidates, separator) {
 | |
|     let baseClasses = new Set();
 | |
|     for (let candidate of candidates){
 | |
|         baseClasses.add(candidate.split(separator).pop());
 | |
|     }
 | |
|     return Array.from(baseClasses);
 | |
| }
 | |
| function prefix(context, selector) {
 | |
|     let prefix = context.tailwindConfig.prefix;
 | |
|     return typeof prefix === "function" ? prefix(selector) : prefix + selector;
 | |
| }
 | |
| function* pathToRoot(node) {
 | |
|     yield node;
 | |
|     while(node.parent){
 | |
|         yield node.parent;
 | |
|         node = node.parent;
 | |
|     }
 | |
| }
 | |
| /**
 | |
|  * Only clone the node itself and not its children
 | |
|  *
 | |
|  * @param {*} node
 | |
|  * @param {*} overrides
 | |
|  * @returns
 | |
|  */ function shallowClone(node, overrides = {}) {
 | |
|     let children = node.nodes;
 | |
|     node.nodes = [];
 | |
|     let tmp = node.clone(overrides);
 | |
|     node.nodes = children;
 | |
|     return tmp;
 | |
| }
 | |
| /**
 | |
|  * Clone just the nodes all the way to the top that are required to represent
 | |
|  * this singular rule in the tree.
 | |
|  *
 | |
|  * For example, if we have CSS like this:
 | |
|  * ```css
 | |
|  * @media (min-width: 768px) {
 | |
|  *   @supports (display: grid) {
 | |
|  *     .foo {
 | |
|  *       display: grid;
 | |
|  *       grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
 | |
|  *     }
 | |
|  *   }
 | |
|  *
 | |
|  *   @supports (backdrop-filter: blur(1px)) {
 | |
|  *     .bar {
 | |
|  *       backdrop-filter: blur(1px);
 | |
|  *     }
 | |
|  *   }
 | |
|  *
 | |
|  *   .baz {
 | |
|  *     color: orange;
 | |
|  *   }
 | |
|  * }
 | |
|  * ```
 | |
|  *
 | |
|  * And we're cloning `.bar` it'll return a cloned version of what's required for just that single node:
 | |
|  *
 | |
|  * ```css
 | |
|  * @media (min-width: 768px) {
 | |
|  *   @supports (backdrop-filter: blur(1px)) {
 | |
|  *     .bar {
 | |
|  *       backdrop-filter: blur(1px);
 | |
|  *     }
 | |
|  *   }
 | |
|  * }
 | |
|  * ```
 | |
|  *
 | |
|  * @param {import('postcss').Node} node
 | |
|  */ function nestedClone(node) {
 | |
|     for (let parent of pathToRoot(node)){
 | |
|         if (node === parent) {
 | |
|             continue;
 | |
|         }
 | |
|         if (parent.type === "root") {
 | |
|             break;
 | |
|         }
 | |
|         node = shallowClone(parent, {
 | |
|             nodes: [
 | |
|                 node
 | |
|             ]
 | |
|         });
 | |
|     }
 | |
|     return node;
 | |
| }
 | |
| /**
 | |
|  * @param {import('postcss').Root} root
 | |
|  */ function buildLocalApplyCache(root, context) {
 | |
|     /** @type {ApplyCache} */ let cache = new Map();
 | |
|     root.walkRules((rule)=>{
 | |
|         // Ignore rules generated by Tailwind
 | |
|         for (let node of pathToRoot(rule)){
 | |
|             var _node_raws_tailwind;
 | |
|             if (((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.layer) !== undefined) {
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         // Clone what's required to represent this singular rule in the tree
 | |
|         let container = nestedClone(rule);
 | |
|         let sort = context.offsets.create("user");
 | |
|         for (let className of extractClasses(rule)){
 | |
|             let list = cache.get(className) || [];
 | |
|             cache.set(className, list);
 | |
|             list.push([
 | |
|                 {
 | |
|                     layer: "user",
 | |
|                     sort,
 | |
|                     important: false
 | |
|                 },
 | |
|                 container
 | |
|             ]);
 | |
|         }
 | |
|     });
 | |
|     return cache;
 | |
| }
 | |
| /**
 | |
|  * @returns {ApplyCache}
 | |
|  */ function buildApplyCache(applyCandidates, context) {
 | |
|     for (let candidate of applyCandidates){
 | |
|         if (context.notClassCache.has(candidate) || context.applyClassCache.has(candidate)) {
 | |
|             continue;
 | |
|         }
 | |
|         if (context.classCache.has(candidate)) {
 | |
|             context.applyClassCache.set(candidate, context.classCache.get(candidate).map(([meta, rule])=>[
 | |
|                     meta,
 | |
|                     rule.clone()
 | |
|                 ]));
 | |
|             continue;
 | |
|         }
 | |
|         let matches = Array.from((0, _generateRules.resolveMatches)(candidate, context));
 | |
|         if (matches.length === 0) {
 | |
|             context.notClassCache.add(candidate);
 | |
|             continue;
 | |
|         }
 | |
|         context.applyClassCache.set(candidate, matches);
 | |
|     }
 | |
|     return context.applyClassCache;
 | |
| }
 | |
| /**
 | |
|  * Build a cache only when it's first used
 | |
|  *
 | |
|  * @param {() => ApplyCache} buildCacheFn
 | |
|  * @returns {ApplyCache}
 | |
|  */ function lazyCache(buildCacheFn) {
 | |
|     let cache = null;
 | |
|     return {
 | |
|         get: (name)=>{
 | |
|             cache = cache || buildCacheFn();
 | |
|             return cache.get(name);
 | |
|         },
 | |
|         has: (name)=>{
 | |
|             cache = cache || buildCacheFn();
 | |
|             return cache.has(name);
 | |
|         }
 | |
|     };
 | |
| }
 | |
| /**
 | |
|  * Take a series of multiple caches and merge
 | |
|  * them so they act like one large cache
 | |
|  *
 | |
|  * @param {ApplyCache[]} caches
 | |
|  * @returns {ApplyCache}
 | |
|  */ function combineCaches(caches) {
 | |
|     return {
 | |
|         get: (name)=>caches.flatMap((cache)=>cache.get(name) || []),
 | |
|         has: (name)=>caches.some((cache)=>cache.has(name))
 | |
|     };
 | |
| }
 | |
| function extractApplyCandidates(params) {
 | |
|     let candidates = params.split(/[\s\t\n]+/g);
 | |
|     if (candidates[candidates.length - 1] === "!important") {
 | |
|         return [
 | |
|             candidates.slice(0, -1),
 | |
|             true
 | |
|         ];
 | |
|     }
 | |
|     return [
 | |
|         candidates,
 | |
|         false
 | |
|     ];
 | |
| }
 | |
| function processApply(root, context, localCache) {
 | |
|     let applyCandidates = new Set();
 | |
|     // Collect all @apply rules and candidates
 | |
|     let applies = [];
 | |
|     root.walkAtRules("apply", (rule)=>{
 | |
|         let [candidates] = extractApplyCandidates(rule.params);
 | |
|         for (let util of candidates){
 | |
|             applyCandidates.add(util);
 | |
|         }
 | |
|         applies.push(rule);
 | |
|     });
 | |
|     // Start the @apply process if we have rules with @apply in them
 | |
|     if (applies.length === 0) {
 | |
|         return;
 | |
|     }
 | |
|     // Fill up some caches!
 | |
|     let applyClassCache = combineCaches([
 | |
|         localCache,
 | |
|         buildApplyCache(applyCandidates, context)
 | |
|     ]);
 | |
|     /**
 | |
|    * When we have an apply like this:
 | |
|    *
 | |
|    * .abc {
 | |
|    *    @apply hover:font-bold;
 | |
|    * }
 | |
|    *
 | |
|    * What we essentially will do is resolve to this:
 | |
|    *
 | |
|    * .abc {
 | |
|    *    @apply .hover\:font-bold:hover {
 | |
|    *      font-weight: 500;
 | |
|    *    }
 | |
|    * }
 | |
|    *
 | |
|    * Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
 | |
|    * What happens in this function is that we prepend a `.` and escape the candidate.
 | |
|    * This will result in `.hover\:font-bold`
 | |
|    * Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
 | |
|    *
 | |
|    * @param {string} selector
 | |
|    * @param {string} utilitySelectors
 | |
|    * @param {string} candidate
 | |
|    */ function replaceSelector(selector, utilitySelectors, candidate) {
 | |
|         let selectorList = extractSelectors(selector);
 | |
|         let utilitySelectorsList = extractSelectors(utilitySelectors);
 | |
|         let candidateList = extractSelectors(`.${(0, _escapeClassName.default)(candidate)}`);
 | |
|         let candidateClass = candidateList.nodes[0].nodes[0];
 | |
|         selectorList.each((sel)=>{
 | |
|             /** @type {Set<import('postcss-selector-parser').Selector>} */ let replaced = new Set();
 | |
|             utilitySelectorsList.each((utilitySelector)=>{
 | |
|                 let hasReplaced = false;
 | |
|                 utilitySelector = utilitySelector.clone();
 | |
|                 utilitySelector.walkClasses((node)=>{
 | |
|                     if (node.value !== candidateClass.value) {
 | |
|                         return;
 | |
|                     }
 | |
|                     // Don't replace multiple instances of the same class
 | |
|                     // This is theoretically correct but only partially
 | |
|                     // We'd need to generate every possible permutation of the replacement
 | |
|                     // For example with `.foo + .foo { … }` and `section { @apply foo; }`
 | |
|                     // We'd need to generate all of these:
 | |
|                     // - `.foo + .foo`
 | |
|                     // - `.foo + section`
 | |
|                     // - `section + .foo`
 | |
|                     // - `section + section`
 | |
|                     if (hasReplaced) {
 | |
|                         return;
 | |
|                     }
 | |
|                     // Since you can only `@apply` class names this is sufficient
 | |
|                     // We want to replace the matched class name with the selector the user is using
 | |
|                     // Ex: Replace `.text-blue-500` with `.foo.bar:is(.something-cool)`
 | |
|                     node.replaceWith(...sel.nodes.map((node)=>node.clone()));
 | |
|                     // Record that we did something and we want to use this new selector
 | |
|                     replaced.add(utilitySelector);
 | |
|                     hasReplaced = true;
 | |
|                 });
 | |
|             });
 | |
|             // Sort tag names before class names (but only sort each group (separated by a combinator)
 | |
|             // separately and not in total)
 | |
|             // This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
 | |
|             for (let sel of replaced){
 | |
|                 let groups = [
 | |
|                     []
 | |
|                 ];
 | |
|                 for (let node of sel.nodes){
 | |
|                     if (node.type === "combinator") {
 | |
|                         groups.push(node);
 | |
|                         groups.push([]);
 | |
|                     } else {
 | |
|                         let last = groups[groups.length - 1];
 | |
|                         last.push(node);
 | |
|                     }
 | |
|                 }
 | |
|                 sel.nodes = [];
 | |
|                 for (let group of groups){
 | |
|                     if (Array.isArray(group)) {
 | |
|                         group.sort((a, b)=>{
 | |
|                             if (a.type === "tag" && b.type === "class") {
 | |
|                                 return -1;
 | |
|                             } else if (a.type === "class" && b.type === "tag") {
 | |
|                                 return 1;
 | |
|                             } else if (a.type === "class" && b.type === "pseudo" && b.value.startsWith("::")) {
 | |
|                                 return -1;
 | |
|                             } else if (a.type === "pseudo" && a.value.startsWith("::") && b.type === "class") {
 | |
|                                 return 1;
 | |
|                             }
 | |
|                             return 0;
 | |
|                         });
 | |
|                     }
 | |
|                     sel.nodes = sel.nodes.concat(group);
 | |
|                 }
 | |
|             }
 | |
|             sel.replaceWith(...replaced);
 | |
|         });
 | |
|         return selectorList.toString();
 | |
|     }
 | |
|     let perParentApplies = new Map();
 | |
|     // Collect all apply candidates and their rules
 | |
|     for (let apply of applies){
 | |
|         let [candidates] = perParentApplies.get(apply.parent) || [
 | |
|             [],
 | |
|             apply.source
 | |
|         ];
 | |
|         perParentApplies.set(apply.parent, [
 | |
|             candidates,
 | |
|             apply.source
 | |
|         ]);
 | |
|         let [applyCandidates, important] = extractApplyCandidates(apply.params);
 | |
|         if (apply.parent.type === "atrule") {
 | |
|             if (apply.parent.name === "screen") {
 | |
|                 let screenType = apply.parent.params;
 | |
|                 throw apply.error(`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates.map((c)=>`${screenType}:${c}`).join(" ")} instead.`);
 | |
|             }
 | |
|             throw apply.error(`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`);
 | |
|         }
 | |
|         for (let applyCandidate of applyCandidates){
 | |
|             if ([
 | |
|                 prefix(context, "group"),
 | |
|                 prefix(context, "peer")
 | |
|             ].includes(applyCandidate)) {
 | |
|                 // TODO: Link to specific documentation page with error code.
 | |
|                 throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
 | |
|             }
 | |
|             if (!applyClassCache.has(applyCandidate)) {
 | |
|                 throw apply.error(`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`);
 | |
|             }
 | |
|             let rules = applyClassCache.get(applyCandidate);
 | |
|             // Verify that we can apply the class
 | |
|             for (let [, rule] of rules){
 | |
|                 if (rule.type === "atrule") {
 | |
|                     continue;
 | |
|                 }
 | |
|                 rule.walkRules(()=>{
 | |
|                     throw apply.error([
 | |
|                         `The \`${applyCandidate}\` class cannot be used with \`@apply\` because \`@apply\` does not currently support nested CSS.`,
 | |
|                         "Rewrite the selector without nesting or configure the `tailwindcss/nesting` plugin:",
 | |
|                         "https://tailwindcss.com/docs/using-with-preprocessors#nesting"
 | |
|                     ].join("\n"));
 | |
|                 });
 | |
|             }
 | |
|             candidates.push([
 | |
|                 applyCandidate,
 | |
|                 important,
 | |
|                 rules
 | |
|             ]);
 | |
|         }
 | |
|     }
 | |
|     for (let [parent, [candidates, atApplySource]] of perParentApplies){
 | |
|         let siblings = [];
 | |
|         for (let [applyCandidate, important, rules] of candidates){
 | |
|             let potentialApplyCandidates = [
 | |
|                 applyCandidate,
 | |
|                 ...extractBaseCandidates([
 | |
|                     applyCandidate
 | |
|                 ], context.tailwindConfig.separator)
 | |
|             ];
 | |
|             for (let [meta, node] of rules){
 | |
|                 let parentClasses = extractClasses(parent);
 | |
|                 let nodeClasses = extractClasses(node);
 | |
|                 // When we encounter a rule like `.dark .a, .b { … }` we only want to be left with `[.dark, .a]` if the base applyCandidate is `.a` or with `[.b]` if the base applyCandidate is `.b`
 | |
|                 // So we've split them into groups
 | |
|                 nodeClasses = nodeClasses.groups.filter((classList)=>classList.some((className)=>potentialApplyCandidates.includes(className))).flat();
 | |
|                 // Add base utility classes from the @apply node to the list of
 | |
|                 // classes to check whether it intersects and therefore results in a
 | |
|                 // circular dependency or not.
 | |
|                 //
 | |
|                 // E.g.:
 | |
|                 // .foo {
 | |
|                 //   @apply hover:a; // This applies "a" but with a modifier
 | |
|                 // }
 | |
|                 //
 | |
|                 // We only have to do that with base classes of the `node`, not of the `parent`
 | |
|                 // E.g.:
 | |
|                 // .hover\:foo {
 | |
|                 //   @apply bar;
 | |
|                 // }
 | |
|                 // .bar {
 | |
|                 //   @apply foo;
 | |
|                 // }
 | |
|                 //
 | |
|                 // This should not result in a circular dependency because we are
 | |
|                 // just applying `.foo` and the rule above is `.hover\:foo` which is
 | |
|                 // unrelated. However, if we were to apply `hover:foo` then we _did_
 | |
|                 // have to include this one.
 | |
|                 nodeClasses = nodeClasses.concat(extractBaseCandidates(nodeClasses, context.tailwindConfig.separator));
 | |
|                 let intersects = parentClasses.some((selector)=>nodeClasses.includes(selector));
 | |
|                 if (intersects) {
 | |
|                     throw node.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`);
 | |
|                 }
 | |
|                 let root = _postcss.default.root({
 | |
|                     nodes: [
 | |
|                         node.clone()
 | |
|                     ]
 | |
|                 });
 | |
|                 // Make sure every node in the entire tree points back at the @apply rule that generated it
 | |
|                 root.walk((node)=>{
 | |
|                     node.source = atApplySource;
 | |
|                 });
 | |
|                 let canRewriteSelector = node.type !== "atrule" || node.type === "atrule" && node.name !== "keyframes";
 | |
|                 if (canRewriteSelector) {
 | |
|                     root.walkRules((rule)=>{
 | |
|                         // Let's imagine you have the following structure:
 | |
|                         //
 | |
|                         // .foo {
 | |
|                         //   @apply bar;
 | |
|                         // }
 | |
|                         //
 | |
|                         // @supports (a: b) {
 | |
|                         //   .bar {
 | |
|                         //     color: blue
 | |
|                         //   }
 | |
|                         //
 | |
|                         //   .something-unrelated {}
 | |
|                         // }
 | |
|                         //
 | |
|                         // In this case we want to apply `.bar` but it happens to be in
 | |
|                         // an atrule node. We clone that node instead of the nested one
 | |
|                         // because we still want that @supports rule to be there once we
 | |
|                         // applied everything.
 | |
|                         //
 | |
|                         // However it happens to be that the `.something-unrelated` is
 | |
|                         // also in that same shared @supports atrule. This is not good,
 | |
|                         // and this should not be there. The good part is that this is
 | |
|                         // a clone already and it can be safely removed. The question is
 | |
|                         // how do we know we can remove it. Basically what we can do is
 | |
|                         // match it against the applyCandidate that you want to apply. If
 | |
|                         // it doesn't match the we can safely delete it.
 | |
|                         //
 | |
|                         // If we didn't do this, then the `replaceSelector` function
 | |
|                         // would have replaced this with something that didn't exist and
 | |
|                         // therefore it removed the selector altogether. In this specific
 | |
|                         // case it would result in `{}` instead of `.something-unrelated {}`
 | |
|                         if (!extractClasses(rule).some((candidate)=>candidate === applyCandidate)) {
 | |
|                             rule.remove();
 | |
|                             return;
 | |
|                         }
 | |
|                         // Strip the important selector from the parent selector if at the beginning
 | |
|                         let importantSelector = typeof context.tailwindConfig.important === "string" ? context.tailwindConfig.important : null;
 | |
|                         // We only want to move the "important" selector if this is a Tailwind-generated utility
 | |
|                         // We do *not* want to do this for user CSS that happens to be structured the same
 | |
|                         let isGenerated = parent.raws.tailwind !== undefined;
 | |
|                         let parentSelector = isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0 ? parent.selector.slice(importantSelector.length) : parent.selector;
 | |
|                         // If the selector becomes empty after replacing the important selector
 | |
|                         // This means that it's the same as the parent selector and we don't want to replace it
 | |
|                         // Otherwise we'll crash
 | |
|                         if (parentSelector === "") {
 | |
|                             parentSelector = parent.selector;
 | |
|                         }
 | |
|                         rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate);
 | |
|                         // And then re-add it if it was removed
 | |
|                         if (importantSelector && parentSelector !== parent.selector) {
 | |
|                             rule.selector = (0, _applyImportantSelector.applyImportantSelector)(rule.selector, importantSelector);
 | |
|                         }
 | |
|                         rule.walkDecls((d)=>{
 | |
|                             d.important = meta.important || important;
 | |
|                         });
 | |
|                         // Move pseudo elements to the end of the selector (if necessary)
 | |
|                         let selector = (0, _postcssselectorparser.default)().astSync(rule.selector);
 | |
|                         selector.each((sel)=>(0, _pseudoElements.movePseudos)(sel));
 | |
|                         rule.selector = selector.toString();
 | |
|                     });
 | |
|                 }
 | |
|                 // It could be that the node we were inserted was removed because the class didn't match
 | |
|                 // If that was the *only* rule in the parent, then we have nothing add so we skip it
 | |
|                 if (!root.nodes[0]) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 // Insert it
 | |
|                 siblings.push([
 | |
|                     meta.sort,
 | |
|                     root.nodes[0]
 | |
|                 ]);
 | |
|             }
 | |
|         }
 | |
|         // Inject the rules, sorted, correctly
 | |
|         let nodes = context.offsets.sort(siblings).map((s)=>s[1]);
 | |
|         // `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
 | |
|         parent.after(nodes);
 | |
|     }
 | |
|     for (let apply of applies){
 | |
|         // If there are left-over declarations, just remove the @apply
 | |
|         if (apply.parent.nodes.length > 1) {
 | |
|             apply.remove();
 | |
|         } else {
 | |
|             // The node is empty, drop the full node
 | |
|             apply.parent.remove();
 | |
|         }
 | |
|     }
 | |
|     // Do it again, in case we have other `@apply` rules
 | |
|     processApply(root, context, localCache);
 | |
| }
 | |
| function expandApplyAtRules(context) {
 | |
|     return (root)=>{
 | |
|         // Build a cache of the user's CSS so we can use it to resolve classes used by @apply
 | |
|         let localCache = lazyCache(()=>buildLocalApplyCache(root, context));
 | |
|         processApply(root, context, localCache);
 | |
|     };
 | |
| }
 |