Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022-PRESENT Kevin Deng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,124 @@
import { CodeTransform, MagicString, MagicStringAST } from "magic-string-ast";
import { FilterPattern, FilterPattern as FilterPattern$1, createFilter as createRollupFilter, normalizePath } from "unplugin-utils";
import { SFCDescriptor, SFCParseResult, SFCScriptBlock as SFCScriptBlock$1 } from "@vue/compiler-sfc";
import * as t from "@babel/types";
import { Node, Program } from "@babel/types";
import { ResolvedOptions } from "@vitejs/plugin-vue";
import { Plugin } from "rollup";
import { HmrContext, Plugin as Plugin$1 } from "vite";
export * from "magic-string-ast";
export * from "ast-kit";
//#region src/ast.d.ts
declare function checkInvalidScopeReference(node: t.Node | undefined, method: string, setupBindings: string[]): void;
declare function isStaticExpression(node: t.Node, options?: Partial<Record<"object" | "fn" | "objectMethod" | "array" | "unary" | "regex", boolean> & {
magicComment?: string;
}>): boolean;
declare function isStaticObjectKey(node: t.ObjectExpression): boolean;
/**
* @param node must be a static expression, SpreadElement is not supported
*/
declare function resolveObjectExpression(node: t.ObjectExpression): Record<string | number, t.ObjectMethod | t.ObjectProperty> | undefined;
declare const HELPER_PREFIX = "__MACROS_";
declare function importHelperFn(s: MagicString, offset: number, imported: string, local?: string, from?: string): string;
//#endregion
//#region src/constants.d.ts
declare const DEFINE_PROPS = "defineProps";
declare const DEFINE_PROPS_DOLLAR = "$defineProps";
declare const DEFINE_PROPS_REFS = "definePropsRefs";
declare const DEFINE_EMITS = "defineEmits";
declare const WITH_DEFAULTS = "withDefaults";
declare const DEFINE_OPTIONS = "defineOptions";
declare const DEFINE_MODELS = "defineModels";
declare const DEFINE_MODELS_DOLLAR = "$defineModels";
declare const DEFINE_SETUP_COMPONENT = "defineSetupComponent";
declare const DEFINE_RENDER = "defineRender";
declare const DEFINE_SLOTS = "defineSlots";
declare const DEFINE_STYLEX = "defineStyleX";
declare const DEFINE_PROP = "defineProp";
declare const DEFINE_PROP_DOLLAR = "$defineProp";
declare const DEFINE_EMIT = "defineEmit";
declare const REPO_ISSUE_URL: "https://github.com/vue-macros/vue-macros/issues";
declare const REGEX_SRC_FILE: RegExp;
declare const REGEX_SETUP_SFC: RegExp;
declare const REGEX_SETUP_SFC_SUB: RegExp;
declare const REGEX_VUE_SFC: RegExp;
/** webpack only */
declare const REGEX_VUE_SUB: RegExp;
/** webpack only */
declare const REGEX_VUE_SUB_SETUP: RegExp;
declare const REGEX_NODE_MODULES: RegExp;
declare const REGEX_SUPPORTED_EXT: RegExp;
declare const VIRTUAL_ID_PREFIX = "/vue-macros";
//#endregion
//#region src/dep.d.ts
declare function detectVueVersion(root?: string, defaultVersion?: number): number;
//#endregion
//#region src/error.d.ts
declare class TransformError<T extends string> extends SyntaxError {
message: T;
constructor(message: T);
}
//#endregion
//#region src/unplugin.d.ts
interface FilterOptions {
include?: FilterPattern$1;
exclude?: FilterPattern$1;
}
declare function createFilter(options: FilterOptions): (id: string | unknown) => boolean;
interface VuePluginApi {
options: ResolvedOptions;
version: string;
}
declare function getVuePluginApi(plugins: Readonly<(Plugin | Plugin$1)[]> | undefined): VuePluginApi | null;
declare enum FilterFileType {
/** Vue SFC */
VUE_SFC = 0,
/** Vue SFC with `<script setup>` */
VUE_SFC_WITH_SETUP = 1,
/** foo.setup.tsx */
SETUP_SFC = 2,
/** Source files */
SRC_FILE = 3,
}
declare function getFilterPattern(types: FilterFileType[], framework?: string): RegExp[];
declare function hackViteHMR(ctx: HmrContext, filter: (id: string | unknown) => boolean, callback: (code: string, id: string) => CodeTransform | undefined | Promise<CodeTransform | undefined>): void;
//#endregion
//#region src/options.d.ts
interface BaseOptions extends FilterOptions {
version?: number;
isProduction?: boolean;
}
//#endregion
//#region src/types.d.ts
type MarkRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;
type RecordToUnion<T extends Record<string, any>> = T[keyof T];
type UnionToIntersection<U> = (U extends unknown ? (arg: U) => 0 : never) extends ((arg: infer I) => 0) ? I : never;
//#endregion
//#region src/vue.d.ts
type SFCScriptBlock = Omit<SFCScriptBlock$1, "scriptAst" | "scriptSetupAst">;
type SFC = Omit<SFCDescriptor, "script" | "scriptSetup"> & {
sfc: SFCParseResult;
script?: SFCScriptBlock | null;
scriptSetup?: SFCScriptBlock | null;
lang: string | undefined;
getScriptAst: () => Program | undefined;
getSetupAst: () => Program | undefined;
offset: number;
} & Pick<SFCParseResult, "errors">;
declare function parseSFC(code: string, id: string): SFC;
declare function getFileCodeAndLang(code: string, id: string): {
code: string;
lang: string;
};
declare function addNormalScript({
script,
lang
}: SFC, s: MagicString): {
start(): number;
end(): void;
};
declare function removeMacroImport(node: Node, s: MagicStringAST, offset: number): true | undefined;
//#endregion
export { BaseOptions, DEFINE_EMIT, DEFINE_EMITS, DEFINE_MODELS, DEFINE_MODELS_DOLLAR, DEFINE_OPTIONS, DEFINE_PROP, DEFINE_PROPS, DEFINE_PROPS_DOLLAR, DEFINE_PROPS_REFS, DEFINE_PROP_DOLLAR, DEFINE_RENDER, DEFINE_SETUP_COMPONENT, DEFINE_SLOTS, DEFINE_STYLEX, FilterFileType, FilterOptions, type FilterPattern, HELPER_PREFIX, MarkRequired, Overwrite, REGEX_NODE_MODULES, REGEX_SETUP_SFC, REGEX_SETUP_SFC_SUB, REGEX_SRC_FILE, REGEX_SUPPORTED_EXT, REGEX_VUE_SFC, REGEX_VUE_SUB, REGEX_VUE_SUB_SETUP, REPO_ISSUE_URL, RecordToUnion, SFC, SFCScriptBlock, TransformError, UnionToIntersection, VIRTUAL_ID_PREFIX, VuePluginApi, WITH_DEFAULTS, addNormalScript, checkInvalidScopeReference, createFilter, createRollupFilter, detectVueVersion, getFileCodeAndLang, getFilterPattern, getVuePluginApi, hackViteHMR, importHelperFn, isStaticExpression, isStaticObjectKey, normalizePath, parseSFC, removeMacroImport, resolveObjectExpression };

