UNPKG

eslint-plugin-svelte-tailwindcss

Version:
246 lines (243 loc) 7.73 kB
import clearModule from 'clear-module'; import escalade from 'escalade/sync'; import { createJiti } from 'jiti'; import * as fs from 'node:fs/promises'; import * as path from 'node:path'; import { pathToFileURL } from 'node:url'; import postcss from 'postcss'; import postcssImport from 'postcss-import'; import { runAsWorker } from 'synckit'; import { generateRules } from 'tailwindcss/lib/lib/generateRules.js'; import { createContext } from 'tailwindcss/lib/lib/setupContextUtils.js'; import loadConfigFallback from 'tailwindcss/loadConfig.js'; import resolveConfigFallback from 'tailwindcss/resolveConfig.js'; import pkg from 'enhanced-resolve'; import fs$1 from 'node:fs'; const { CachedInputFileSystem, ResolverFactory } = pkg; const createExpiringMap = (duration) => { const map = /* @__PURE__ */ new Map(); return { get(key) { const result = map.get(key); if (!result) { return void 0; } if (result.expiration <= /* @__PURE__ */ new Date()) { map.delete(key); return void 0; } return result.value; }, set(key, value) { const expiration = /* @__PURE__ */ new Date(); expiration.setMilliseconds(expiration.getMilliseconds() + duration); map.set(key, { expiration, value }); } }; }; const fileSystem = new CachedInputFileSystem(fs$1, 3e4); const esmResolver = ResolverFactory.createResolver({ conditionNames: ["node", "import"], extensions: [".mjs", ".js"], fileSystem, mainFields: ["module"], useSyncFileSystemCalls: true }); const cjsResolver = ResolverFactory.createResolver({ conditionNames: ["node", "require"], extensions: [".js", ".cjs"], fileSystem, mainFields: ["main"], useSyncFileSystemCalls: true }); const cssResolver = ResolverFactory.createResolver({ conditionNames: ["style"], extensions: [".css"], fileSystem, mainFields: ["style"], useSyncFileSystemCalls: true }); const resolveCssFrom = (base, id) => cssResolver.resolveSync({}, base, id) || id; const resolveJsFrom = (base, id) => { try { return esmResolver.resolveSync({}, base, id) || id; } catch { return cjsResolver.resolveSync({}, base, id) || id; } }; const sourceToPathMap = /* @__PURE__ */ new Map(); const sourceToEntryMap = /* @__PURE__ */ new Map(); const pathToContextMap = createExpiringMap(1e4); const createLoader = ({ filepath, jiti, legacy, onError }) => { const cacheKey = `${+Date.now()}`; const loadFile = async (id, base, resourceType) => { try { const resolved = resolveJsFrom(base, id); const url = pathToFileURL(resolved); url.searchParams.append("t", cacheKey); return await jiti.import(url.href, { default: true }); } catch (err) { return onError(id, err, resourceType); } }; if (legacy) { const baseDir = path.dirname(filepath); return (id) => loadFile(id, baseDir, "module"); } return async (id, base, resourceType) => ({ base, module: await loadFile(id, base, resourceType) }); }; const getBaseDir = (filePath) => filePath ? path.dirname(filePath) : process.cwd(); const getConfigPath = (twConfigPath, baseDir) => { if (twConfigPath) { if (twConfigPath.endsWith(".css")) { return null; } return path.resolve(baseDir, twConfigPath); } try { return escalade(baseDir, (_dir, names) => { const configFiles = [ "tailwind.config.js", "tailwind.config.cjs", "tailwind.config.mjs", "tailwind.config.ts" ]; return configFiles.find((file) => names.includes(file)); }) ?? null; } catch { return null; } }; const loadV4 = async (baseDir, pkgDir, entryPoint) => { const pkgPath = resolveJsFrom(baseDir, "tailwindcss"); const tw = await import(pathToFileURL(pkgPath).toString()); if (!tw.__unstable__loadDesignSystem) { return null; } entryPoint = entryPoint ?? `${pkgDir}/theme.css`; const jiti = createJiti(import.meta.url, { fsCache: false, moduleCache: false }); const importBasePath = path.dirname(entryPoint); let css = await fs.readFile(entryPoint, "utf-8"); let supportsImports = false; try { await tw.__unstable__loadDesignSystem('@import "./empty";', { loadStylesheet: () => { supportsImports = true; return { base: importBasePath, content: "" }; } }); } catch { } if (!supportsImports) { const resolveImports = postcss([postcssImport()]); const result = await resolveImports.process(css, { from: entryPoint }); css = result.css; } const design = await tw.__unstable__loadDesignSystem(css, { base: importBasePath, loadConfig: createLoader({ filepath: entryPoint, jiti, legacy: true, onError(id, err) { console.error(`Unable to load config: ${id}`, err); return {}; } }), // v4.0.0-alpha.25+ loadModule: createLoader({ filepath: entryPoint, jiti, legacy: false, onError: (id, err, resourceType) => { console.error(`Unable to load ${resourceType}: ${id}`, err); if (resourceType === "config") { return {}; } return () => { }; } }), // v4.0.0-alpha.24 and below loadPlugin: createLoader({ filepath: entryPoint, jiti, legacy: true, onError(id, err) { console.error(`Unable to load plugin: ${id}`, err); return () => { }; } }), loadStylesheet: async (id, base) => { const resolved = resolveCssFrom(base, id); return { base: path.dirname(resolved), content: await fs.readFile(resolved, "utf-8") }; } }); return { context: { getClassOrder: (classList) => design.getClassOrder(classList) }, // Stubs that are not needed for v4 generateRules: () => [] }; }; const loadTailwindConfig = async (baseDir, tailwindConfigPath, entryPoint) => { let createContext$1 = createContext; let generateRules$1 = generateRules; let resolveConfig = resolveConfigFallback; let loadConfig = loadConfigFallback; let tailwindConfig = { content: [] }; try { const pkgFile = resolveJsFrom(baseDir, "tailwindcss/package.json"); const pkgDir = path.dirname(pkgFile); try { const v4 = await loadV4(baseDir, pkgDir, entryPoint); if (v4) { return v4; } } catch { } resolveConfig = await import(path.join(pkgDir, "resolveConfig")); createContext$1 = (await import(path.join(pkgDir, "lib/lib/setupContextUtils"))).createContext; generateRules$1 = (await import(path.join(pkgDir, "lib/lib/generateRules"))).generateRules; loadConfig = await import(path.join(pkgDir, "loadConfig")); } catch { } if (tailwindConfigPath) { clearModule(tailwindConfigPath); const loadedConfig = loadConfig(tailwindConfigPath); tailwindConfig = loadedConfig.default ?? loadedConfig; } tailwindConfig.content = ["no-op"]; return { context: createContext$1(resolveConfig(tailwindConfig)), generateRules: generateRules$1 }; }; runAsWorker(async (filePath, classes) => { const baseDir = getBaseDir(filePath); const configPath = sourceToPathMap.get(filePath) ?? getConfigPath(filePath, baseDir); sourceToPathMap.set(filePath, configPath); const entryPoint = sourceToEntryMap.get(filePath) ?? filePath; sourceToEntryMap.set(filePath, entryPoint); const contextKey = `${configPath}:${entryPoint}`; const existing = pathToContextMap.get(contextKey); if (existing) { return existing.context.getClassOrder(classes); } const result = await loadTailwindConfig(baseDir, configPath, entryPoint); pathToContextMap.set(contextKey, result); return result.context.getClassOrder(classes); });