UNPKG

weapp-tailwindcss

Version:

把 tailwindcss 原子化样式思想,带给小程序开发者们! bring tailwindcss to miniprogram developers!

1,665 lines (1,641 loc) 84.5 kB
import { applyV4CssCalcDefaults, createTailwindcssPatcherFromContext, findNearestPackageRoot, warnMissingCssEntries } from "./chunk-SZOXLSNK.mjs"; import { getDefaultOptions } from "./chunk-TFOTUR4L.mjs"; import { defuOverrideArray, isMap } from "./chunk-RR5HCKVQ.mjs"; // src/tailwindcss/runtime.ts import { statSync } from "fs"; // src/debug/index.ts import _createDebug from "debug"; var _debug = _createDebug("weapp-tw"); function createDebug(prefix) { function debug2(formatter, ...args) { return _debug((prefix ?? "") + formatter, ...args); } return debug2; } // src/tailwindcss/runtime.ts var debug = createDebug("[tailwindcss:runtime] "); var refreshTailwindcssPatcherSymbol = /* @__PURE__ */ Symbol.for("weapp-tailwindcss.refreshTailwindcssPatcher"); var runtimeClassSetCache = /* @__PURE__ */ new WeakMap(); function getCacheEntry(twPatcher) { let entry = runtimeClassSetCache.get(twPatcher); if (!entry) { entry = {}; runtimeClassSetCache.set(twPatcher, entry); } return entry; } function getTailwindConfigSignature(twPatcher) { const configPath = twPatcher.options?.tailwind?.config; if (typeof configPath !== "string" || configPath.length === 0) { return void 0; } try { const stats = statSync(configPath); return `${configPath}:${stats.size}:${stats.mtimeMs}`; } catch { return `${configPath}:missing`; } } function invalidateRuntimeClassSet(twPatcher) { if (!twPatcher) { return; } runtimeClassSetCache.delete(twPatcher); } function createTailwindPatchPromise(twPatcher, onPatched) { return Promise.resolve(twPatcher.patch()).then(async (result) => { invalidateRuntimeClassSet(twPatcher); if (onPatched) { try { await onPatched(); } catch (error) { debug("failed to persist patch target after patch(): %O", error); } } return result; }); } async function refreshTailwindRuntimeState(state, force) { if (!force) { return false; } await state.patchPromise; let refreshed = false; if (typeof state.refreshTailwindcssPatcher === "function") { const next = await state.refreshTailwindcssPatcher({ clearCache: true }); if (next !== state.twPatcher) { state.twPatcher = next; } refreshed = true; } if (refreshed) { state.patchPromise = createTailwindPatchPromise(state.twPatcher, state.onPatchCompleted); } return refreshed; } function shouldPreferSync(majorVersion) { if (majorVersion == null) { return true; } if (majorVersion === 3) { return true; } if (majorVersion === 4) { return true; } return false; } function tryGetRuntimeClassSetSync(twPatcher) { if (typeof twPatcher.getClassSetSync !== "function") { return void 0; } if (!shouldPreferSync(twPatcher.majorVersion)) { return void 0; } try { const set = twPatcher.getClassSetSync(); if (set && set.size === 0) { return void 0; } return set; } catch (error) { if (twPatcher.majorVersion === 4) { debug("getClassSetSync() unavailable for tailwindcss v4, fallback to async getClassSet(): %O", error); } else { debug("getClassSetSync() failed, fallback to async getClassSet(): %O", error); } return void 0; } } async function collectRuntimeClassSet(twPatcher, options = {}) { let activePatcher = twPatcher; if (options.force && !options.skipRefresh) { const refresh = activePatcher[refreshTailwindcssPatcherSymbol]; if (typeof refresh === "function") { try { const refreshed = await refresh({ clearCache: true }); if (refreshed) { activePatcher = refreshed; } } catch (error) { debug("refreshTailwindcssPatcher failed, continuing with existing patcher: %O", error); } } } const entry = getCacheEntry(activePatcher); const signature = getTailwindConfigSignature(activePatcher); if (!options.force) { if (entry.value && entry.signature === signature) { return entry.value; } if (entry.promise) { return entry.promise; } } else { entry.value = void 0; } const task = (async () => { const syncSet = tryGetRuntimeClassSetSync(activePatcher); if (syncSet) { return syncSet; } try { const result = await activePatcher.extract({ write: false }); if (result?.classSet) { return result.classSet; } } catch (error) { debug("extract() failed, fallback to getClassSet(): %O", error); } try { const fallbackSet = await Promise.resolve(activePatcher.getClassSet()); if (fallbackSet) { return fallbackSet; } } catch (error) { debug("getClassSet() failed, returning empty set: %O", error); } return /* @__PURE__ */ new Set(); })(); entry.promise = task; entry.signature = signature; try { const resolved = await task; entry.value = resolved; entry.promise = void 0; entry.signature = signature; return resolved; } catch (error) { entry.promise = void 0; throw error; } } // package.json var package_default = { name: "weapp-tailwindcss", version: "4.9.0", description: "\u628A tailwindcss \u539F\u5B50\u5316\u6837\u5F0F\u601D\u60F3\uFF0C\u5E26\u7ED9\u5C0F\u7A0B\u5E8F\u5F00\u53D1\u8005\u4EEC! bring tailwindcss to miniprogram developers!", author: "ice breaker <1324318532@qq.com>", license: "MIT", homepage: "https://tw.icebreaker.top", repository: { type: "git", url: "git+https://github.com/sonofmagic/weapp-tailwindcss.git", directory: "packages/weapp-tailwindcss" }, bugs: { url: "https://github.com/sonofmagic/weapp-tailwindcss/issues" }, keywords: [ "tailwindcss", "weapp", "wechat", "mini", "miniprogram", "mini app", "weapp-tw", "weapp-tailwindcss", "taro", "uni-app", "remax", "rax", "mpx", "jit", "mp", "android", "ios", "\u5C0F\u7A0B\u5E8F", "vite", "postcss", "webpack", "webpack-plugin", "gulp", "gulp-plugin" ], exports: { ".": { style: "./index.css", types: "./dist/index.d.ts", import: "./dist/index.mjs", require: "./dist/index.js" }, "./escape": { types: "./dist/escape.d.ts", import: "./dist/escape.mjs", require: "./dist/escape.js" }, "./vite": { types: "./dist/vite.d.ts", import: "./dist/vite.mjs", require: "./dist/vite.js" }, "./webpack": { types: "./dist/webpack.d.ts", import: "./dist/webpack.mjs", require: "./dist/webpack.js" }, "./webpack4": { types: "./dist/webpack4.d.ts", import: "./dist/webpack4.mjs", require: "./dist/webpack4.js" }, "./core": { types: "./dist/core.d.ts", import: "./dist/core.mjs", require: "./dist/core.js" }, "./gulp": { types: "./dist/gulp.d.ts", import: "./dist/gulp.mjs", require: "./dist/gulp.js" }, "./defaults": { types: "./dist/defaults.d.ts", import: "./dist/defaults.mjs", require: "./dist/defaults.js" }, "./presets": { types: "./dist/presets.d.ts", import: "./dist/presets.mjs", require: "./dist/presets.js" }, "./reset": { types: "./dist/reset.d.ts", import: "./dist/reset.mjs", require: "./dist/reset.js" }, "./css-macro/postcss": { types: "./dist/css-macro/postcss.d.ts", import: "./dist/css-macro/postcss.mjs", require: "./dist/css-macro/postcss.js" }, "./css-macro": { types: "./dist/css-macro.d.ts", import: "./dist/css-macro.mjs", require: "./dist/css-macro.js" }, "./types": { types: "./dist/types.d.ts", import: "./dist/types.mjs", require: "./dist/types.js" }, "./postcss-html-transform": { types: "./dist/postcss-html-transform.d.ts", import: "./dist/postcss-html-transform.mjs", require: "./dist/postcss-html-transform.js" }, "./package.json": "./package.json", "./index.css": "./index.css", "./index": "./index.css", "./preflight.css": "./preflight.css", "./preflight": "./preflight.css", "./theme.css": "./theme.css", "./theme": "./theme.css", "./utilities.css": "./utilities.css", "./utilities": "./utilities.css", "./with-layer.css": "./with-layer.css", "./with-layer": "./with-layer.css", "./uni-app-x": "./uni-app-x.css", "./uni-app-x.css": "./uni-app-x.css", "./css": "./css/index.css", "./*": "./*" }, main: "./dist/index.js", module: "./dist/index.mjs", types: "./dist/index.d.ts", style: "index.css", typesVersions: { "*": { "*": [ "./dist/*", "./dist/index.d.ts" ] } }, bin: { "weapp-tailwindcss-webpack-plugin": "bin/weapp-tailwindcss.js", "weapp-tailwindcss": "bin/weapp-tailwindcss.js", "weapp-tw": "bin/weapp-tailwindcss.js" }, files: [ "bin", "css", "dist", "index.css", "preflight.css", "theme.css", "uni-app-x.css", "utilities.css", "with-layer.css" ], engines: { node: "^18.17.0 || >=20.5.0" }, scripts: { dev: "tsup --watch --sourcemap", build: "tsup && node scripts/ensure-escape-dts.mjs", "build:tsc": "cross-env NODE_ENV=development tsc --build tsconfig.json", "build:cli": "cd plugins/cli && pnpm run build", "build:css": "tsx scripts/build-css.ts", "build:weapp-theme": "tsx scripts/build-weapp-theme.ts", test: "npm run postinstall && vitest run", "test:dev": "vitest", "test:ui": "vitest --ui", bench: "vitest bench --config ./vitest.config.ts", "bench:js-handlers": "tsx scripts/js-bench.ts", "bench:js-diff": "tsx scripts/js-bench-diff.ts", clean: "tsx scripts/clean.ts", "get-decl": "tsx scripts/get-decl.ts", "ls:pack": "npm pack --dry-run", "cli:patch": "node bin/weapp-tailwindcss.js patch", colors: "tsx scripts/colors.ts", release: "tsx scripts/release.ts", lint: "eslint .", "lint:fix": "eslint ./src --fix", postinstall: "node bin/weapp-tailwindcss.js patch" }, publishConfig: { access: "public", registry: "https://registry.npmjs.org" }, dependencies: { "@ast-core/escape": "~1.0.1", "@babel/parser": "~7.28.5", "@babel/traverse": "~7.28.5", "@babel/types": "~7.28.5", "@tailwindcss-mangle/config": "^6.1.0", "@vue/compiler-dom": "catalog:vue3", "@vue/compiler-sfc": "catalog:vue3", "@weapp-core/escape": "~6.0.1", "@weapp-core/regex": "~1.0.1", "@weapp-tailwindcss/logger": "workspace:*", "@weapp-tailwindcss/postcss": "workspace:*", "@weapp-tailwindcss/shared": "workspace:*", cac: "^6.7.14", debug: "~4.4.3", "fast-glob": "^3.3.3", htmlparser2: "10.0.0", "loader-utils": "2.0.4", "local-pkg": "^1.1.2", "lru-cache": "10.4.3", "magic-string": "0.30.21", semver: "~7.7.3", "tailwindcss-patch": "catalog:tailwindcssPatch", "webpack-sources": "3.3.3", yaml: "^2.8.2" } }; // src/constants.ts var pluginName = "weapp-tailwindcss-webpack-plugin"; var vitePluginName = "weapp-tailwindcss:adaptor"; var WEAPP_TW_REQUIRED_NODE_VERSION = "18.17.0"; var WEAPP_TW_VERSION = package_default.version; var DEFAULT_RUNTIME_PACKAGE_REPLACEMENTS = { "tailwind-merge": "@weapp-tailwindcss/merge", "class-variance-authority": "@weapp-tailwindcss/cva", "tailwind-variants": "@weapp-tailwindcss/variants" }; // src/context/index.ts import { rm } from "fs/promises"; import { logger as logger4, pc } from "@weapp-tailwindcss/logger"; // src/cache/index.ts import { LRUCache } from "lru-cache"; // src/cache/md5.ts import { md5 } from "@weapp-tailwindcss/shared/node"; // src/cache/index.ts function isProcessResult(value) { return typeof value === "object" && value !== null && "result" in value; } function createCache(options) { const disabled = options === false; const hashMap = /* @__PURE__ */ new Map(); const instance = new LRUCache({ // 可能会添加和删除一些页面和组件, 先设定 1024 吧 max: 1024, ttl: 0, ttlAutopurge: false }); const cache = { hashMap, instance, hasHashKey(key) { return hashMap.has(key); }, getHashValue(key) { return hashMap.get(key); }, setHashValue(key, value) { return hashMap.set(key, value); }, get(key) { return instance.get(key); }, set(key, value) { return instance.set(key, value); }, computeHash(message) { return md5(message); }, calcHashValueChanged(key, hash) { const hit = hashMap.get(key); if (hit) { hashMap.set(key, { changed: hash !== hit.hash, hash }); } else { hashMap.set(key, { changed: true, hash }); } return cache; }, has(key) { return instance.has(key); }, async process({ key, hashKey, rawSource, hash, resolveCache, transform, onCacheHit }) { if (disabled) { const value2 = await transform(); return isProcessResult(value2) ? value2.result : value2; } const cacheHashKey = hashKey ?? key; let hasChanged = true; if (hash != null || rawSource != null) { const nextHash = hash ?? cache.computeHash(rawSource); cache.calcHashValueChanged(cacheHashKey, nextHash); const entry = cache.getHashValue(cacheHashKey); hasChanged = entry?.changed ?? true; } const readCache = resolveCache ?? (() => cache.get(key)); if (!hasChanged) { const cached = readCache(); if (cached !== void 0) { await onCacheHit?.(cached); return cached; } } const value = await transform(); const normalized = isProcessResult(value) ? value : { result: value }; const stored = normalized.cacheValue ?? normalized.result; cache.set(key, stored); return normalized.result; } }; return cache; } function initializeCache(cacheConfig) { if (typeof cacheConfig === "boolean" || cacheConfig === void 0) { return createCache(cacheConfig); } return cacheConfig; } // src/tailwindcss/targets.ts import { existsSync, readFileSync } from "fs"; import { mkdir, writeFile } from "fs/promises"; import path from "path"; import process from "process"; import { logger } from "@weapp-tailwindcss/logger"; var PATCH_INFO_FILENAME = "tailwindcss-target.json"; var PATCH_INFO_CACHE_RELATIVE_PATH = path.join("node_modules", ".cache", "weapp-tailwindcss", PATCH_INFO_FILENAME); var PATCH_INFO_LEGACY_RELATIVE_PATH = path.join(".tw-patch", PATCH_INFO_FILENAME); var loggedInvalidPatchRecords = /* @__PURE__ */ new Set(); function formatRelativeToBase(targetPath, baseDir) { if (!baseDir) { return path.normalize(targetPath); } const relative = path.relative(baseDir, targetPath); if (!relative || relative === ".") { return "."; } if (relative.startsWith("..")) { return path.normalize(targetPath); } return path.join(".", relative); } function resolveRecordLocation(baseDir) { const normalizedBase = path.normalize(baseDir); const packageRoot = findNearestPackageRoot(normalizedBase) ?? normalizedBase; const packageJsonPath = path.join(packageRoot, "package.json"); const hasPackageJson = existsSync(packageJsonPath); const recordKeySource = hasPackageJson ? packageJsonPath : normalizedBase; const recordKey = md5(path.normalize(recordKeySource)); const recordDir = path.join(packageRoot, "node_modules", ".cache", "weapp-tailwindcss", recordKey); const recordPath = path.join(recordDir, PATCH_INFO_FILENAME); return { normalizedBase, packageRoot, recordDir, recordKey, recordPath, packageJsonPath: hasPackageJson ? packageJsonPath : void 0 }; } function getRecordFileCandidates(baseDir) { const { normalizedBase, packageRoot, recordPath } = resolveRecordLocation(baseDir); const candidates = /* @__PURE__ */ new Set([ recordPath, path.join(packageRoot, PATCH_INFO_CACHE_RELATIVE_PATH), path.join(normalizedBase, PATCH_INFO_CACHE_RELATIVE_PATH), path.join(normalizedBase, PATCH_INFO_LEGACY_RELATIVE_PATH) ]); return [...candidates]; } function logTailwindcssTarget(kind, patcher, baseDir) { const packageInfo = patcher?.packageInfo; const label = kind === "cli" ? "weapp-tw patch" : "tailwindcss-patcher"; if (!packageInfo?.rootPath) { logger.warn( "%s \u672A\u627E\u5230 Tailwind CSS \u4F9D\u8D56\uFF0C\u8BF7\u68C0\u67E5\u5728 %s \u662F\u5426\u5DF2\u5B89\u88C5 tailwindcss", label, baseDir ?? process.cwd() ); return; } const displayPath = formatRelativeToBase(packageInfo.rootPath, baseDir); const version = packageInfo.version ? ` (v${packageInfo.version})` : ""; logger.info("%s \u7ED1\u5B9A Tailwind CSS -> %s%s", label, displayPath, version); } function warnInvalidPatchTargetRecord(baseDir, recordPath, reason) { const normalizedPath = path.normalize(recordPath); if (loggedInvalidPatchRecords.has(normalizedPath)) { return; } loggedInvalidPatchRecords.add(normalizedPath); const fileDisplay = formatRelativeToBase(normalizedPath, baseDir); const baseDisplay = formatRelativeToBase(path.normalize(baseDir), process.cwd()); const reasonMessage = reason ? `\uFF1A${reason}` : ""; logger.warn( `\u68C0\u6D4B\u5230\u635F\u574F\u7684 Tailwind CSS \u76EE\u6807\u8BB0\u5F55 ${fileDisplay}${reasonMessage}\u3002\u8BF7\u5728 ${baseDisplay} \u91CD\u65B0\u6267\u884C "weapp-tw patch --record-target" \u6216\u5220\u9664\u8BE5\u6587\u4EF6\u540E\u518D\u8FD0\u884C\u3002` ); } function readPatchTargetRecord(baseDir) { if (!baseDir) { return void 0; } const normalizedBase = path.normalize(baseDir); for (const recordPath of getRecordFileCandidates(normalizedBase)) { if (!existsSync(recordPath)) { continue; } try { const content = readFileSync(recordPath, "utf8"); const parsed = JSON.parse(content); if (!parsed || typeof parsed.tailwindPackagePath !== "string") { warnInvalidPatchTargetRecord(normalizedBase, recordPath, "\u7F3A\u5C11 tailwindPackagePath \u5B57\u6BB5"); continue; } return { baseDir: normalizedBase, path: recordPath, record: parsed }; } catch (error) { const reason = error instanceof Error ? error.message : String(error); warnInvalidPatchTargetRecord(normalizedBase, recordPath, reason); continue; } } return void 0; } async function saveCliPatchTargetRecord(baseDir, patcher, options) { if (!baseDir || !patcher?.packageInfo?.rootPath) { return void 0; } const normalizedBase = path.normalize(baseDir); const location = resolveRecordLocation(normalizedBase); const recordPath = options?.recordPath ? path.normalize(options.recordPath) : location.recordPath; const record = { tailwindPackagePath: path.normalize(patcher.packageInfo.rootPath), packageVersion: patcher.packageInfo.version, recordedAt: (/* @__PURE__ */ new Date()).toISOString(), source: options?.source ?? "cli", tailwindcssBasedir: normalizedBase, cwd: options?.cwd ? path.normalize(options.cwd) : normalizedBase, patchVersion: WEAPP_TW_VERSION, packageJsonPath: options?.packageJsonPath ?? location.packageJsonPath, recordKey: options?.recordKey ?? location.recordKey }; try { await mkdir(path.dirname(recordPath), { recursive: true }); await writeFile(recordPath, `${JSON.stringify(record, null, 2)} `, "utf8"); return recordPath; } catch (error) { const baseDisplay = formatRelativeToBase(normalizedBase, process.cwd()); logger.warn( '\u81EA\u52A8\u66F4\u65B0 Tailwind CSS \u8865\u4E01\u8BB0\u5F55\u5931\u8D25\uFF0C\u8BF7\u5728 %s \u8FD0\u884C "weapp-tw patch --cwd %s"\u3002', baseDisplay, normalizedBase ); logger.debug("failed to persist patch target record %s: %O", recordPath, error); return void 0; } } function findPatchTargetRecord(baseDir) { const visited = /* @__PURE__ */ new Set(); const fallback = baseDir ?? process.cwd(); let current = path.resolve(fallback); while (!visited.has(current)) { const record = readPatchTargetRecord(current); if (record) { return record; } const parent = path.dirname(current); if (parent === current) { break; } visited.add(current); current = parent; } return void 0; } function createPatchTargetRecorder(baseDir, patcher, options) { if (!baseDir || !patcher?.packageInfo?.rootPath || options?.recordTarget === false) { return void 0; } const normalizedBase = path.normalize(baseDir); const recorded = findPatchTargetRecord(normalizedBase); const location = resolveRecordLocation(normalizedBase); const expectedPath = path.normalize(patcher.packageInfo.rootPath); let reason; if (!recorded) { reason = "missing"; } else { const normalizedRecorded = path.normalize(recorded.record.tailwindPackagePath); if (normalizedRecorded !== expectedPath) { reason = "mismatch"; } else if (path.normalize(recorded.path) !== path.normalize(location.recordPath) || !recorded.record.recordKey || recorded.record.recordKey !== location.recordKey) { reason = "migrate"; } else if (!recorded.record.patchVersion || recorded.record.patchVersion !== WEAPP_TW_VERSION) { reason = "stale"; } else if (options?.cwd && recorded.record.cwd && path.normalize(recorded.record.cwd) !== path.normalize(options.cwd)) { reason = "metadata"; } else if (!recorded.record.cwd && options?.cwd) { reason = "metadata"; } } const shouldPersist = options?.alwaysRecord || !recorded || Boolean(reason); if (!shouldPersist) { return void 0; } let message; switch (reason) { case "mismatch": message = "\u68C0\u6D4B\u5230 Tailwind CSS \u76EE\u6807\u8BB0\u5F55\u4E0E\u5F53\u524D\u89E3\u6790\u7ED3\u679C\u4E0D\u4E00\u81F4\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u65B0 patch \u5E76\u5237\u65B0\u7F13\u5B58\u3002"; break; case "migrate": case "stale": message = "\u6B63\u5728\u5237\u65B0\u5F53\u524D\u5B50\u5305\u7684 Tailwind CSS \u8865\u4E01\u8BB0\u5F55\uFF0C\u786E\u4FDD\u7F13\u5B58\u9694\u79BB\u3002"; break; case "missing": message = "\u672A\u627E\u5230\u5F53\u524D\u5B50\u5305\u7684 Tailwind CSS \u76EE\u6807\u8BB0\u5F55\uFF0C\u6B63\u5728\u751F\u6210\u3002"; break; default: break; } const onPatched = async () => saveCliPatchTargetRecord(normalizedBase, patcher, { cwd: options?.cwd ?? normalizedBase, source: options?.source ?? "cli", recordPath: location.recordPath, recordKey: location.recordKey, packageJsonPath: location.packageJsonPath }); return { recordPath: location.recordPath, message, reason, onPatched }; } // src/context/compiler-context-cache.ts import { Buffer } from "buffer"; import { logger as logger2 } from "@weapp-tailwindcss/logger"; var globalCacheHolder = globalThis; var compilerContextCache = globalCacheHolder.__WEAPP_TW_COMPILER_CONTEXT_CACHE__ ?? (globalCacheHolder.__WEAPP_TW_COMPILER_CONTEXT_CACHE__ = /* @__PURE__ */ new Map()); function compareNormalizedValues(a, b) { const aStr = JSON.stringify(a); const bStr = JSON.stringify(b); return aStr.localeCompare(bStr); } function withCircularGuard(value, stack, factory) { if (stack.has(value)) { throw new TypeError("Cannot serialize circular structure in compiler context options"); } stack.add(value); try { return factory(); } finally { stack.delete(value); } } function encodeTaggedValue(type, value) { const record = { __type: type }; if (value !== void 0) { record.value = value; } return record; } function normalizeOptionsValue(rawValue, stack = /* @__PURE__ */ new WeakSet()) { if (rawValue === null) { return null; } if (rawValue === void 0) { return encodeTaggedValue("Undefined"); } const type = typeof rawValue; if (type === "string") { return rawValue; } if (type === "boolean") { return rawValue; } if (type === "number") { const numericValue = rawValue; if (Number.isNaN(numericValue)) { return encodeTaggedValue("Number", "NaN"); } if (!Number.isFinite(numericValue)) { return encodeTaggedValue("Number", numericValue > 0 ? "Infinity" : "-Infinity"); } if (Object.is(numericValue, -0)) { return encodeTaggedValue("Number", "-0"); } return numericValue; } if (type === "bigint") { return encodeTaggedValue("BigInt", rawValue.toString()); } if (type === "symbol") { const symbolValue = rawValue; return encodeTaggedValue("Symbol", symbolValue.description ?? String(symbolValue)); } if (type === "function") { return encodeTaggedValue("Function", rawValue.toString()); } if (Array.isArray(rawValue)) { return withCircularGuard(rawValue, stack, () => rawValue.map((item) => normalizeOptionsValue(item, stack))); } if (rawValue instanceof Date) { return encodeTaggedValue("Date", rawValue.toISOString()); } if (rawValue instanceof RegExp) { return { __type: "RegExp", source: rawValue.source, flags: rawValue.flags }; } if (typeof Buffer !== "undefined" && Buffer.isBuffer(rawValue)) { return encodeTaggedValue("Buffer", rawValue.toString("base64")); } if (ArrayBuffer.isView(rawValue)) { const view = rawValue; const buffer = Buffer.from(view.buffer, view.byteOffset, view.byteLength); return encodeTaggedValue(view.constructor?.name ?? "ArrayBufferView", buffer.toString("base64")); } if (rawValue instanceof ArrayBuffer) { return encodeTaggedValue("ArrayBuffer", Buffer.from(rawValue).toString("base64")); } if (rawValue instanceof Set) { return withCircularGuard(rawValue, stack, () => { const normalizedEntries = Array.from(rawValue, (element) => normalizeOptionsValue(element, stack)); normalizedEntries.sort(compareNormalizedValues); return { __type: "Set", value: normalizedEntries }; }); } if (rawValue instanceof Map) { return withCircularGuard(rawValue, stack, () => { const normalizedEntries = Array.from(rawValue.entries()).map(([key, entryValue]) => ({ key: normalizeOptionsValue(key, stack), value: normalizeOptionsValue(entryValue, stack) })); normalizedEntries.sort((a, b) => compareNormalizedValues(a.key, b.key)); return { __type: "Map", value: normalizedEntries.map((entry) => [entry.key, entry.value]) }; }); } if (typeof URL !== "undefined" && rawValue instanceof URL) { return encodeTaggedValue("URL", rawValue.toString()); } if (rawValue instanceof Error) { const errorValue = rawValue; return { __type: "Error", name: errorValue.name, message: errorValue.message, stack: errorValue.stack ?? "" }; } if (rawValue instanceof Promise) { return encodeTaggedValue("Promise"); } if (rawValue instanceof WeakMap) { return encodeTaggedValue("WeakMap"); } if (rawValue instanceof WeakSet) { return encodeTaggedValue("WeakSet"); } if (rawValue && typeof rawValue === "object") { return withCircularGuard(rawValue, stack, () => { const result = {}; const entries = Object.entries(rawValue); entries.sort(([a], [b]) => a.localeCompare(b)); for (const [key, entryValue] of entries) { result[key] = normalizeOptionsValue(entryValue, stack); } return result; }); } return encodeTaggedValue(typeof rawValue, String(rawValue)); } function createCompilerContextCacheKey(opts) { try { const normalized = normalizeOptionsValue(opts ?? {}); const serialized = JSON.stringify(normalized); return md5(serialized); } catch (error) { logger2.debug("skip compiler context cache: %O", error); return void 0; } } function withCompilerContextCache(opts, factory) { const cacheKey = createCompilerContextCacheKey(opts); if (cacheKey) { const cached = compilerContextCache.get(cacheKey); if (cached) { return cached; } } const ctx = factory(); if (cacheKey) { compilerContextCache.set(cacheKey, ctx); } return ctx; } // src/context/custom-attributes.ts function toCustomAttributesEntities(customAttributes) { if (!customAttributes) { return []; } if (isMap(customAttributes)) { return [ ...customAttributes.entries() ]; } return Object.entries(customAttributes); } // src/context/handlers.ts import { createStyleHandler } from "@weapp-tailwindcss/postcss"; // src/js/babel.ts import { LRUCache as LRUCache2 } from "lru-cache"; import MagicString from "magic-string"; // src/babel/index.ts import _babelTraverse from "@babel/traverse"; import { parse, parseExpression } from "@babel/parser"; function _interopDefaultCompat(e) { return e && typeof e === "object" && "default" in e ? e.default : e; } var traverse = _interopDefaultCompat(_babelTraverse); // src/utils/nameMatcher.ts import { escapeStringRegexp } from "@weapp-core/regex"; function buildFuzzyMatcher(fuzzyStrings) { if (fuzzyStrings.length === 0) { return void 0; } if (fuzzyStrings.length === 1) { const [needle] = fuzzyStrings; return (value) => value.includes(needle); } const unique = [...new Set(fuzzyStrings)]; const pattern = new RegExp(unique.map(escapeStringRegexp).join("|")); return (value) => pattern.test(value); } function normaliseRegex(regex) { const { source, flags } = regex; if (!flags.includes("g")) { return regex; } return new RegExp(source, flags.replace(/g/g, "")); } function createNameMatcher(list, { exact = false } = {}) { if (!list || list.length === 0) { return () => false; } const exactStrings = exact ? /* @__PURE__ */ new Set() : void 0; const fuzzyStrings = []; const regexList = []; for (const item of list) { if (typeof item === "string") { if (exact) { exactStrings.add(item); } else { fuzzyStrings.push(item); } } else { regexList.push(normaliseRegex(item)); } } const fuzzyMatcher = exact ? void 0 : buildFuzzyMatcher(fuzzyStrings); const hasRegex = regexList.length > 0; return (value) => { if (exact && exactStrings?.has(value)) { return true; } if (fuzzyMatcher?.(value)) { return true; } if (!hasRegex) { return false; } return regexList.some((regex) => regex.test(value)); }; } // src/js/evalTransforms.ts import { jsStringEscape } from "@ast-core/escape"; function isEvalPath(path2) { if (path2.isCallExpression()) { const calleePath = path2.get("callee"); return calleePath.isIdentifier({ name: "eval" }); } return false; } function createEvalReplacementToken(path2, updated) { const node = path2.node; let offset = 0; let original; if (path2.isStringLiteral()) { offset = 1; original = path2.node.value; } else if (path2.isTemplateElement()) { original = path2.node.value.raw; } else { original = ""; } if (typeof node.start !== "number" || typeof node.end !== "number") { return void 0; } const start = node.start + offset; const end = node.end - offset; if (start >= end) { return void 0; } if (original === updated) { return void 0; } const value = path2.isStringLiteral() ? jsStringEscape(updated) : updated; return { start, end, value, path: path2 }; } function handleEvalStringLiteral(path2, options, updater, handler) { const { code } = handler(path2.node.value, { ...options, needEscaped: false, generateMap: false }); if (!code) { return; } const token = createEvalReplacementToken(path2, code); if (token) { updater.addToken(token); } } function handleEvalTemplateElement(path2, options, updater, handler) { const { code } = handler(path2.node.value.raw, { ...options, generateMap: false }); if (!code) { return; } const token = createEvalReplacementToken(path2, code); if (token) { updater.addToken(token); } } function walkEvalExpression(path2, options, updater, handler) { const maybeTraverse = path2?.traverse; if (typeof maybeTraverse === "function") { try { return maybeTraverse.call(path2, { StringLiteral(innerPath) { handleEvalStringLiteral(innerPath, options, updater, handler); }, TemplateElement(innerPath) { handleEvalTemplateElement(innerPath, options, updater, handler); } }); } catch (error) { const msg = error?.message ?? ""; const scopeError = /pass a scope and parentPath|traversing a Program\/File/i.test(msg); if (!scopeError) { throw error; } } } const getArgs = path2?.get?.("arguments"); if (Array.isArray(getArgs)) { for (const arg of getArgs) { if (arg?.isStringLiteral?.()) { handleEvalStringLiteral(arg, options, updater, handler); continue; } if (arg?.isTemplateLiteral?.()) { for (const quasi of arg.get("quasis")) { handleEvalTemplateElement(quasi, options, updater, handler); } } } return; } const nodeArgs = path2?.node?.arguments; if (Array.isArray(nodeArgs)) { for (const n of nodeArgs) { if (n?.type === "StringLiteral") { const stub = { node: n, isStringLiteral: () => true }; handleEvalStringLiteral(stub, options, updater, handler); } else if (n?.type === "TemplateLiteral" && Array.isArray(n.quasis)) { for (const q of n.quasis) { const stub = { node: q, isTemplateElement: () => true }; handleEvalTemplateElement(stub, options, updater, handler); } } } } } // src/js/handlers.ts import { jsStringEscape as jsStringEscape2 } from "@ast-core/escape"; import { escapeStringRegexp as escapeStringRegexp2 } from "@weapp-core/regex"; import { splitCode } from "@weapp-tailwindcss/shared/extractors"; // src/utils/decode.ts var unicodeEscapeRE = /\\u([\dA-Fa-f]{4})/g; var unicodeEscapeTestRE = /\\u[\dA-Fa-f]{4}/; function decodeUnicode(value) { if (!unicodeEscapeTestRE.test(value)) { return value; } return value.replace(unicodeEscapeRE, (_match, hex) => { const codePoint = Number.parseInt(hex, 16); return Number.isNaN(codePoint) ? _match : String.fromCharCode(codePoint); }); } function decodeUnicode2(input) { if (!unicodeEscapeTestRE.test(input)) { return input; } try { return JSON.parse(`"${input}"`); } catch (_error) { return decodeUnicode(input); } } // src/wxml/shared.ts import { escape, MappingChars2String } from "@weapp-core/escape"; function replaceWxml(original, options = { keepEOL: false, escapeMap: MappingChars2String }) { const { keepEOL, escapeMap, ignoreHead } = options; let res = original; if (!keepEOL) { res = res.replaceAll(/[\n\r]+/g, ""); } res = escape(res, { map: escapeMap, ignoreHead }); return res; } // src/js/handlers.ts var patternCache = /* @__PURE__ */ new Map(); var replacementCacheByEscapeMap = /* @__PURE__ */ new WeakMap(); var defaultReplacementCache = /* @__PURE__ */ new Map(); function getPattern(candidate) { let cached = patternCache.get(candidate); if (!cached) { cached = new RegExp(escapeStringRegexp2(candidate)); patternCache.set(candidate, cached); } return cached; } function getReplacement(candidate, escapeMap) { if (!escapeMap) { let cached2 = defaultReplacementCache.get(candidate); if (cached2 === void 0) { cached2 = replaceWxml(candidate, { escapeMap }); defaultReplacementCache.set(candidate, cached2); } return cached2; } let store = replacementCacheByEscapeMap.get(escapeMap); if (!store) { store = /* @__PURE__ */ new Map(); replacementCacheByEscapeMap.set(escapeMap, store); } let cached = store.get(candidate); if (cached === void 0) { cached = replaceWxml(candidate, { escapeMap }); store.set(candidate, cached); } return cached; } function hasIgnoreComment(node) { return Array.isArray(node.leadingComments) && node.leadingComments.some((comment) => comment.value.includes("weapp-tw") && comment.value.includes("ignore")); } function shouldTransformClassName(candidate, { alwaysEscape, classNameSet, jsPreserveClass }) { if (alwaysEscape) { return true; } if (!classNameSet) { return false; } if (!classNameSet.has(candidate)) { return false; } return !jsPreserveClass?.(candidate); } function extractLiteralValue(path2, { unescapeUnicode, arbitraryValues }) { const allowDoubleQuotes = arbitraryValues?.allowDoubleQuotes; let offset = 0; let original; if (path2.isStringLiteral()) { offset = 1; original = path2.node.value; } else if (path2.isTemplateElement()) { original = path2.node.value.raw; } else { original = ""; } let literal = original; if (unescapeUnicode && original.includes("\\u")) { literal = decodeUnicode2(original); } return { allowDoubleQuotes, literal, offset, original }; } function replaceHandleValue(path2, options) { const { escapeMap, needEscaped = false } = options; const { classNameSet, alwaysEscape } = options; if (!alwaysEscape && (!classNameSet || classNameSet.size === 0)) { return void 0; } const { literal, original, allowDoubleQuotes, offset } = extractLiteralValue(path2, options); if (hasIgnoreComment(path2.node)) { return void 0; } const candidates = splitCode(literal, allowDoubleQuotes); if (candidates.length === 0) { return void 0; } let transformed = literal; let mutated = false; for (const candidate of candidates) { if (!shouldTransformClassName(candidate, options)) { continue; } if (!transformed.includes(candidate)) { continue; } const pattern = getPattern(candidate); const replacement = getReplacement(candidate, escapeMap); const replaced = transformed.replace(pattern, replacement); if (replaced !== transformed) { transformed = replaced; mutated = true; } } const node = path2.node; if (!mutated || typeof node.start !== "number" || typeof node.end !== "number") { return void 0; } const start = node.start + offset; const end = node.end - offset; if (start >= end || transformed === original) { return void 0; } const value = needEscaped ? jsStringEscape2(transformed) : transformed; return { start, end, value, path: path2 }; } // src/js/JsTokenUpdater.ts var JsTokenUpdater = class { constructor({ value } = {}) { this.tokens = value ? [...value] : []; } addToken(token) { if (token) { this.tokens.push(token); } } push(...args) { this.tokens.push(...args); return this; } /** * 待写入的 token 数量。 */ get length() { return this.tokens.length; } map(callbackfn) { this.tokens = this.tokens.map(callbackfn); return this; } filter(callbackfn) { this.tokens = this.tokens.filter(callbackfn); return this; } updateMagicString(ms) { for (const { start, end, value } of this.tokens) { ms.update(start, end, value); } return ms; } }; // src/js/ModuleGraph.ts var JsModuleGraph = class { constructor(entry, graphOptions) { this.modules = /* @__PURE__ */ new Map(); this.queue = []; this.ignoredExportNames = /* @__PURE__ */ new Map(); this.resolve = graphOptions.resolve; this.load = graphOptions.load; this.filter = graphOptions.filter; this.maxDepth = graphOptions.maxDepth ?? Number.POSITIVE_INFINITY; const { moduleGraph: _moduleGraph, filename: _ignoredFilename, ...rest } = entry.handlerOptions; this.baseOptions = { ...rest, filename: entry.filename }; this.parserOptions = entry.handlerOptions.babelParserOptions; this.rootFilename = entry.filename; this.modules.set(entry.filename, { filename: entry.filename, source: entry.source, analysis: entry.analysis }); this.queue.push({ filename: entry.filename, depth: 0 }); } build() { this.collectDependencies(); const linked = {}; for (const [filename, state] of this.modules) { if (filename === this.rootFilename) { continue; } const childOptions = { ...this.baseOptions, filename }; const ms = processUpdatedSource(state.source, childOptions, state.analysis); const code = ms.toString(); if (code !== state.source) { linked[filename] = { code }; } } return linked; } addIgnoredExport(filename, exportName) { if (!exportName) { return; } let pending = this.ignoredExportNames.get(filename); if (!pending) { pending = /* @__PURE__ */ new Set(); this.ignoredExportNames.set(filename, pending); } if (pending.has(exportName)) { return; } pending.add(exportName); const existing = this.modules.get(filename); if (existing) { this.applyIgnoredExportsToAnalysis(filename, existing.analysis); } } registerIgnoredExportsFromTokens(resolved, tokens) { for (const token of tokens) { if (token.type === "ImportSpecifier") { this.addIgnoredExport(resolved, token.imported); } else if (token.type === "ImportDefaultSpecifier") { this.addIgnoredExport(resolved, "default"); } } } applyIgnoredExportsToAnalysis(filename, analysis) { const pending = this.ignoredExportNames.get(filename); if (!pending || pending.size === 0) { return; } const names = new Set(pending); pending.clear(); const propagate = []; for (const exportPath of analysis.exportDeclarations) { if (names.size === 0) { break; } if (exportPath.isExportDefaultDeclaration()) { if (names.has("default")) { analysis.walker.walkExportDefaultDeclaration(exportPath); names.delete("default"); } continue; } if (exportPath.isExportNamedDeclaration()) { const source = exportPath.node.source?.value; if (typeof source === "string") { for (const spec of exportPath.get("specifiers")) { if (!spec.isExportSpecifier()) { continue; } const exported = spec.get("exported"); let exportedName; if (exported.isIdentifier()) { exportedName = exported.node.name; } else if (exported.isStringLiteral()) { exportedName = exported.node.value; } if (!exportedName || !names.has(exportedName)) { continue; } const local = spec.get("local"); if (local.isIdentifier()) { propagate.push({ specifier: source, exportName: local.node.name }); names.delete(exportedName); } else if (local.isStringLiteral()) { propagate.push({ specifier: source, exportName: local.node.value }); names.delete(exportedName); } } continue; } const declaration = exportPath.get("declaration"); if (declaration.isVariableDeclaration()) { for (const decl of declaration.get("declarations")) { const id = decl.get("id"); if (id.isIdentifier()) { const exportName = id.node.name; if (names.has(exportName)) { analysis.walker.walkVariableDeclarator(decl); names.delete(exportName); } } } } for (const spec of exportPath.get("specifiers")) { if (!spec.isExportSpecifier()) { continue; } const exported = spec.get("exported"); let exportedName; if (exported.isIdentifier()) { exportedName = exported.node.name; } else if (exported.isStringLiteral()) { exportedName = exported.node.value; } if (!exportedName || !names.has(exportedName)) { continue; } const local = spec.get("local"); analysis.walker.walkNode(local); names.delete(exportedName); } continue; } if (exportPath.isExportAllDeclaration()) { const source = exportPath.node.source?.value; if (typeof source === "string") { for (const exportName of names) { propagate.push({ specifier: source, exportName }); } names.clear(); } } } for (const { specifier, exportName } of propagate) { let resolved; try { resolved = this.resolve(specifier, filename); } catch { resolved = void 0; } if (!resolved) { pending.add(exportName); continue; } if (this.filter && !this.filter(resolved, specifier, filename)) { pending.add(exportName); continue; } this.addIgnoredExport(resolved, exportName); } for (const name of names) { pending.add(name); } } collectDependencies() { while (this.queue.length > 0) { const { filename, depth } = this.queue.shift(); if (depth >= this.maxDepth) { continue; } const state = this.modules.get(filename); if (!state) { continue; } const dependencySpecifiers = /* @__PURE__ */ new Map(); for (const token of state.analysis.walker.imports) { if (!dependencySpecifiers.has(token.source)) { dependencySpecifiers.set(token.source, []); } dependencySpecifiers.get(token.source).push(token); } for (const exportPath of state.analysis.exportDeclarations) { if (exportPath.isExportAllDeclaration() || exportPath.isExportNamedDeclaration()) { const source = exportPath.node.source?.value; if (typeof source === "string" && !dependencySpecifiers.has(source)) { dependencySpecifiers.set(source, []); } } } for (const [specifier, tokens] of dependencySpecifiers) { let resolved; try { resolved = this.resolve(specifier, filename); } catch { continue; } if (!resolved) { continue; } if (this.filter && !this.filter(resolved, specifier, filename)) { continue; } if (tokens.length > 0) { this.registerIgnoredExportsFromTokens(resolved, tokens); } if (this.modules.has(resolved)) { continue; } let source; try { source = this.load(resolved); } catch { continue; } if (typeof source !== "string") { continue; } let analysis; try { const ast = babelParse(source, { ...this.parserOptions, sourceFilename: resolved }); analysis = analyzeSource(ast, { ...this.baseOptions, filename: resolved }); this.applyIgnoredExportsToAnalysis(resolved, analysis); } catch { continue; } this.modules.set(resolved, { filename: resolved, source, analysis }); this.queue.push({ filename: resolved, depth: depth + 1 }); } } } }; // src/js/NodePathWalker.ts var NodePathWalker = class { constructor({ ignoreCallExpressionIdentifiers, callback } = {}) { this.ignoreCallExpressionIdentifiers = ignoreCallExpressionIdentifiers ?? []; this.callback = callback ?? (() => { }); this.imports = /* @__PURE__ */ new Set(); this.visited = /* @__PURE__ */ new WeakSet(); this.isIgnoredCallIdentifier = createNameMatcher(this.ignoreCallExpressionIdentifiers, { exact: true }); } walkVariableDeclarator(path2) { const init = path2.get("init"); this.walkNode(init); } walkTemplateLiteral(path2) { for (const exp of path2.get("expressions")) { this.walkNode(exp); } for (const quasis of path2.get("quasis")) { this.callback(quasis); } } walkStringLiteral(path2) { this.callback(path2); } walkBinaryExpression(path2) { const left = path2.get("left"); this.walkNode(left); const right = path2.get("right"); this.walkNode(right); } walkLogicalExpression(path2) { const left = path2.get("left"); this.walkNode(left); const right = path2.get("right"); this.walkNode(right); } walkObjectExpression(path2) { const props = path2.get("properties"); for (const prop of props) { if (prop.isObjectProperty()) { const key = prop.get("key"); this.walkNode(key); const value = prop.get("value"); this.walkNode(value); } } } walkArrayExpression(path2) { const elements = path2.get("elements"); for (const element of elements) { this.walkNode(element); } } walkNode(arg) { if (this.visited.has(arg)) { return; } this.visited.add(arg); if (arg.isIdentifier()) { const binding = arg?.scope?.getBinding?.(arg.node.name); if (binding) { this.walkNode(binding.path); } } else if (arg.isMemberExpression()) { const objectPath = arg.get("object"); if (objectPath.isIdentifier()) { const binding = arg?.scope?.getBinding?.(objectPath.node.name); if (binding) { if (binding.path.isVariableDeclarator()) { this.wal