View file

@ -0,0 +1,257 @@
import { babelParse, getLang, isFunctionType, isLiteralType, resolveObjectKey, resolveString } from "ast-kit";
import { createFilter as createFilter$1, createFilter as createRollupFilter, normalizePath } from "unplugin-utils";
import { parse, walkIdentifiers } from "@vue/compiler-sfc";
export * from "magic-string-ast"
export * from "ast-kit"
//#region src/ast.ts
function checkInvalidScopeReference(node, method, setupBindings) {
if (!node) return;
walkIdentifiers(node, (id) => {
if (setupBindings.includes(id.name)) throw new SyntaxError(`\`${method}()\` in <script setup> cannot reference locally declared variables (${id.name}) because it will be hoisted outside of the setup() function.`);
});
}
function isStaticExpression(node, options = {}) {
const { magicComment, fn, object, objectMethod, array, unary, regex } = options;
if (magicComment && node.leadingComments?.some((comment) => comment.value.trim() === magicComment)) return true;
else if (fn && isFunctionType(node)) return true;
switch (node.type) {
case "UnaryExpression": return !!unary && isStaticExpression(node.argument, options);
case "LogicalExpression":
case "BinaryExpression": return isStaticExpression(node.left, options) && isStaticExpression(node.right, options);
case "ConditionalExpression": return isStaticExpression(node.test, options) && isStaticExpression(node.consequent, options) && isStaticExpression(node.alternate, options);
case "SequenceExpression":
case "TemplateLiteral": return node.expressions.every((expr) => isStaticExpression(expr, options));
case "ArrayExpression": return !!array && node.elements.every((element) => element && isStaticExpression(element, options));
case "ObjectExpression": return !!object && node.properties.every((prop) => {
if (prop.type === "SpreadElement") return prop.argument.type === "ObjectExpression" && isStaticExpression(prop.argument, options);
else if (!isLiteralType(prop.key) && prop.computed) return false;
else if (prop.type === "ObjectProperty" && !isStaticExpression(prop.value, options)) return false;
if (prop.type === "ObjectMethod" && !objectMethod) return false;
return true;
});
case "ParenthesizedExpression":
case "TSNonNullExpression":
case "TSAsExpression":
case "TSTypeAssertion":
case "TSSatisfiesExpression": return isStaticExpression(node.expression, options);
case "RegExpLiteral": return !!regex;
}
if (isLiteralType(node)) return true;
return false;
}
function isStaticObjectKey(node) {
return node.properties.every((prop) => {
if (prop.type === "SpreadElement") return prop.argument.type === "ObjectExpression" && isStaticObjectKey(prop.argument);
return !prop.computed || isLiteralType(prop.key);
});
}
/**
* @param node must be a static expression, SpreadElement is not supported
*/
function resolveObjectExpression(node) {
const maps = Object.create(null);
for (const property of node.properties) if (property.type === "SpreadElement") {
if (property.argument.type !== "ObjectExpression") return void 0;
Object.assign(maps, resolveObjectExpression(property.argument));
} else {
const key = resolveObjectKey(property);
maps[key] = property;
}
return maps;
}
const importedMap = /* @__PURE__ */ new WeakMap();
const HELPER_PREFIX = "__MACROS_";
function importHelperFn(s, offset, imported, local = imported, from = "vue") {
const cacheKey = `${from}@${imported}`;
if (!importedMap.get(s)?.has(cacheKey)) {
s.appendLeft(offset, `\nimport ${imported === "default" ? HELPER_PREFIX + local : `{ ${imported} as ${HELPER_PREFIX + local} }`} from ${JSON.stringify(from)};`);
if (importedMap.has(s)) importedMap.get(s).add(cacheKey);
else importedMap.set(s, new Set([cacheKey]));
}
return `${HELPER_PREFIX}${local}`;
}
//#endregion
//#region src/constants.ts
const DEFINE_PROPS = "defineProps";
const DEFINE_PROPS_DOLLAR = "$defineProps";
const DEFINE_PROPS_REFS = "definePropsRefs";
const DEFINE_EMITS = "defineEmits";
const WITH_DEFAULTS = "withDefaults";
const DEFINE_OPTIONS = "defineOptions";
const DEFINE_MODELS = "defineModels";
const DEFINE_MODELS_DOLLAR = "$defineModels";
const DEFINE_SETUP_COMPONENT = "defineSetupComponent";
const DEFINE_RENDER = "defineRender";
const DEFINE_SLOTS = "defineSlots";
const DEFINE_STYLEX = "defineStyleX";
const DEFINE_PROP = "defineProp";
const DEFINE_PROP_DOLLAR = "$defineProp";
const DEFINE_EMIT = "defineEmit";
const REPO_ISSUE_URL = `https://github.com/vue-macros/vue-macros/issues`;
const REGEX_SRC_FILE = /\.[cm]?[jt]sx?$/;
const REGEX_SETUP_SFC = /\.setup\.[cm]?[jt]sx?$/;
const REGEX_SETUP_SFC_SUB = /\.setup\.[cm]?[jt]sx?((?!(?<!definePage&)vue&).)*$/;
const REGEX_VUE_SFC = /\.vue$/;
/** webpack only */
const REGEX_VUE_SUB = /\.vue(\.[tj]sx?)?\?vue&type=script/;
/** webpack only */
const REGEX_VUE_SUB_SETUP = /\.vue(\.[tj]sx?)?\?vue&type=script\b.+\bsetup=true/;
const REGEX_NODE_MODULES = /node_modules/;
const REGEX_SUPPORTED_EXT = /\.([cm]?[jt]sx?|vue)$/;
const VIRTUAL_ID_PREFIX = "/vue-macros";
//#endregion
//#region src/dep.ts
let require;
function getRequire() {
if (require) return require;
try {
if (globalThis.process?.getBuiltinModule) {
const module = process.getBuiltinModule("node:module");
if (module?.createRequire) return require = module.createRequire(import.meta.url);
}
} catch {}
}
function detectVueVersion(root, defaultVersion = 3.5) {
const require$1 = getRequire();
if (!require$1) {
console.warn(`Cannot detect Vue version. Default to Vue ${defaultVersion}`);
return defaultVersion;
}
const { resolve } = require$1("node:path");
const { statSync } = require$1("node:fs");
const { getPackageInfoSync } = require$1("local-pkg");
root ||= process.cwd();
let isFile = false;
try {
isFile = statSync(root).isFile();
} catch {}
const paths = [root];
if (!isFile) paths.unshift(resolve(root, "_index.js"));
const vuePkg = getPackageInfoSync("vue", { paths });
if (vuePkg && vuePkg.version) {
const version = Number.parseFloat(vuePkg.version);
return version >= 2 && version < 3 ? Math.trunc(version) : version;
} else return defaultVersion;
}
//#endregion
//#region src/error.ts
var TransformError = class extends SyntaxError {
constructor(message) {
super(message);
this.message = message;
this.name = "TransformError";
}
};
//#endregion
//#region src/unplugin.ts
function createFilter(options) {
return createFilter$1(options.include, options.exclude);
}
const VUE_PLUGINS = new Set(["vite:vue", "unplugin-vue"]);
function getVuePluginApi(plugins) {
const vuePlugin = (plugins || []).find((p) => VUE_PLUGINS.has(p.name));
if (!vuePlugin) throw new Error("Cannot find Vue plugin (@vitejs/plugin-vue or unplugin-vue). Please make sure to add it before using Vue Macros.");
const api = vuePlugin.api;
if (!api?.version) throw new Error("The Vue plugin is not supported (@vitejs/plugin-vue or unplugin-vue). Please make sure version > 4.3.4.");
return api;
}
let FilterFileType = /* @__PURE__ */ function(FilterFileType$1) {
/** Vue SFC */
FilterFileType$1[FilterFileType$1["VUE_SFC"] = 0] = "VUE_SFC";
/** Vue SFC with `<script setup>` */
FilterFileType$1[FilterFileType$1["VUE_SFC_WITH_SETUP"] = 1] = "VUE_SFC_WITH_SETUP";
/** foo.setup.tsx */
FilterFileType$1[FilterFileType$1["SETUP_SFC"] = 2] = "SETUP_SFC";
/** Source files */
FilterFileType$1[FilterFileType$1["SRC_FILE"] = 3] = "SRC_FILE";
return FilterFileType$1;
}({});
function getFilterPattern(types, framework) {
const filter = [];
const isWebpackLike = framework === "webpack" || framework === "rspack";
if (types.includes(FilterFileType.VUE_SFC)) filter.push(isWebpackLike ? REGEX_VUE_SUB : REGEX_VUE_SFC);
if (types.includes(FilterFileType.VUE_SFC_WITH_SETUP)) filter.push(isWebpackLike ? REGEX_VUE_SUB_SETUP : REGEX_VUE_SFC);
if (types.includes(FilterFileType.SETUP_SFC)) filter.push(REGEX_SETUP_SFC);
if (types.includes(FilterFileType.SRC_FILE)) filter.push(REGEX_SRC_FILE);
return filter;
}
function hackViteHMR(ctx, filter, callback) {
if (!filter(ctx.file)) return;
const { read } = ctx;
ctx.read = async () => {
const code = await read();
return (await callback(code, ctx.file))?.code || code;
};
}
//#endregion
//#region src/vue.ts
function parseSFC(code, id) {
const sfc = parse(code, { filename: id });
const { descriptor, errors } = sfc;
const scriptLang = sfc.descriptor.script?.lang;
const scriptSetupLang = sfc.descriptor.scriptSetup?.lang;
if (sfc.descriptor.script && sfc.descriptor.scriptSetup && (scriptLang || "js") !== (scriptSetupLang || "js")) throw new Error(`[vue-macros] <script> and <script setup> must have the same language type.`);
const lang = scriptLang || scriptSetupLang;
return Object.assign({}, descriptor, {
sfc,
lang,
errors,
offset: descriptor.scriptSetup?.loc.start.offset ?? 0,
getSetupAst() {
if (!descriptor.scriptSetup) return;
return babelParse(descriptor.scriptSetup.content, lang, {
plugins: [["importAttributes", { deprecatedAssertSyntax: true }]],
cache: true
});
},
getScriptAst() {
if (!descriptor.script) return;
return babelParse(descriptor.script.content, lang, {
plugins: [["importAttributes", { deprecatedAssertSyntax: true }]],
cache: true
});
}
});
}
function getFileCodeAndLang(code, id) {
if (!REGEX_VUE_SFC.test(id)) return {
code,
lang: getLang(id)
};
const sfc = parseSFC(code, id);
const scriptCode = sfc.script?.content ?? "";
return {
code: sfc.scriptSetup ? `${scriptCode}\n;\n${sfc.scriptSetup.content}` : scriptCode,
lang: sfc.lang ?? "js"
};
}
function addNormalScript({ script, lang }, s) {
return {
start() {
if (script) return script.loc.end.offset;
const attrs = lang ? ` lang="${lang}"` : "";
s.prependLeft(0, `<script${attrs}>`);
return 0;
},
end() {
if (!script) s.appendRight(0, `\n<\/script>\n`);
}
};
}
function removeMacroImport(node, s, offset) {
if (node.type === "ImportDeclaration" && node.attributes?.some((attr) => resolveString(attr.key) === "type" && attr.value.value === "macro")) {
s.removeNode(node, { offset });
return true;
}
}
//#endregion
export { DEFINE_EMIT, DEFINE_EMITS, DEFINE_MODELS, DEFINE_MODELS_DOLLAR, DEFINE_OPTIONS, DEFINE_PROP, DEFINE_PROPS, DEFINE_PROPS_DOLLAR, DEFINE_PROPS_REFS, DEFINE_PROP_DOLLAR, DEFINE_RENDER, DEFINE_SETUP_COMPONENT, DEFINE_SLOTS, DEFINE_STYLEX, FilterFileType, HELPER_PREFIX, REGEX_NODE_MODULES, REGEX_SETUP_SFC, REGEX_SETUP_SFC_SUB, REGEX_SRC_FILE, REGEX_SUPPORTED_EXT, REGEX_VUE_SFC, REGEX_VUE_SUB, REGEX_VUE_SUB_SETUP, REPO_ISSUE_URL, TransformError, VIRTUAL_ID_PREFIX, WITH_DEFAULTS, addNormalScript, checkInvalidScopeReference, createFilter, createRollupFilter, detectVueVersion, getFileCodeAndLang, getFilterPattern, getVuePluginApi, hackViteHMR, importHelperFn, isStaticExpression, isStaticObjectKey, normalizePath, parseSFC, removeMacroImport, resolveObjectExpression };

