vite-plugin-utils
Version:
A collection of opinionated Vite plugin utils
134 lines (133 loc) • 3.92 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
export function cleanUrl(url) {
const queryRE = /\?.*$/s;
const hashRE = /#.*$/s;
return url.replace(hashRE, '').replace(queryRE, '');
}
/**
* @see https://github.com/rich-harris/magic-string
*/
export class MagicString {
constructor(str) {
this.str = str;
this.starts = '';
this.ends = '';
}
append(content) {
this.ends += content;
return this;
}
prepend(content) {
this.starts = content + this.starts;
return this;
}
overwrite(start, end, content) {
if (end < start) {
throw new Error(`"end" con't be less than "start".`);
}
if (!this.overwrites) {
this.overwrites = [];
}
this.overwrites.push({ loc: [start, end], content });
return this;
}
toString() {
let str = this.str;
if (this.overwrites) {
const arr = [...this.overwrites].sort((a, b) => b.loc[0] - a.loc[0]);
for (const { loc: [start, end], content } of arr) {
// TODO: check start or end overlap
str = str.slice(0, start) + content + str.slice(end);
}
}
return this.starts + str + this.ends;
}
}
/**
* - `'' -> '.'`
* - `foo` -> `./foo`
*/
export function relativeify(relativePath) {
if (relativePath === '') {
return '.';
}
if (!/^\.{1,2}[/\\]/.test(relativePath)) {
return './' + relativePath;
}
return relativePath;
}
/**
* Ast tree walk
*/
export async function walk(ast, visitors, ancestors = []) {
var _a;
if (!ast)
return;
if (Array.isArray(ast)) {
for (const element of ast) {
await walk(element, visitors, ancestors);
}
}
else {
ancestors = ancestors.concat(ast);
for (const key of Object.keys(ast)) {
// @ts-ignore
await (typeof ast[key] === 'object' && walk(ast[key], visitors, ancestors));
}
}
await ((_a = visitors[ast.type]) === null || _a === void 0 ? void 0 : _a.call(visitors, ast, ancestors));
}
walk.sync = function walkSync(ast, visitors, ancestors = []) {
var _a;
if (!ast)
return;
if (Array.isArray(ast)) {
for (const element of ast) {
walkSync(element, visitors, ancestors);
}
}
else {
ancestors = ancestors.concat(ast);
for (const key of Object.keys(ast)) {
// @ts-ignore
typeof ast[key] === 'object' && walkSync(ast[key], visitors, ancestors);
}
}
(_a = visitors[ast.type]) === null || _a === void 0 ? void 0 : _a.call(visitors, ast, ancestors);
};
const isWindows = os.platform() === 'win32';
function slash(p) {
return p.replace(/\\/g, '/');
}
export function normalizePath(id) {
return path.posix.normalize(isWindows ? slash(id) : id);
}
/**
* @see https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color
* @see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
*/
export const COLOURS = {
$: (c) => (str) => `\x1b[${c}m` + str + '\x1b[0m',
gary: (str) => COLOURS.$(90)(str),
cyan: (str) => COLOURS.$(36)(str),
yellow: (str) => COLOURS.$(33)(str),
green: (str) => COLOURS.$(32)(str),
red: (str) => COLOURS.$(31)(str),
};
const VOLUME_RE = /^[A-Z]:/i;
export function node_modules(root, paths = []) {
if (!root)
return paths;
if (!(root.startsWith('/') || VOLUME_RE.test(root)))
return paths;
const p = path.posix.join(normalizePath(root), 'node_modules');
if (fs.existsSync(p) && fs.statSync(p).isDirectory()) {
paths = paths.concat(p);
}
root = path.posix.join(root, '..');
return (root === '/' || /^[A-Z]:$/i.test(root))
? paths
: node_modules(root, paths);
}