UNPKG

@sanity/pkg-utils

Version:

Simple utilities for modern npm packages.

1,070 lines (1,069 loc) 103 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target, mod )); var path = require("node:path"), rimraf = require("rimraf"), node_module = require("node:module"), node = require("esbuild-register/dist/node"), pkgUp = require("pkg-up"), findConfig = require("find-config"), node_fs = require("node:fs"), chalk = require("chalk"), zod = require("zod"), fs = require("node:fs/promises"), browserslist = require("browserslist"), config$1 = require("@sanity/browserslist-config"), ts = require("typescript"), zodValidationError = require("zod-validation-error"), rxjs = require("rxjs"), apiExtractor = require("@microsoft/api-extractor"), mkdirp = require("mkdirp"), prettier = require("prettier"), tsdocConfig = require("@microsoft/tsdoc-config"), jsoncParser = require("jsonc-parser"), recast = require("recast"), typeScriptParser = require("recast/parsers/typescript.js"), rollup = require("rollup"), rollupPlugin = require("@optimize-lodash/rollup-plugin"), alias = require("@rollup/plugin-alias"), pluginBabel = require("@rollup/plugin-babel"), commonjs = require("@rollup/plugin-commonjs"), json = require("@rollup/plugin-json"), pluginNodeResolve = require("@rollup/plugin-node-resolve"), replace = require("@rollup/plugin-replace"), terser = require("@rollup/plugin-terser"), esbuild = require("rollup-plugin-esbuild"), treeify = require("treeify"), prettyBytes = require("pretty-bytes"), prompts = require("prompts"), node_child_process = require("node:child_process"), getLatestVersion = require("get-latest-version"), gitUrlParse = require("git-url-parse"), outdent = require("outdent"), operators = require("rxjs/operators"), globby = require("globby"), chokidar = require("chokidar"), _documentCurrentScript = typeof document < "u" ? document.currentScript : null; function _interopDefaultCompat(e) { return e && typeof e == "object" && "default" in e ? e : { default: e }; } function _interopNamespaceCompat(e) { if (e && typeof e == "object" && "default" in e) return e; var n = /* @__PURE__ */ Object.create(null); return e && Object.keys(e).forEach(function(k) { if (k !== "default") { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: !0, get: function() { return e[k]; } }); } }), n.default = e, Object.freeze(n); } var path__default = /* @__PURE__ */ _interopDefaultCompat(path), rimraf__namespace = /* @__PURE__ */ _interopNamespaceCompat(rimraf), pkgUp__default = /* @__PURE__ */ _interopDefaultCompat(pkgUp), findConfig__default = /* @__PURE__ */ _interopDefaultCompat(findConfig), chalk__default = /* @__PURE__ */ _interopDefaultCompat(chalk), fs__default = /* @__PURE__ */ _interopDefaultCompat(fs), browserslist__default = /* @__PURE__ */ _interopDefaultCompat(browserslist), config__default = /* @__PURE__ */ _interopDefaultCompat(config$1), ts__default = /* @__PURE__ */ _interopDefaultCompat(ts), prettier__namespace = /* @__PURE__ */ _interopNamespaceCompat(prettier), typeScriptParser__default = /* @__PURE__ */ _interopDefaultCompat(typeScriptParser), alias__default = /* @__PURE__ */ _interopDefaultCompat(alias), commonjs__default = /* @__PURE__ */ _interopDefaultCompat(commonjs), json__default = /* @__PURE__ */ _interopDefaultCompat(json), replace__default = /* @__PURE__ */ _interopDefaultCompat(replace), terser__default = /* @__PURE__ */ _interopDefaultCompat(terser), esbuild__default = /* @__PURE__ */ _interopDefaultCompat(esbuild), treeify__default = /* @__PURE__ */ _interopDefaultCompat(treeify), prettyBytes__default = /* @__PURE__ */ _interopDefaultCompat(prettyBytes), prompts__default = /* @__PURE__ */ _interopDefaultCompat(prompts), getLatestVersion__default = /* @__PURE__ */ _interopDefaultCompat(getLatestVersion), gitUrlParse__default = /* @__PURE__ */ _interopDefaultCompat(gitUrlParse), globby__default = /* @__PURE__ */ _interopDefaultCompat(globby), chokidar__namespace = /* @__PURE__ */ _interopNamespaceCompat(chokidar); function fileExists(filePath) { try { return node_fs.statSync(filePath), !0; } catch { return !1; } } const CONFIG_FILE_NAMES = [ "package.config.ts", "package.config.js", "package.config.cjs", "package.config.mjs" ]; function findConfigFile(cwd) { const pkgJsonPath = findConfig__default.default("package.json", { cwd }); if (!pkgJsonPath) return; const pkgPath = path__default.default.dirname(pkgJsonPath); for (const fileName of CONFIG_FILE_NAMES) { const configPath = path__default.default.resolve(pkgPath, fileName); if (fileExists(configPath)) return configPath; } } const require$2 = node_module.createRequire(typeof document > "u" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("_chunks-cjs/index.cjs", document.baseURI).href); async function loadConfig(options) { const { cwd } = options, pkgPath = await pkgUp__default.default({ cwd }); if (!pkgPath) return; const root = path__default.default.dirname(pkgPath), configFile = await findConfigFile(root); if (!configFile || !configFile.startsWith(cwd)) return; const esbuildOptions = { extensions: [".js", ".mjs", ".ts"] }, { unregister } = globalThis.__DEV__ ? { unregister: () => { } } : node.register(esbuildOptions), mod = require$2(configFile); return unregister(), mod?.default || mod || void 0; } function assertLast(a, arr) { const aIdx = arr.indexOf(a); return aIdx === -1 ? !0 : aIdx === arr.length - 1; } function assertOrder(a, b, arr) { const aIdx = arr.indexOf(a), bIdx = arr.indexOf(b); return aIdx === -1 || bIdx === -1 ? !0 : aIdx < bIdx; } const pkgSchema = zod.z.object({ type: zod.z.optional(zod.z.enum(["commonjs", "module"])), name: zod.z.string(), version: zod.z.string(), license: zod.z.string(), bin: zod.z.optional(zod.z.record(zod.z.string())), dependencies: zod.z.optional(zod.z.record(zod.z.string())), devDependencies: zod.z.optional(zod.z.record(zod.z.string())), peerDependencies: zod.z.optional(zod.z.record(zod.z.string())), source: zod.z.optional(zod.z.string()), main: zod.z.optional(zod.z.string()), browser: zod.z.optional(zod.z.record(zod.z.string())), module: zod.z.optional(zod.z.string()), types: zod.z.optional(zod.z.string()), exports: zod.z.optional( zod.z.record( zod.z.union([ zod.z.custom((val) => /^\.\/.*\.json$/.test(val)), zod.z.custom((val) => /^\.\/.*\.css$/.test(val)), zod.z.object({ types: zod.z.optional(zod.z.string()), source: zod.z.optional(zod.z.string()), browser: zod.z.optional( zod.z.object({ source: zod.z.string(), import: zod.z.optional(zod.z.string()), require: zod.z.optional(zod.z.string()) }) ), node: zod.z.optional( zod.z.object({ source: zod.z.optional(zod.z.string()), import: zod.z.optional(zod.z.string()), require: zod.z.optional(zod.z.string()) }) ), import: zod.z.optional(zod.z.string()), require: zod.z.optional(zod.z.string()), default: zod.z.string() }), zod.z.object({ types: zod.z.optional(zod.z.string()), svelte: zod.z.string(), default: zod.z.optional(zod.z.string()) }) ]) ) ), browserslist: zod.z.optional(zod.z.union([zod.z.string(), zod.z.array(zod.z.string())])), sideEffects: zod.z.optional(zod.z.union([zod.z.boolean(), zod.z.array(zod.z.string())])), // @TODO type this properly typesVersions: zod.z.optional(zod.z.any()) }), typoMap = /* @__PURE__ */ new Map(); for (const key of pkgSchema.keyof()._def.values) typoMap.set(key.toUpperCase(), key); function validatePkg(input) { const pkg = pkgSchema.parse(input), invalidKey = Object.keys(input).find((key) => { const needle = key.toUpperCase(); return typoMap.has(needle) ? typoMap.get(needle) !== key : !1; }); if (invalidKey) throw new TypeError( ` - package.json: "${invalidKey}" is not a valid key. Did you mean "${typoMap.get(invalidKey.toUpperCase())}"?` ); return pkg; } async function loadPkg(options) { const { cwd } = options, pkgPath = await pkgUp__default.default({ cwd }); if (!pkgPath) throw new Error("no package.json found"); const buf = await fs__default.default.readFile(pkgPath), raw = JSON.parse(buf.toString()); return validatePkg(raw), raw; } async function loadPkgWithReporting(options) { const { cwd, logger, strict } = options; try { const pkg = await loadPkg({ cwd }); let shouldError = !1; if (strict && (pkg.type || (shouldError = !0, logger.error( 'the `type` field in `./package.json` must be either "module" or "commonjs")' ))), pkg.exports) { const _exports = Object.entries(pkg.exports); for (const [expPath, exp] of _exports) { if (typeof exp == "string" || "svelte" in exp) continue; const keys = Object.keys(exp); exp.types && (shouldError = !0, logger.error( `exports["${expPath}"]: the \`types\` condition shouldn't be used as dts files are generated in such a way that both CJS and ESM is supported` )), exp.module && (shouldError = !0, logger.error( `exports["${expPath}"]: the \`module\` condition shouldn't be used as it's not well supported in all bundlers.` )), exp.node ? (exp.import && exp.node.import && !assertOrder("node", "import", keys) && (shouldError = !0, logger.error( `exports["${expPath}"]: the \`node\` property should come before the \`import\` property` )), exp.node.module && (shouldError = !0, logger.error( `exports["${expPath}"]: the \`node.module\` condition shouldn't be used as it's not well supported in all bundlers. A better strategy is to refactor the codebase to no longer be vulnerable to the "dual package hazard"` )), !exp.node.source && exp.node.import && (exp.node.require || exp.require) && (exp.node.import.endsWith(".cjs.js") || exp.node.import.endsWith(".cjs.mjs")) && (shouldError = !0, logger.error( `exports["${expPath}"]: the \`node.import\` re-export pattern shouldn't be used as it's not well supported in all bundlers. A better strategy is to refactor the codebase to no longer be vulnerable to the "dual package hazard"` )), exp.require && exp.node.require && exp.require === exp.node.require ? (shouldError = !0, logger.error( `exports["${expPath}"]: the \`node.require\` property isn't necessary as it's identical to \`require\`` )) : exp.require && exp.node.require && !assertOrder("node", "require", keys) && (shouldError = !0, logger.error( `exports["${expPath}"]: the \`node\` property should come before the \`require\` property` ))) : assertOrder("import", "require", keys) || logger.warn( `exports["${expPath}"]: the \`import\` property should come before the \`require\` property` ), assertLast("default", keys) || (shouldError = !0, logger.error( `exports["${expPath}"]: the \`default\` property should be the last property` )); } } return shouldError && process.exit(1), pkg; } catch (err) { if (err instanceof zod.ZodError) for (const issue of err.issues) { if (issue.code === "invalid_type") { logger.error( [ `\`${formatPath(issue.path)}\` `, `in \`./package.json\` must be of type ${chalk__default.default.magenta(issue.expected)} `, `(received ${chalk__default.default.magenta(issue.received)})` ].join("") ); continue; } logger.error(issue); } else logger.error(err); process.exit(1); } } function formatPath(segments) { return segments.map((s, idx) => idx === 0 ? s : typeof s == "number" ? `[${s}]` : s.startsWith(".") ? `["${s}"]` : `.${s}`).join(""); } function createLogger(quiet = !1) { return { log: (...args) => { quiet || console.log(...args); }, info: (...args) => { quiet || console.log(chalk__default.default.blue("[info]"), ...args); }, warn: (...args) => { console.log(chalk__default.default.yellow("[warning]"), ...args); }, error: (...args) => { console.log(chalk__default.default.red("[error]"), ...args); }, success: (...args) => { quiet || console.log(chalk__default.default.green("[success]"), ...args); } }; } function browserslistToEsbuild(browserslistConfig, options = {}) { if (!browserslistConfig) { const path2 = process.cwd(); browserslistConfig = browserslist__default.default.loadConfig({ path: path2, ...options }); } const SUPPORTED_ESBUILD_TARGETS = [ "es", "chrome", "edge", "firefox", "ios", "node", "safari", "opera", "ie" ], UNSUPPORTED = ["android 4"], replaces = { ios_saf: "ios", android: "chrome" }, separator = " "; return browserslist__default.default(browserslistConfig, options).filter((b) => !UNSUPPORTED.some((u) => b.startsWith(u))).map((b) => b === "safari TP" ? browserslist__default.default("last 1 safari version")[0] : b).map((b) => b.split(separator)).map((b) => (replaces[b[0]] && (b[0] = replaces[b[0]]), b)).map((b) => (b[1].includes("-") && (b[1] = b[1].slice(0, b[1].indexOf("-"))), b)).map((b) => (b[1].endsWith(".0") && (b[1] = b[1].slice(0, -2)), b)).filter((b) => /^\d+(\.\d+)*$/.test(b[1])).filter((b) => SUPPORTED_ESBUILD_TARGETS.includes(b[0])).reduce((acc, b) => { const existingIndex = acc.findIndex((br) => br[0] === b[0]); return existingIndex !== -1 ? acc[existingIndex][1] = b[1] : acc.push(b), acc; }, []).map((b) => b.join("")); } function resolveConfigProperty(prop, initialValue) { return prop ? typeof prop == "function" ? prop(initialValue) : prop : initialValue; } const DEFAULT_BROWSERSLIST_QUERY = config__default.default; function pathContains(containerPath, itemPath) { return !path__default.default.relative(containerPath, itemPath).startsWith(".."); } function findCommonDirPath(filePaths) { let ret; for (const filePath of filePaths) { let dirPath = path__default.default.dirname(filePath); if (!ret) { ret = dirPath; continue; } for (; dirPath !== ret && (dirPath = path__default.default.dirname(dirPath), dirPath !== ret); ) { if (pathContains(dirPath, ret)) { ret = dirPath; break; } if (dirPath === ".") return; } } return ret; } const fileEnding = /\.[mc]?js$/, dtsEnding = ".d.ts", defaultEnding = ".js", mjsEnding = ".mjs", cjsEnding = ".cjs", mtsEnding = ".d.mts", ctsEnding = ".d.cts"; function getTargetPaths(_type, expOrBundle) { const type = _type === "module" ? "module" : "commonjs", set = /* @__PURE__ */ new Set(); return expOrBundle?.import && set.add(expOrBundle.import.replace(fileEnding, type === "module" ? dtsEnding : mtsEnding)), expOrBundle?.require && set.add(expOrBundle.require.replace(fileEnding, type === "commonjs" ? dtsEnding : ctsEnding)), isPkgExport$1(expOrBundle) && (expOrBundle.browser?.source || (expOrBundle.browser?.import && set.add( expOrBundle.browser.import.replace(fileEnding, type === "module" ? dtsEnding : mtsEnding) ), expOrBundle.browser?.require && set.add( expOrBundle.browser.require.replace( fileEnding, type === "commonjs" ? dtsEnding : ctsEnding ) )), expOrBundle.node?.source || (expOrBundle.node?.import && set.add( expOrBundle.node.import.replace(fileEnding, type === "module" ? dtsEnding : mtsEnding) ), expOrBundle.node?.require && set.add( expOrBundle.node.require.replace(fileEnding, type === "commonjs" ? dtsEnding : ctsEnding) ))), Array.from(set); } function isPkgExport$1(exp) { return exp?.browser || exp?.node || exp?.default; } function isRecord(value) { return !!value && !Array.isArray(value) && typeof value == "object"; } const pkgExtMap = { // pkg.type: "commonjs" commonjs: { commonjs: defaultEnding, esm: mjsEnding }, // pkg.type: "module" module: { commonjs: cjsEnding, esm: defaultEnding } }; function validateExports(_exports, options) { const { pkg } = options, type = pkg.type || "commonjs", ext = pkgExtMap[type], errors = []; for (const exp of _exports) exp.require && !exp.require.endsWith(ext.commonjs) && errors.push( `package.json with \`type: "${type}"\` - \`exports["${exp._path}"].require\` must end with "${ext.commonjs}"` ), exp.import && !exp.import.endsWith(ext.esm) && errors.push( `package.json with \`type: "${type}"\` - \`exports["${exp._path}"].import\` must end with "${ext.esm}"` ); return errors; } function parseExports(options) { const { cwd, pkg, strict, strictOptions: strictOptions2, logger } = options, type = pkg.type || "commonjs", errors = [], report = (kind, message) => { kind === "warn" ? logger.warn(message) : errors.push(message); }; if (!pkg.main && strict && strictOptions2.alwaysPackageJsonMain !== "off" && report(strictOptions2.alwaysPackageJsonMain, "package.json: `main` must be declared"), !Array.isArray(pkg.files) && strict && strictOptions2.alwaysPackageJsonFiles !== "off" && report( strictOptions2.alwaysPackageJsonFiles, "package.json: `files` should be used over `.npmignore`" ), pkg.source) { if (strict && pkg.exports?.["."] && typeof pkg.exports["."] == "object" && "source" in pkg.exports["."] && pkg.exports["."].source === pkg.source) errors.push( 'package.json: the "source" property can be removed, as it is equal to exports["."].source.' ); else if (!pkg.exports && pkg.main) { const extMap = pkgExtMap[type], importExport = pkg.main.replace(fileEnding, extMap.esm), requireExport = pkg.main.replace(fileEnding, extMap.commonjs), defaultExport = pkg.main.replace(fileEnding, defaultEnding), maybeBrowserCondition = []; if (pkg.browser) { const browserConditions = []; pkg.module && pkg.browser?.[pkg.module] ? browserConditions.push( ` "import": ${JSON.stringify(pkg.browser[pkg.module].replace(fileEnding, extMap.esm))}` ) : pkg.browser?.[pkg.main] && browserConditions.push( ` "import": ${JSON.stringify(pkg.browser[pkg.main].replace(fileEnding, extMap.esm))}` ), pkg.browser?.[pkg.main] && browserConditions.push( ` "require": ${JSON.stringify(pkg.browser[pkg.main].replace(fileEnding, extMap.commonjs))}` ), browserConditions.length && maybeBrowserCondition.push( ' "browser": {', ` "source": ${JSON.stringify(pkg.browser?.[pkg.source] || pkg.source)},`, ...browserConditions, " }" ); } errors.push( ...[ "package.json: `exports` are missing, it should be:", '"exports": {', ' ".": {', ` "source": ${JSON.stringify(pkg.source)},`, // If browser conditions are detected then add them to the suggestion ...maybeBrowserCondition.length > 0 ? maybeBrowserCondition : [], type === "commonjs" && ` "import": ${JSON.stringify(importExport)},`, type === "module" && ` "require": ${JSON.stringify(requireExport)},`, ` "default": ${JSON.stringify(defaultExport)}`, " },", ' "./package.json": "./package.json"', "}" ].filter(Boolean) ); } } if (errors.length) throw new Error(` - ` + errors.join(` - `)); if (!pkg.exports) throw new Error( ` - ` + [ "package.json: `exports` are missing, please set a minimal configuration, for example:", '"exports": {', ' ".": {', ' "source": "./src/index.js",', ' "default": "./dist/index.js"', " },", ' "./package.json": "./package.json"', "}" ].join(` - `) ); const _exports = []; strict && strictOptions2.noPackageJsonTypings !== "off" && "typings" in pkg && report(strictOptions2.noPackageJsonTypings, "package.json: `typings` should be `types`"), strict && strictOptions2.alwaysPackageJsonTypes !== "off" && !pkg.types && typeof pkg.exports?.["."] == "object" && "source" in pkg.exports["."] && pkg.exports["."].source?.endsWith(".ts") && report( strictOptions2.alwaysPackageJsonTypes, "package.json: `types` must be declared for the npm listing to show as a TypeScript module." ), strict && !pkg.exports["./package.json"] && errors.push('package.json: `exports["./package.json"] must be declared.'); for (const [exportPath, exportEntry] of Object.entries(pkg.exports)) if (exportPath.endsWith(".json") || typeof exportEntry == "string" && exportEntry.endsWith(".json")) exportPath === "./package.json" && exportEntry !== "./package.json" && errors.push('package.json: `exports["./package.json"]` must be "./package.json".'); else if (exportPath.endsWith(".css")) typeof exportEntry == "string" && !node_fs.existsSync(path.resolve(cwd, exportEntry)) ? errors.push( `package.json: \`exports[${JSON.stringify(exportPath)}]\`: file does not exist.` ) : typeof exportEntry != "string" && errors.push( `package.json: \`exports[${JSON.stringify(exportPath)}]\`: export conditions not supported for CSS files.` ); else if (!(isRecord(exportEntry) && "svelte" in exportEntry)) if (isPkgExport(exportEntry)) { const exp = { _exported: !0, _path: exportPath, ...exportEntry }; if (!exp.default) { const fallback = type === "module" ? exp.import : exp.require; fallback && (exp.default = fallback); } !exp.require && type === "commonjs" && exp.default && (exp.require = exp.default), !exp.import && type === "module" && exp.default && (exp.import = exp.default), exportPath === "." && (exportEntry.require && pkg.main && exportEntry.require !== pkg.main && errors.push( 'package.json: mismatch between "main" and "exports.require". These must be equal.' ), exportEntry.import && pkg.module && exportEntry.import !== pkg.module && errors.push( 'package.json: mismatch between "module" and "exports.import" These must be equal.' )), _exports.push(exp); } else isRecord(exportEntry) || errors.push("package.json: exports must be an object"); if (errors.push(...validateExports(_exports, { pkg })), errors.length) throw new Error(` - ` + errors.join(` - `)); return _exports; } function isPkgExport(value) { return isRecord(value) && "source" in value && typeof value.source == "string"; } async function loadTSConfig(options) { const { cwd, tsconfigPath } = options, configPath = ts__default.default.findConfigFile(cwd, ts__default.default.sys.fileExists, tsconfigPath); if (!configPath) return; const configFile = ts__default.default.readConfigFile(configPath, ts__default.default.sys.readFile); return ts__default.default.parseJsonConfigFileContent(configFile.config, ts__default.default.sys, cwd); } function resolveBrowserTarget(versions) { const target = versions.filter( (version) => version.startsWith("chrome") || version.startsWith("edge") || version.startsWith("firefox") || version.startsWith("ios") || version.startsWith("safari") || version.startsWith("opera") ); if (target.length !== 0) return target; } function resolveNodeTarget(versions) { const target = versions.filter((version) => version.startsWith("node")); if (target.length !== 0) return target; } const toggle = zod.z.union([zod.z.literal("error"), zod.z.literal("warn"), zod.z.literal("off")]), strictOptions = zod.z.object({ noPackageJsonTypings: toggle.default("error"), noImplicitSideEffects: toggle.default("warn"), noImplicitBrowsersList: toggle.default("warn"), alwaysPackageJsonTypes: toggle.default("error"), alwaysPackageJsonMain: toggle.default("error"), alwaysPackageJsonFiles: toggle.default("error"), noCheckTypes: toggle.default("warn") }).strict(), validationSchema = zod.z.object({ strictOptions: strictOptions.default({}) }); function parseStrictOptions(input) { return validationSchema.parse({ strictOptions: input }, { errorMap: zodValidationError.errorMap }).strictOptions; } async function resolveBuildContext(options) { const { config: config2, cwd, emitDeclarationOnly = !1, logger, pkg, strict, tsconfig: tsconfigPath } = options, tsconfig = await loadTSConfig({ cwd, tsconfigPath }), strictOptions2 = parseStrictOptions(config2?.strictOptions ?? {}); if (strictOptions2.noCheckTypes !== "off" && tsconfig?.options && config2?.dts !== "rolldown" && tsconfig.options.noCheck !== !1 && !tsconfig.options.noCheck) { if (strictOptions2.noCheckTypes === "error") throw new Error( "`noCheck` is not set to `true` in the tsconfig.json file used by `package.config.ts`. This makes generating dts files slower than it needs to be, as it will perform type checking on the dts files while at it." ); logger.warn( "`noCheck` is not set to `true` in the tsconfig.json file used by `package.config.ts`. This makes generating dts files slower than it needs to be, as it will perform type checking on the dts files while at it." ); } let browserslist2 = pkg.browserslist; if (!browserslist2) { if (strict && strictOptions2.noImplicitBrowsersList !== "off") { if (strictOptions2.noImplicitBrowsersList === "error") throw new Error( '\n- package.json: "browserslist" is missing, set it to `"browserslist": "extends @sanity/browserslist-config"`' ); logger.warn( 'Could not detect a `browserslist` property in `package.json`, using default configuration. Add `"browserslist": "extends @sanity/browserslist-config"` to silence this warning.' ); } browserslist2 = DEFAULT_BROWSERSLIST_QUERY; } const targetVersions = browserslistToEsbuild(browserslist2); if (strict && strictOptions2.noImplicitSideEffects !== "off" && typeof pkg.sideEffects > "u") { const msg = "package.json: `sideEffects` is missing, see https://webpack.js.org/guides/tree-shaking/#clarifying-tree-shaking-and-sideeffects for how to define `sideEffects`"; if (strictOptions2.noImplicitSideEffects === "error") throw new Error(msg); logger.warn(msg); } const nodeTarget = resolveNodeTarget(targetVersions), webTarget = resolveBrowserTarget(targetVersions); if (!nodeTarget) throw new Error("no matching `node` target"); if (!webTarget) throw new Error("no matching `web` target"); const target = { "*": webTarget.concat(nodeTarget), browser: webTarget, node: nodeTarget }, parsedExports = parseExports({ cwd, pkg, strict, strictOptions: strictOptions2, logger }).reduce( (acc, { _path: exportPath, ...exportEntry }) => Object.assign(acc, { [exportPath]: exportEntry }), {} ), exports2 = resolveConfigProperty(config2?.exports, parsedExports), parsedExternal = [ ...pkg.dependencies ? Object.keys(pkg.dependencies) : [], ...pkg.peerDependencies ? Object.keys(pkg.peerDependencies) : [] ], external = config2 && Array.isArray(config2.external) ? [...parsedExternal, ...config2.external] : resolveConfigProperty(config2?.external, parsedExternal), externalWithTypes = /* @__PURE__ */ new Set([pkg.name, ...external, ...external.map(transformPackageName)]), bundledDependencies = (pkg.devDependencies ? Object.keys(pkg.devDependencies) : []).filter( // Do not bundle anything that is marked as external (_) => !externalWithTypes.has(_) ), bundledPackages = config2 && Array.isArray(config2.extract?.bundledPackages) ? [...bundledDependencies, ...config2.extract.bundledPackages] : resolveConfigProperty(config2?.extract?.bundledPackages, bundledDependencies), outputPaths = Object.values(exports2).flatMap((exportEntry) => [ exportEntry.import, exportEntry.require, exportEntry.browser?.import, exportEntry.browser?.require, exportEntry.node?.source && exportEntry.node.import, exportEntry.node?.source && exportEntry.node.require ].filter(Boolean)).map((p) => path__default.default.resolve(cwd, p)), commonDistPath = findCommonDirPath(outputPaths); if (commonDistPath === cwd) throw new Error( "all output files must share a common parent directory which is not the root package directory" ); if (commonDistPath && !pathContains(cwd, commonDistPath)) throw new Error("all output files must be located within the package"); const configDistPath = config2?.dist ? path__default.default.resolve(cwd, config2.dist) : void 0; if (configDistPath && commonDistPath && configDistPath !== commonDistPath && !pathContains(configDistPath, commonDistPath)) throw logger.log(`did you mean to configure \`dist: './${path__default.default.relative(cwd, commonDistPath)}'\`?`), new Error("all output files must be located with the configured `dist` path"); const distPath = configDistPath || commonDistPath; if (!distPath) throw new Error("could not detect `dist` path"); return { config: config2, cwd, distPath, emitDeclarationOnly, exports: exports2, external, bundledPackages, files: [], logger, pkg, runtime: config2?.runtime ?? "*", strict, target, ts: { config: tsconfig, configPath: tsconfigPath }, dts: config2?.dts === "rolldown" ? "rolldown" : "api-extractor" }; } function transformPackageName(packageName) { if (packageName.startsWith("@types/")) return packageName; if (packageName.startsWith("@")) { const [scope, name] = packageName.split("/"); return `@types/${scope?.slice(1)}__${name}`; } else return `@types/${packageName}`; } function resolveBuildTasks(ctx) { const { config: config2, pkg, target } = ctx, bundles = config2?.bundles || [], tasks = [], exports2 = Object.entries(ctx.exports || {}).map( ([_path, exp]) => ({ _path, ...exp }) ), dtsTask2 = { type: "build:dts", entries: [] }, rolldownDtsTask2 = {}, rollupTasks = {}; function addRollupTaskEntry(format, runtime, entry) { const buildId = `${format}:${runtime}`; ctx.dts === "rolldown" && (rolldownDtsTask2[buildId] ? rolldownDtsTask2[buildId].entries.push(entry) : rolldownDtsTask2[buildId] = { type: "rolldown:dts", buildId, entries: [entry], runtime, format, target: target[runtime] }), ctx.emitDeclarationOnly || (rollupTasks[buildId] ? rollupTasks[buildId].entries.push(entry) : rollupTasks[buildId] = { type: "build:js", buildId, entries: [entry], runtime, format, target: target[runtime] }); } if (ctx.dts === "api-extractor") { for (const exp of exports2) { const importId = path__default.default.join(pkg.name, exp._path); exp.source?.endsWith(".ts") && dtsTask2.entries.push({ importId, exportPath: exp._path, sourcePath: exp.source, targetPaths: getTargetPaths(pkg.type, exp) }), exp.browser?.source?.endsWith(".ts") && dtsTask2.entries.push({ importId, exportPath: exp._path, sourcePath: exp.browser.source, targetPaths: getTargetPaths(pkg.type, exp.browser) }), exp.node?.source?.endsWith(".ts") && dtsTask2.entries.push({ importId, exportPath: exp._path, sourcePath: exp.node.source, targetPaths: getTargetPaths(pkg.type, exp.node) }); } for (const bundle of bundles) if (bundle.source?.endsWith(".ts")) { const exportPath = (bundle.import || bundle.require).replace(/\.[mc]?js$/, ""), importId = path__default.default.join(pkg.name, exportPath); dtsTask2.entries.push({ importId, exportPath, sourcePath: bundle.source, targetPaths: getTargetPaths(pkg.type, bundle) }); } dtsTask2.entries.length && tasks.push(dtsTask2); } for (const exp of exports2) { const output = exp.require; output && addRollupTaskEntry("commonjs", ctx.runtime, { path: exp._path, source: exp.source, output }); } for (const exp of exports2) { const output = exp.import; output && addRollupTaskEntry("esm", ctx.runtime, { path: exp._path, source: exp.source, output }); } for (const exp of exports2) { const output = exp.browser?.require; output && addRollupTaskEntry("commonjs", "browser", { path: exp._path, source: exp.browser?.source || exp.source, output }); } for (const exp of exports2) { const output = exp.browser?.import; output && addRollupTaskEntry("esm", "browser", { path: exp._path, source: exp.browser?.source || exp.source, output }); } for (const bundle of bundles) { const idx = bundles.indexOf(bundle); bundle.require && addRollupTaskEntry("commonjs", bundle.runtime || ctx.runtime, { path: `__$$bundle_cjs_${idx}$$__`, source: bundle.source, output: bundle.require }), bundle.import && addRollupTaskEntry("esm", bundle.runtime || ctx.runtime, { path: `__$$bundle_esm_${idx}$$__`, source: bundle.source, output: bundle.import }); } return tasks.push(...Object.values(rolldownDtsTask2)), tasks.push(...Object.values(rollupTasks)), tasks; } function createSpinner(msg, quiet = !1) { const startTime = Date.now(); return quiet || console.log(msg), { complete: () => { quiet || console.log(`${chalk__default.default.green("[success]")} ${chalk__default.default.gray(`${Date.now() - startTime}ms`)}`); }, error: () => { console.log(`${chalk__default.default.red("[error]")} ${chalk__default.default.gray(`${Date.now() - startTime}ms`)}`); } }; } function printExtractMessages(ctx, messages) { const { cwd, logger } = ctx, warnings = messages.filter((msg) => msg.logLevel === "warning"); warnings.length && logger.log(); for (const msg of warnings) { const sourceFilePath = msg.sourceFilePath && path__default.default.relative(cwd, msg.sourceFilePath); msg.messageId !== "TS6307" && logger.log( [ `${chalk__default.default.cyan(sourceFilePath || "?")}`, `:${chalk__default.default.yellow(msg.sourceFileLine)}:${chalk__default.default.yellow(msg.sourceFileColumn)}`, ` - ${chalk__default.default.yellow("warning")} ${chalk__default.default.gray(msg.messageId)} `, msg.text, ` ` ].join("") ); } const errors = messages.filter((msg) => msg.logLevel === "error"); !warnings.length && errors.length && logger.log(""); for (const msg of errors) { const sourceFilePath = msg.sourceFilePath && path__default.default.relative(cwd, msg.sourceFilePath); logger.log( [ `${chalk__default.default.cyan(sourceFilePath || "?")}`, `:${chalk__default.default.yellow(msg.sourceFileLine)}:${chalk__default.default.yellow(msg.sourceFileColumn)}`, ` - ${chalk__default.default.red("error")} ${chalk__default.default.gray(msg.messageId)} `, msg.text, ` ` ].join("") ); } errors.length && process.exit(1); } var printExtractMessages$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, printExtractMessages }); function printDiagnostic(options) { const { cwd, logger, diagnostic } = options; if (diagnostic.file && diagnostic.start) { const { line, character } = ts__default.default.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start), message = ts__default.default.flattenDiagnosticMessageText(diagnostic.messageText, ` `), file = path__default.default.relative(cwd, diagnostic.file.fileName), output = [ `${chalk__default.default.yellow(file)}:${chalk__default.default.blue(line + 1)}:${chalk__default.default.blue(character + 1)} - `, `${chalk__default.default.gray(`TS${diagnostic.code}:`)} ${message}` ].join(""); diagnostic.category === ts__default.default.DiagnosticCategory.Error && logger.error(output), diagnostic.category === ts__default.default.DiagnosticCategory.Warning && logger.warn(output), diagnostic.category === ts__default.default.DiagnosticCategory.Message && logger.log(output), diagnostic.category === ts__default.default.DiagnosticCategory.Suggestion && logger.log(output); } else logger.log(ts__default.default.flattenDiagnosticMessageText(diagnostic.messageText, ` `)); } async function buildTypes(options) { const { cwd, logger, outDir, tsconfig, strict = !1 } = options, compilerOptions = { ...tsconfig.options, declaration: !0, declarationDir: outDir, emitDeclarationOnly: !0, noEmit: !1, noEmitOnError: strict ? !0 : tsconfig.options.noEmitOnError ?? !0, noCheck: tsconfig.options.noCheck ?? tsconfig.options.isolatedDeclarations, outDir }, program = ts__default.default.createProgram(tsconfig.fileNames, compilerOptions), emitResult = program.emit(), allDiagnostics = ts__default.default.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); for (const diagnostic of allDiagnostics) printDiagnostic({ cwd, logger, diagnostic }); if (emitResult.emitSkipped && allDiagnostics.filter((diag) => diag.category === ts__default.default.DiagnosticCategory.Error).length) throw new Error("failed to compile TypeScript definitions"); } class DtsError extends Error { messages; constructor(message, messages) { super(message), this.messages = messages; } } function createApiExtractorConfig(options) { const { bundledPackages, distPath, exportPath, filePath, messages, projectFolder, mainEntryPointFilePath, tsconfig, tsconfigPath, dtsRollupEnabled } = options; return { apiReport: { enabled: !1, reportFileName: "<unscopedPackageName>.api.md" }, bundledPackages, // If `paths` are used for self-referencing imports (e.g. the module is named `sanity`, and the `sanity/structure` export is also importing from `sanity/router`), compiler: tsconfig.options.paths ? { overrideTsconfig: { extends: tsconfigPath, compilerOptions: { // An empty object replaces whatever is in the original tsconfig file paths: {} } } } : { tsconfigFilePath: tsconfigPath }, docModel: { enabled: !1, apiJsonFilePath: path__default.default.resolve(distPath, `${exportPath}.api.json`) }, dtsRollup: { enabled: dtsRollupEnabled, untrimmedFilePath: path__default.default.resolve(distPath, filePath) // betaTrimmedFilePath: path.resolve(distPath, filePath.replace('.d.ts', '-beta.d.ts')), // publicTrimmedFilePath: path.resolve(distPath, filePath.replace('.d.ts', '-public.d.ts')), }, tsdocMetadata: { enabled: !1 }, messages, mainEntryPointFilePath, projectFolder }; } var createApiExtractorConfig$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, createApiExtractorConfig }); const require$1 = node_module.createRequire(typeof document > "u" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("_chunks-cjs/index.cjs", document.baseURI).href); async function createTSDocConfig(opts) { const { customTags } = opts; if (customTags.length === 0) return; const tsDocBaseBuf = await fs.readFile( require$1.resolve("@microsoft/api-extractor/extends/tsdoc-base.json") ), tsDocBaseConfig = jsoncParser.parse(tsDocBaseBuf.toString()), tagDefinitions = (tsDocBaseConfig.tagDefinitions || []).concat( customTags.map((t) => ({ tagName: `@${t.name}`, syntaxKind: t.syntaxKind, allowMultiple: t.allowMultiple })) ), supportForTags = { ...tsDocBaseConfig.supportForTags }; for (const customTag of customTags) supportForTags[`@${customTag.name}`] = !0; return tsdocConfig.TSDocConfigFile.loadFromObject({ ...tsDocBaseConfig, noStandardTags: !1, tagDefinitions, supportForTags }); } var createTSDocConfig$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, createTSDocConfig }); async function extractModuleBlocksFromTypes({ tsOutDir, extractResult }) { const program = extractResult.compilerState.program, moduleBlocks = [], sourceFiles = [...program.getSourceFiles()].filter((sourceFile) => sourceFile.fileName.includes(tsOutDir)); for (const sourceFile of sourceFiles) sourceFile.text.includes("declare module") && moduleBlocks.push(...extractModuleBlocks(sourceFile.text)); return moduleBlocks; } function extractModuleBlocks(fileContent) { return recast.parse(fileContent, { parser: typeScriptParser__default.default }).program.body.filter((node2) => node2.type === "TSModuleDeclaration").map((node2) => recast.print(node2).code); } const LOG_LEVELS = { error: "error", info: "info", off: "none", warn: "warning" }; function getExtractMessagesConfig(options) { const { rules, disabled = !1 } = options; function ruleToLogLevel(key, defaultLevel) { const r = rules?.[key]; return r ? LOG_LEVELS[r] : defaultLevel || "warning"; } return { compilerMessageReporting: { default: { logLevel: disabled ? "none" : "warning" } }, extractorMessageReporting: disabled ? { default: { logLevel: "none", addToApiReportFile: !1 } } : { default: { logLevel: "warning", addToApiReportFile: !1 }, "ae-forgotten-export": { /** * This is hardcoded to `none` as it's no longer needed since TypeScript 5.5 https://github.com/microsoft/TypeScript/issues/42873 * It's hardcoded to `none` since supported by API Extractor when using `module: 'Preserve'` doesn't support it well since `@microsoft/api-extractor` v7.49.0, which upgraded from TS 5.4 to 5.7 internally */ logLevel: "none", addToApiReportFile: !1 }, "ae-incompatible-release-tags": { logLevel: ruleToLogLevel("ae-incompatible-release-tags", "error"), addToApiReportFile: !1 }, "ae-internal-missing-underscore": { logLevel: ruleToLogLevel("ae-internal-missing-underscore"), addToApiReportFile: !1 }, "ae-missing-release-tag": { logLevel: ruleToLogLevel("ae-missing-release-tag", "error"), addToApiReportFile: !1 }, "ae-wrong-input-file-type": { logLevel: "none", addToApiReportFile: !1 } }, tsdocMessageReporting: disabled ? { default: { logLevel: "none", addToApiReportFile: !1 } } : { default: { logLevel: "warning", addToApiReportFile: !1 }, "tsdoc-link-tag-unescaped-text": { logLevel: ruleToLogLevel( "tsdoc-link-tag-unescaped-text", "warning" ), addToApiReportFile: !1 }, "tsdoc-undefined-tag": { logLevel: ruleToLogLevel("tsdoc-undefined-tag", "error"), addToApiReportFile: !1 }, "tsdoc-unsupported-tag": { logLevel: ruleToLogLevel("tsdoc-unsupported-tag", "none"), addToApiReportFile: !1 } } }; } var getExtractMessagesConfig$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, getExtractMessagesConfig }); async function extractTypes(options) { const { bundledPackages, customTags, distPath, exportPath, files, filePaths, projectPath, rules, sourceTypesPath, tmpPath, tsconfig, tsconfigPath, extractorDisabled } = options, tsdocConfigFile = await createTSDocConfig({ customTags: customTags || [] }), filePath = filePaths[0].replace(/\.d\.[mc]ts$/, ".d.ts"), shouldCleanUpDts = !filePaths.includes(filePath), extractorConfig = apiExtractor.ExtractorConfig.prepare({ configObject: createApiExtractorConfig({ bundledPackages, distPath, exportPath, filePath, messages: getExtractMessagesConfig({ rules, disabled: extractorDisabled }), projectFolder: projectPath, mainEntryPointFilePath: sourceTypesPath, tsconfig, tsconfigPath, dtsRollupEnabled: !0 }), configObjectFullPath: void 0, tsdocConfigFile, packageJsonFullPath: path__default.default.resolve(projectPath, "package.json") }), messages = [], extractorResult = apiExtractor.Extractor.invoke(extractorConfig, { // Equivalent to the "--local" command-line parameter localBuild: !0, // Equivalent to the "--verbose" command-line parameter showVerboseMessages: !0, // handle messages messageCallback(message) { messages.push(message), message.handled = !0; } }), typesPath = path__default.default.resolve(distPath, filePath), typesBuf = await fs__default.default.readFile(typesPath), prettierConfig = await prettier__namespace.resolveConfig(typesPath); await mkdirp.mkdirp(path__default.default.dirname(typesPath)); const moduleBlocks = await extractModuleBlocksFromTypes({ extractResult: extractorResult, tsOutDir: tmpPath }), code = [typesBuf.toString(), ...moduleBlocks].join(` `), prettyCode = await prettier__namespace.format(code, { ...prettierConfig, filepath: typesPath }); for (const expFilePath of filePaths) { const expTypesPath = path__default.default.resolve(distPath, expFilePath); await fs__default.default.writeFile(expTypesPath, prettyCode), files.push({ type: "types", path: expTypesPath }); } return shouldCleanUpDts && await fs__default.default.unlink(typesPath), { extractorResult, messages }; } async function doExtract(ctx, task) { const { config: config2, cwd, files, logger, strict, ts: ts2, bundledPackages } = ctx; if (!ts2.config || !ts2.configPath) return { type: "dts", messages: [], results: [] }; const { outDir, rootDir = cwd } = ts2.config.options; if (!outDir) throw new Error("tsconfig.json is missing `compilerOptions.outDir`"); const tmpPath = path__default.default.resolve(outDir, "__tmp__"); await buildTypes({ cwd, logger, outDir: tmpPath, strict, tsconfig: ts2.config }); const messages = [], results = []; for (const entry of task.entries) { const exportPath = entry.exportPath === "." ? "./index" : entry.exportPath, sourceTypesPath = path__default.default.resolve( tmpPath, path__default.default.relative(rootDir, path__default.default.resolve(cwd, entry.sourcePath)).replace(/\.ts$/, ".d.ts") ), targetPaths = entry.targetPaths.map((targetPath) => path__default.default.resolve(cwd, targetPath)), filePaths = targetPaths.map((targetPath) => path__default.default.relative(outDir, targetPath)), result = await extractTypes({ bundledPackages: bundledPackages || [], customTags: config2?.extract?.customTags, distPath: outDir, exportPath, files, filePaths, projectPath: cwd, rules: config2?.extract?.rules, sourceTypesPath, tsconfig: ts2.config, tmpPath, tsconfigPath: path__default.default.resolve(cwd, ts2.configPath || "tsconfig.json"), extractorDisabled: config2?.extract?.enabled === !1 }); messages.push(...result.messages); const errors = result.messages.filter((msg) => msg.logLevel === "error"); if (errors.length > 0) throw await rimraf.rimraf(tmpPath), new DtsError(`encountered ${errors.length} errors when extracting types`, errors); results.push({ sourcePath: path__default.default.resolve(cwd, entry.sourcePath), filePaths: targetPaths }); } return await rimraf.rimraf(tmpPath), { type: "dts", messages, results }; } const dtsTask = { name: (ctx, task) => [ `Build type definitions with ${chalk__default.default.bold(ctx.dts)}...`, " entries:", ...task.entries.map((entry) => entry.targetPaths.map((targetPath) => [ ` - ${chalk__default.default.cyan(entry.importId)}: `, `${chalk__default.default.yellow(entry.sourcePath)} ${chalk__default.default.gray("\u2192")} ${chalk__default.default.yellow(targetPath)}` ].join("")).join(` `)) ].join(` `), exec: (ctx, task) => new rxjs.Observable((observer) => { doExtract(ctx, task).then((result) => { observer.next(result), observer.complete(); }).catch((err) => { observer.error(err); }); }), complete: (ctx, _task, result) => { printExtractMessages(ctx, result.messages); }, error: (ctx, _task, err) => { const { logger } = ctx; err instanceof DtsError ? printExtractMessages(ctx, err.messages) : err instanceof Error && logger.error(err); } }, dtsWatchTask = { name: (_ctx, task) => [ "build type definitions", ...task.entries.map((entry) => entry.target