View file

@ -0,0 +1,43 @@
The MIT License (MIT)
Copyright © 2025-PRESENT Kevin Deng (https://github.com/sxzz)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The MIT License (MIT)
Copyright (c) 2019 RollupJS Plugin Contributors (https://github.com/rollup/plugins/graphs/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,74 @@
# unplugin-utils
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Unit Test][unit-test-src]][unit-test-href]
[![codecov][codecov-src]][codecov-href]
A set of utility functions commonly used by unplugins.
Thanks to [@rollup/pluginutils](https://github.com/rollup/plugins/tree/master/packages/pluginutils). This projects is heavily copied from it.
## Why Fork?
- 🌍 Platform agnostic, supports running in the browser, Node.js...
- ✂️ Subset, smaller bundle size.
- **💯 Coverage**: 100% test coverage.
## Install
```bash
npm i unplugin-utils
```
## Usage
### createFilter
```ts
export default function myPlugin(options = {}) {
const filter = createFilter(options.include, options.exclude)
return {
transform(code, id) {
if (!filter(id)) return
// proceed with the transformation...
},
}
}
```
### normalizePath
```ts
import { normalizePath } from 'unplugin-utils'
normalizePath(String.raw`foo\bar`) // 'foo/bar'
normalizePath('foo/bar') // 'foo/bar'
```
## Sponsors
<p align="center">
<a href="https://cdn.jsdelivr.net/gh/sxzz/sponsors/sponsors.svg">
<img src='https://cdn.jsdelivr.net/gh/sxzz/sponsors/sponsors.svg'/>
</a>
</p>
## License
[MIT](./LICENSE) License © 2025-PRESENT [Kevin Deng](https://github.com/sxzz)
[MIT](./LICENSE) Copyright (c) 2019 RollupJS Plugin Contributors (https://github.com/rollup/plugins/graphs/contributors)
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/unplugin-utils.svg
[npm-version-href]: https://npmjs.com/package/unplugin-utils
[npm-downloads-src]: https://img.shields.io/npm/dm/unplugin-utils
[npm-downloads-href]: https://www.npmcharts.com/compare/unplugin-utils?interval=30
[unit-test-src]: https://github.com/sxzz/unplugin-utils/actions/workflows/unit-test.yml/badge.svg
[unit-test-href]: https://github.com/sxzz/unplugin-utils/actions/workflows/unit-test.yml
[codecov-src]: https://codecov.io/gh/sxzz/unplugin-utils/graph/badge.svg?token=VDWXCPSL1O
[codecov-href]: https://codecov.io/gh/sxzz/unplugin-utils

View file

@ -0,0 +1,31 @@
//#region src/filter.d.ts
/**
* A valid `picomatch` glob pattern, or array of patterns.
*/
type FilterPattern = ReadonlyArray<string | RegExp> | string | RegExp | null;
/**
* Constructs a filter function which can be used to determine whether or not
* certain modules should be operated upon.
* @param include If `include` is omitted or has zero length, filter will return `true` by default.
* @param exclude ID must not match any of the `exclude` patterns.
* @param options Additional options.
* @param options.resolve Optionally resolves the patterns against a directory other than `process.cwd()`.
* If a `string` is specified, then the value will be used as the base directory.
* Relative paths will be resolved against `process.cwd()` first.
* If `false`, then the patterns will not be resolved against any directory.
* This can be useful if you want to create a filter for virtual module names.
*/
declare function createFilter(include?: FilterPattern, exclude?: FilterPattern, options?: {
resolve?: string | false | null;
}): (id: string | unknown) => boolean;
//#endregion
//#region src/path.d.ts
/**
* Converts path separators to forward slash.
*/
declare function normalizePath(filename: string): string;
//#endregion
//#region src/utils.d.ts
declare function toArray<T>(thing: readonly T[] | T | undefined | null): readonly T[];
//#endregion
export { FilterPattern, createFilter, normalizePath, toArray };

View file

@ -0,0 +1,67 @@
import { isAbsolute, join, resolve } from "pathe";
import pm from "picomatch";
//#region src/path.ts
/**
* Converts path separators to forward slash.
*/
function normalizePath(filename) {
return filename.replaceAll("\\", "/");
}
//#endregion
//#region src/utils.ts
const isArray = Array.isArray;
function toArray(thing) {
if (isArray(thing)) return thing;
if (thing == null) return [];
return [thing];
}
//#endregion
//#region src/filter.ts
const escapeMark = "[_#EsCaPe#_]";
function getMatcherString(id, resolutionBase) {
if (resolutionBase === false || isAbsolute(id) || id.startsWith("**")) return normalizePath(id);
const basePath = normalizePath(resolve(resolutionBase || "")).replaceAll(/[-^$*+?.()|[\]{}]/g, `${escapeMark}$&`);
return join(basePath, normalizePath(id)).replaceAll(escapeMark, "\\");
}
/**
* Constructs a filter function which can be used to determine whether or not
* certain modules should be operated upon.
* @param include If `include` is omitted or has zero length, filter will return `true` by default.
* @param exclude ID must not match any of the `exclude` patterns.
* @param options Additional options.
* @param options.resolve Optionally resolves the patterns against a directory other than `process.cwd()`.
* If a `string` is specified, then the value will be used as the base directory.
* Relative paths will be resolved against `process.cwd()` first.
* If `false`, then the patterns will not be resolved against any directory.
* This can be useful if you want to create a filter for virtual module names.
*/
function createFilter(include, exclude, options) {
const resolutionBase = options && options.resolve;
const getMatcher = (id) => id instanceof RegExp ? id : { test: (what) => {
const pattern = getMatcherString(id, resolutionBase);
return pm(pattern, { dot: true })(what);
} };
const includeMatchers = toArray(include).map(getMatcher);
const excludeMatchers = toArray(exclude).map(getMatcher);
if (!includeMatchers.length && !excludeMatchers.length) return (id) => typeof id === "string" && !id.includes("\0");
return function result(id) {
if (typeof id !== "string") return false;
if (id.includes("\0")) return false;
const pathId = normalizePath(id);
for (const matcher of excludeMatchers) {
if (matcher instanceof RegExp) matcher.lastIndex = 0;
if (matcher.test(pathId)) return false;
}
for (const matcher of includeMatchers) {
if (matcher instanceof RegExp) matcher.lastIndex = 0;
if (matcher.test(pathId)) return true;
}
return !includeMatchers.length;
};
}
//#endregion
export { createFilter, normalizePath, toArray };

View file

@ -0,0 +1,67 @@
{
"name": "unplugin-utils",
"version": "0.3.1",
"description": "A set of utility functions commonly used by unplugins.",
"type": "module",
"license": "MIT",
"homepage": "https://github.com/sxzz/unplugin-utils#readme",
"bugs": {
"url": "https://github.com/sxzz/unplugin-utils/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sxzz/unplugin-utils.git"
},
"author": "Kevin Deng <sxzz@sxzz.moe>",
"funding": "https://github.com/sponsors/sxzz",
"files": [
"dist"
],
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"pathe": "^2.0.3",
"picomatch": "^4.0.3"
},
"devDependencies": {
"@sxzz/eslint-config": "^7.2.7",
"@sxzz/prettier-config": "^2.2.4",
"@types/node": "^24.7.0",
"@types/picomatch": "^4.0.2",
"@vitest/coverage-v8": "3.2.4",
"bumpp": "^10.3.1",
"eslint": "^9.37.0",
"oxc-transform": "^0.94.0",
"prettier": "^3.6.2",
"tsdown": "^0.15.6",
"tsx": "^4.20.6",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
},
"engines": {
"node": ">=20.19.0"
},
"prettier": "@sxzz/prettier-config",
"tsdown": {
"platform": "neutral",
"exports": true
},
"scripts": {
"lint": "eslint --cache .",
"lint:fix": "pnpm run lint --fix",
"build": "tsdown",
"dev": "tsdown --watch",
"test": "vitest",
"typecheck": "tsc --noEmit",
"format": "prettier --cache --write .",
"release": "bumpp"
}
}

View file

@ -0,0 +1,63 @@
{
"name": "@vue-macros/common",
"version": "3.1.2",
"description": "common feature from Vue Macros.",
"type": "module",
"keywords": [
"vue-macros",
"macros",
"vue",
"sfc",
"setup",
"script-setup",
"common"
],
"license": "MIT",
"homepage": "https://vue-macros.dev",
"bugs": {
"url": "https://github.com/vue-macros/vue-macros/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vue-macros/vue-macros.git",
"directory": "packages/common"
},
"author": "Kevin Deng <sxzz@sxzz.moe>",
"funding": "https://github.com/sponsors/vue-macros",
"files": [
"dist"
],
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./*": "./*"
},
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"vue": "^2.7.0 || ^3.2.25"
},
"peerDependenciesMeta": {
"vue": {
"optional": true
}
},
"dependencies": {
"@vue/compiler-sfc": "^3.5.22",
"ast-kit": "^2.1.2",
"local-pkg": "^1.1.2",
"magic-string-ast": "^1.0.2",
"unplugin-utils": "^0.3.0"
},
"devDependencies": {
"@babel/parser": "^7.28.4",
"@vitejs/plugin-vue": "^6.0.1"
},
"engines": {
"node": ">=20.19.0"
},
"scripts": {}
}