typle
Version:
📦 Scan and install missing Typescript type definitions for your dependencies.
342 lines (327 loc) • 15.7 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty, __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
__hasOwnProp.call(b, prop) && __defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b))
__propIsEnum.call(b, prop) && __defNormalProp(a, prop, b[prop]);
return a;
};
var __async = (__this, __arguments, generator) => new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}, rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
}, step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
// ../../node_modules/.pnpm/tsup@8.3.0_jiti@1.21.6_postcss@8.4.31_typescript@5.6.2/node_modules/tsup/assets/esm_shims.js
import { fileURLToPath } from "url";
import path from "path";
var import_meta = {}, getFilename = () => fileURLToPath(import_meta.url), getDirname = () => path.dirname(getFilename()), __dirname = /* @__PURE__ */ getDirname(), __filename = /* @__PURE__ */ getFilename();
// src/utils/util.ts
import path2 from "node:path";
import semver from "semver";
import spawn from "cross-spawn";
// ../../node_modules/.pnpm/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
import process2 from "node:process";
function isUnicodeSupported() {
let { env } = process2, { TERM, TERM_PROGRAM } = env;
return process2.platform !== "win32" ? TERM !== "linux" : !!env.WT_SESSION || !!env.TERMINUS_SUBLIME || env.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
}
// src/utils/util.ts
import { createSpinner } from "nanospinner";
import { getDependencies, readPkg } from "typle-util";
var joincwd = path2.join.bind(void 0, process.cwd()), spinner = createSpinner(), allowedPackageManagers = ["npm", "yarn", "pnpm", "bun"], defaultOptions = {
silent: !0,
install: !0,
dryRun: !1,
pkgManager: void 0,
patterns: [],
ignorePackages: [],
ignoreDeps: [],
additionalArgs: []
};
function clearSpinner() {
spinner.stop(), process.stdout.moveCursor(0, -1), process.stdout.write(" ".repeat(process.stdout.columns || 50) + "\r");
}
function niceTryPromise(fn) {
return __async(this, null, function* () {
try {
return yield fn();
} catch (e) {
}
});
}
function getPkgJson() {
return __async(this, null, function* () {
return yield readPkg(path2.join(__dirname, "../package.json"));
});
}
function getVersion() {
return __async(this, null, function* () {
return (yield getPkgJson()).version;
});
}
function cleanSemver(version) {
return semver.clean(version, { loose: !0 }) || semver.valid(semver.coerce(version));
}
function getTypescriptVersion() {
return __async(this, null, function* () {
let pkgJson = (yield niceTryPromise(readPkg)) || {}, localTypescriptVersion = getDependencies(pkgJson).typescript;
return localTypescriptVersion ? cleanSemver(localTypescriptVersion) : new Promise((resolve, reject) => {
var _a;
let proc = spawn("tsc -v");
(_a = proc.stdout) == null || _a.on("data", (version) => {
resolve(cleanSemver(version.toString())), proc.kill();
}), proc.once("error", reject), proc.once("exit", reject);
});
});
}
function matchVersion(dep, packument) {
return Object.keys(packument.versions).filter((version) => {
try {
return (semver.satisfies(version, semver.validRange(dep.version) || "^" + semver.major(cleanSemver(dep.version) || dep.version), { includePrerelease: !0 }) || semver.satisfies(version, "^" + semver.major(cleanSemver(dep.version) || dep.version), { includePrerelease: !0 })) && !("deprecated" in packument.versions[version]);
} catch (e) {
return !1;
}
}).sort((a, b) => semver.rcompare(a, b))[0];
}
function getUnicode(str, alt = "") {
return isUnicodeSupported() ? str : alt;
}
// src/utils/logger.ts
import pc from "picocolors";
var logger = {}, levels = {
info: pc.cyan("info"),
warn: pc.yellow("warn"),
error: pc.red("error"),
success: pc.bold(pc.green(getUnicode("\u2714", "\u221A")))
};
function log(...msg) {
console.log(...msg);
}
logger.info = (...msg) => {
log(levels.info, ...msg);
};
logger.success = (...msg) => {
log(levels.success, ...msg);
};
logger.warn = (...msg) => {
log(levels.warn, ...msg);
};
logger.error = (...msg) => {
log(levels.error, ...msg);
};
var logger_default = logger;
// src/cli/runner.ts
import fs2 from "node:fs";
import path4 from "node:path";
import semver2 from "semver";
import pc5 from "picocolors";
import { glob } from "tinyglobby";
// src/scanner.ts
import fs from "node:fs";
import path3 from "node:path";
import pc3 from "picocolors";
import detectIndent from "detect-indent";
import { detectPackageManager, installPackage } from "@antfu/install-pkg";
import { convertToTypes, readPkg as readPkg2 } from "typle-util";
import { fetchPackage, filterTypes } from "typle-core";
// src/utils/session.ts
var session = {
install_count: 0
};
// src/utils/generate-list.ts
import pc2 from "picocolors";
import { TYPES_PREFIX } from "typle-util";
function generateList(pkgs, filepath) {
let list = `${" ".repeat(process.stdout.columns || 30)}
${getUnicode("\u{1F4E6} ")}typle ${pc2.gray(pc2.italic("- " + filepath))} ${pc2.italic(`(added ${pkgs.length} package${pkgs.length > 1 ? "s" : ""})`)}`;
return pkgs.forEach((pkg, i) => {
let c = getUnicode(i === pkgs.length - 1 ? "\u2514\u2574" : "\u251C\u2574", "- ");
list += `
` + pc2.white(c) + pc2.gray(TYPES_PREFIX) + pc2.blue(pc2.bold(pkg.replace(TYPES_PREFIX, "")));
}), list + `
`;
}
// src/scanner.ts
var { exit } = process, pkgCwd = joincwd("package.json");
function scan() {
return __async(this, arguments, function* (pkgPath = pkgCwd, tsTag = "latest", options) {
let cwd = path3.resolve(pkgPath), pkgDir = path3.relative(process.cwd(), cwd), prettyPkgPath = cwd === pkgCwd ? "" : pc3.gray(pc3.italic(" (" + pkgDir + ")"));
spinner.start({ text: `scanning ${cwd === pkgCwd ? pc3.blue("package.json") : pc3.blue(pkgDir)} for typings\r`, color: "blue" });
let pkgJson = yield readPkg2(pkgPath), types = [], libraries = [];
try {
types.push(...yield filterTypes(pkgJson, cwd));
} catch (error) {
logger_default.error(error.message), exit(1);
}
if (yield Promise.all(
types.map((lib) => __async(this, null, function* () {
if (options.ignorePackages.includes(lib.name) || options.ignoreDeps.some((deps) => {
deps === "deps" && (deps = "dependencies");
let pkgEl = pkgJson[deps] || pkgJson[deps + "Dependencies"];
return pkgEl == null ? void 0 : pkgEl[lib.name];
})) return;
let dtlib = convertToTypes(lib.name), packument = yield fetchPackage(dtlib);
if (!packument) {
logger_default.warn(pc3.bold(lib.name), "doesn't provide any type definitions");
return;
}
let tags = packument["dist-tags"], version = matchVersion(lib, packument) || tsTag && tags[tsTag] || tags.latest;
if (!version || !packument.versions[version]) {
logger_default.error(`No valid release tag found for ${packument.name}`);
return;
}
let pkg = packument.versions[version];
libraries.push(pkg);
}))
), clearSpinner(), !libraries.length) {
logger_default.info("no typings to add" + prettyPkgPath);
return;
}
if (console.log(
generateList(libraries.map(({ name }) => name).sort(), cwd === pkgCwd ? "package.json" : pkgDir)
), options.dryRun) return;
let pkgManager = options.pkgManager || ((yield detectPackageManager(cwd)) || "npm").split("@")[0], installCmd = pkgManager === "yarn" ? "add" : "install";
if (options.install) {
let pkgs = libraries.map((pkg) => pkg.name.trim() + "@^" + pkg.version.trim()), additionalArgs = options.additionalArgs;
Object.keys(options).filter((option) => !Object.keys(defaultOptions).includes(option)).forEach((option) => {
let opt = options[option];
Array.isArray(opt) || (additionalArgs.push("--" + option), /^(true|false)$/i.test(opt) || additionalArgs.push(opt));
});
let cmd = `${pkgManager} ${installCmd} --save-dev ${pkgs.join(" ")} ${additionalArgs.join(" ")}`;
logger_default.info(`$ ${cmd}`), options.silent && spinner.start({ text: `installing ${pc3.cyan(pkgs.length + " package" + (pkgs.length > 1 ? "s" : ""))} via ${pkgManager}\r`, color: "cyan" });
try {
yield installPackage(pkgs, { dev: !0, silent: options.silent, additionalArgs, cwd: path3.dirname(cwd), packageManager: pkgManager });
} catch (e) {
logger_default.error("Something went wrong while installing dependencies. Try running the following command yourself:", pc3.gray(cmd)), exit(1);
}
options.silent && clearSpinner();
} else {
pkgJson.devDependencies = pkgJson.devDependencies || {}, libraries.forEach((lib) => {
pkgJson.devDependencies[lib.name] = `^${lib.version}`;
}), pkgJson.devDependencies = Object.fromEntries(Object.keys(pkgJson.devDependencies).sort().map((key) => [key, pkgJson.devDependencies[key]]));
let indent = detectIndent(yield fs.promises.readFile(pkgPath, "utf8")).amount || 2;
yield fs.promises.writeFile(pkgPath, JSON.stringify(pkgJson, void 0, indent), "utf8"), logger_default.info("successfully updated package.json"), logger_default.info(`run ${pc3.cyan(`${pkgManager} ${installCmd}`)} to install newly added packages`);
}
session.install_count += libraries.length;
});
}
// src/updater.ts
import updateNotifier from "tiny-update-notifier";
import pc4 from "picocolors";
function updater() {
return __async(this, null, function* () {
let pkg = yield getPkgJson();
try {
let update = yield updateNotifier({ pkg });
update && logger_default.info(`update available: ${pc4.gray(update.current)} ${getUnicode("\u2192", "->")} ${pc4.green(update.latest)} (${update.type})`);
} catch (e) {
logger_default.warn("couldn't fetch new updates");
}
});
}
// src/cli/runner.ts
var { exit: exit2 } = process;
function run() {
return __async(this, arguments, function* (options_ = {}) {
var _a;
let options = __spreadValues(__spreadValues({}, defaultOptions), options_), start = Date.now(), typescriptVersion = yield niceTryPromise(getTypescriptVersion), tsTag = typescriptVersion ? "ts" + semver2.major(typescriptVersion) + "." + semver2.minor(typescriptVersion) : void 0;
typescriptVersion ? logger_default.info("typescript: v" + typescriptVersion) : logger_default.warn("couldn't find any typescript version, is it installed?"), options.pkgManager && !allowedPackageManagers.includes(options.pkgManager) && (logger_default.warn(
pc5.bold(options.pkgManager),
"is not a valid or supported package manager",
pc5.gray(pc5.italic(`(supported: ${pc5.bold("npm")}, ${pc5.bold("yarn")}, ${pc5.bold("pnpm")} and ${pc5.bold("bun")})`))
), delete options.pkgManager), yield updater();
let pkgPath = joincwd("package.json");
if (!((_a = options.patterns) != null && _a.length))
fs2.existsSync(pkgPath) || (logger_default.error("couldn't find 'package.json' in this directory"), exit2(1)), yield scan(pkgPath, tsTag, options);
else {
let files = yield glob(options.patterns, { dot: !0, absolute: !0 });
if (!files.length) {
logger_default.info("no matching patterns found");
return;
}
logger_default.info(`found ${files.length} matching patterns`);
for (let file of files) {
let pkgPath2 = path4.join(file, "package.json");
if (!fs2.existsSync(pkgPath2)) {
logger_default.warn("couldn't find 'package.json' in ", path4.dirname(pkgPath2));
return;
}
yield scan(pkgPath2, tsTag, options);
}
}
options.dryRun && logger_default.info(`no changes made ${pc5.gray(pc5.italic("(--dry-run)"))}`);
let time = ((Date.now() - start) / 1e3).toFixed(1) + "s";
session.install_count ? logger_default.success(`added ${session.install_count} new typings in ${time}`) : logger_default.success(`no typings added in ${time}`);
});
}
// src/cli/installer.ts
import fs3 from "node:fs";
import semver3 from "semver";
import pc6 from "picocolors";
import { installPackage as installPackage2 } from "@antfu/install-pkg";
import { convertToTypes as convertToTypes2 } from "typle-util";
import { fetchPackage as fetchPackage2, hasOwnTypes } from "typle-core";
function install(_0) {
return __async(this, arguments, function* (libs, options = {}) {
fs3.existsSync(joincwd("package.json")) || (logger_default.error("could't find 'package.json' in this directory"), process.exit(1));
let args = options, additionalArgs = [];
Object.keys(args).forEach((arg) => {
let opt = args[arg];
Array.isArray(opt) || (additionalArgs.push("--" + arg), /^(true|false)$/i.test(opt) || additionalArgs.push(opt));
});
let typescriptVersion = yield niceTryPromise(getTypescriptVersion), tsTag = typescriptVersion && "ts" + semver3.major(typescriptVersion) + "." + semver3.minor(typescriptVersion);
typescriptVersion ? logger_default.info("typescript: v" + typescriptVersion) : logger_default.warn("couldn't find any typescript version, is it installed?"), options.pkgManager && !allowedPackageManagers.includes(options.pkgManager) && (logger_default.warn(
options.pkgManager,
"is not a valid or supported package manager",
pc6.gray(pc6.italic(`(we only support ${pc6.underline("npm")} ${pc6.underline("yarn")} ${pc6.underline("pnpm")} and ${pc6.underline("bun")})`))
), delete options.pkgManager), logger_default.warn("this feature is experimental"), yield updater(), logger_default.info("installing libraries"), yield installPackage2(libs, { additionalArgs });
let libraries = [];
yield Promise.all(
libs.map((lib) => __async(this, null, function* () {
let lastindex = lib.lastIndexOf("@");
lastindex !== -1 && (lib = lib.slice(0, Math.max(0, lastindex)));
try {
if (yield hasOwnTypes(lib)) return;
} catch (error) {
logger_default.error(error.message), process.exit(1);
}
let dtlib = convertToTypes2(lib), packument = yield fetchPackage2(dtlib);
if (!packument) {
logger_default.warn(lib, "doesn't provide any type definitions");
return;
}
let tags = packument["dist-tags"], tag = tsTag && tags[tsTag] || tags.latest;
if (!tag || !packument.versions[tag]) {
logger_default.error(`No valid release tag found for ${packument.name}`);
return;
}
let pkg = packument.versions[tag];
libraries.push(pkg);
}))
), libraries.length && (logger_default.info("installing types"), yield installPackage2(libraries.map((lib) => lib.name + "@^" + lib.version), { dev: !0, additionalArgs }));
});
}
export {
__spreadValues,
__async,
__filename,
joincwd,
getVersion,
logger_default,
run,
install
};