storybook
Version:
Storybook: Develop, document, and test UI components in isolation
421 lines (409 loc) • 15 kB
JavaScript
import CJS_COMPAT_NODE_URL_q99y7iqlbzn from 'node:url';
import CJS_COMPAT_NODE_PATH_q99y7iqlbzn from 'node:path';
import CJS_COMPAT_NODE_MODULE_q99y7iqlbzn from "node:module";
var __filename = CJS_COMPAT_NODE_URL_q99y7iqlbzn.fileURLToPath(import.meta.url);
var __dirname = CJS_COMPAT_NODE_PATH_q99y7iqlbzn.dirname(__filename);
var require = CJS_COMPAT_NODE_MODULE_q99y7iqlbzn.createRequire(import.meta.url);
// ------------------------------------------------------------
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
// ------------------------------------------------------------
import {
basename,
dirname,
isAbsolute,
join,
normalize,
resolve
} from "./chunk-LMQEOO5W.js";
import {
__name
} from "./chunk-MB5KTO7X.js";
// src/core-server/mocking-utils/resolve.ts
import { readFileSync as readFileSync2, realpathSync } from "node:fs";
import { createRequire } from "node:module";
import { findMockRedirect } from "@vitest/mocker/redirect";
// ../node_modules/resolve.exports/dist/index.mjs
function e(e2, n2, r2) {
throw new Error(r2 ? `No known conditions for "${n2}" specifier in "${e2}" package` : `Missing "${n2}" specifier in "${e2}" package`);
}
__name(e, "e");
function n(n2, i, o2, f) {
let s, u, l = r(n2, o2), c = function(e2) {
let n3 = /* @__PURE__ */ new Set(["default", ...e2.conditions || []]);
return e2.unsafe || n3.add(e2.require ? "require" : "import"), e2.unsafe || n3.add(e2.browser ? "browser" : "node"), n3;
}(f || {}), a = i[l];
if (void 0 === a) {
let e2, n3, r2, t3;
for (t3 in i) n3 && t3.length < n3.length || ("/" === t3[t3.length - 1] && l.startsWith(t3) ? (u = l.substring(t3.length), n3 = t3) : t3.length > 1 && (r2 = t3.indexOf("*", 1), ~r2 && (e2 = RegExp("^" + t3.substring(0, r2) + "(.*)" + t3.substring(1 + r2) + "$").exec(l), e2 && e2[1] && (u = e2[1], n3 = t3))));
a = i[n3];
}
return a || e(n2, l), s = t(a, c), s || e(n2, l, 1), u && function(e2, n3) {
let r2, t3 = 0, i2 = e2.length, o3 = /[*]/g, f2 = /[/]$/;
for (; t3 < i2; t3++) e2[t3] = o3.test(r2 = e2[t3]) ? r2.replace(o3, n3) : f2.test(r2) ? r2 + n3 : r2;
}(s, u), s;
}
__name(n, "n");
function r(e2, n2, r2) {
if (e2 === n2 || "." === n2) return ".";
let t3 = e2 + "/", i = t3.length, o2 = n2.slice(0, i) === t3, f = o2 ? n2.slice(i) : n2;
return "#" === f[0] ? f : o2 || !r2 ? "./" === f.slice(0, 2) ? f : "./" + f : f;
}
__name(r, "r");
function t(e2, n2, r2) {
if (e2) {
if ("string" == typeof e2) return r2 && r2.add(e2), [e2];
let i, o2;
if (Array.isArray(e2)) {
for (o2 = r2 || /* @__PURE__ */ new Set(), i = 0; i < e2.length; i++) t(e2[i], n2, o2);
if (!r2 && o2.size) return [...o2];
} else for (i in e2) if (n2.has(i)) return t(e2[i], n2, r2);
}
}
__name(t, "t");
function o(e2, r2, t3) {
let i, o2 = e2.exports;
if (o2) {
if ("string" == typeof o2) o2 = { ".": o2 };
else for (i in o2) {
"." !== i[0] && (o2 = { ".": o2 });
break;
}
return n(e2.name, o2, r2 || ".", t3);
}
}
__name(o, "o");
// src/core-server/mocking-utils/extract.ts
import { readFileSync } from "node:fs";
import { generate, parser, types as t2 } from "storybook/internal/babel";
import { logger } from "storybook/internal/node-logger";
import { telemetry } from "storybook/internal/telemetry";
import { transformSync } from "esbuild";
// ../node_modules/estree-walker/src/walker.js
var WalkerBase = class {
static {
__name(this, "WalkerBase");
}
constructor() {
this.should_skip = false;
this.should_remove = false;
this.replacement = null;
this.context = {
skip: /* @__PURE__ */ __name(() => this.should_skip = true, "skip"),
remove: /* @__PURE__ */ __name(() => this.should_remove = true, "remove"),
replace: /* @__PURE__ */ __name((node) => this.replacement = node, "replace")
};
}
/**
* @template {Node} Parent
* @param {Parent | null | undefined} parent
* @param {keyof Parent | null | undefined} prop
* @param {number | null | undefined} index
* @param {Node} node
*/
replace(parent, prop, index, node) {
if (parent && prop) {
if (index != null) {
parent[prop][index] = node;
} else {
parent[prop] = node;
}
}
}
/**
* @template {Node} Parent
* @param {Parent | null | undefined} parent
* @param {keyof Parent | null | undefined} prop
* @param {number | null | undefined} index
*/
remove(parent, prop, index) {
if (parent && prop) {
if (index !== null && index !== void 0) {
parent[prop].splice(index, 1);
} else {
delete parent[prop];
}
}
}
};
// ../node_modules/estree-walker/src/sync.js
var SyncWalker = class extends WalkerBase {
static {
__name(this, "SyncWalker");
}
/**
*
* @param {SyncHandler} [enter]
* @param {SyncHandler} [leave]
*/
constructor(enter, leave) {
super();
this.should_skip = false;
this.should_remove = false;
this.replacement = null;
this.context = {
skip: /* @__PURE__ */ __name(() => this.should_skip = true, "skip"),
remove: /* @__PURE__ */ __name(() => this.should_remove = true, "remove"),
replace: /* @__PURE__ */ __name((node) => this.replacement = node, "replace")
};
this.enter = enter;
this.leave = leave;
}
/**
* @template {Node} Parent
* @param {Node} node
* @param {Parent | null} parent
* @param {keyof Parent} [prop]
* @param {number | null} [index]
* @returns {Node | null}
*/
visit(node, parent, prop, index) {
if (node) {
if (this.enter) {
const _should_skip = this.should_skip;
const _should_remove = this.should_remove;
const _replacement = this.replacement;
this.should_skip = false;
this.should_remove = false;
this.replacement = null;
this.enter.call(this.context, node, parent, prop, index);
if (this.replacement) {
node = this.replacement;
this.replace(parent, prop, index, node);
}
if (this.should_remove) {
this.remove(parent, prop, index);
}
const skipped = this.should_skip;
const removed = this.should_remove;
this.should_skip = _should_skip;
this.should_remove = _should_remove;
this.replacement = _replacement;
if (skipped) return node;
if (removed) return null;
}
let key;
for (key in node) {
const value = node[key];
if (value && typeof value === "object") {
if (Array.isArray(value)) {
const nodes = (
/** @type {Array<unknown>} */
value
);
for (let i = 0; i < nodes.length; i += 1) {
const item = nodes[i];
if (isNode(item)) {
if (!this.visit(item, node, key, i)) {
i--;
}
}
}
} else if (isNode(value)) {
this.visit(value, node, key, null);
}
}
}
if (this.leave) {
const _replacement = this.replacement;
const _should_remove = this.should_remove;
this.replacement = null;
this.should_remove = false;
this.leave.call(this.context, node, parent, prop, index);
if (this.replacement) {
node = this.replacement;
this.replace(parent, prop, index, node);
}
if (this.should_remove) {
this.remove(parent, prop, index);
}
const removed = this.should_remove;
this.replacement = _replacement;
this.should_remove = _should_remove;
if (removed) return null;
}
}
return node;
}
};
function isNode(value) {
return value !== null && typeof value === "object" && "type" in value && typeof value.type === "string";
}
__name(isNode, "isNode");
// ../node_modules/estree-walker/src/index.js
function walk(ast, { enter, leave }) {
const instance = new SyncWalker(enter, leave);
return instance.visit(ast, null);
}
__name(walk, "walk");
// src/core-server/mocking-utils/extract.ts
var DEFAULT_MODULE_DIRECTORIES = ["/node_modules/"];
function isModuleDirectory(path) {
const normalizedPath = normalize(path);
return DEFAULT_MODULE_DIRECTORIES.some((dir) => normalizedPath.includes(dir));
}
__name(isModuleDirectory, "isModuleDirectory");
var babelParser = /* @__PURE__ */ __name((code) => {
return parser.parse(code, {
sourceType: "module",
// Enable plugins to handle modern JavaScript features, including TSX.
plugins: ["typescript", "jsx", "classProperties", "objectRestSpread"],
errorRecovery: true
}).program;
}, "babelParser");
function rewriteSbMockImportCalls(code) {
const ast = babelParser(code);
walk(ast, {
enter(node) {
if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "sb" && node.callee.property.type === "Identifier" && node.callee.property.name === "mock" && node.arguments.length > 0 && node.arguments[0].type === "CallExpression" && node.arguments[0].callee.type === "Import" && node.arguments[0].arguments.length === 1 && node.arguments[0].arguments[0].type === "StringLiteral") {
node.arguments[0] = t2.stringLiteral(node.arguments[0].arguments[0].value);
}
}
});
return generate(ast, {}, code);
}
__name(rewriteSbMockImportCalls, "rewriteSbMockImportCalls");
function extractMockCalls(options, parse, root) {
try {
let hasSpyTrue2 = function(objectExpression) {
if (!objectExpression || !objectExpression.properties) {
return false;
}
for (const prop of objectExpression.properties) {
if (prop.type === "ObjectProperty" && (prop.key.type === "Identifier" && prop.key.name === "spy" || prop.key.type === "StringLiteral" && prop.key.value === "spy") && prop.value.type === "BooleanLiteral" && prop.value.value === true) {
return true;
}
}
return false;
};
var hasSpyTrue = hasSpyTrue2;
__name(hasSpyTrue2, "hasSpyTrue");
const previewConfigCode = readFileSync(options.previewConfigPath, "utf-8");
const { code: jsCode } = transformSync(previewConfigCode, { loader: "tsx", format: "esm" });
const ast = parse(jsCode);
const mocks = [];
walk(ast, {
// @ts-expect-error - Node comes from babel
async enter(node) {
if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression" || node.callee.object.type !== "Identifier" || node.callee.object.name !== "sb" || node.callee.property.type !== "Identifier" || node.callee.property.name !== "mock") {
return;
}
if (node.arguments.length === 0) {
return;
}
let path;
if (node.arguments[0].type === "StringLiteral") {
path = node.arguments[0].value;
} else if (node.arguments[0].type === "CallExpression" && node.arguments[0].callee.type === "Import" && node.arguments[0].arguments[0].type === "StringLiteral") {
path = node.arguments[0].arguments[0].value;
} else {
return;
}
const spy = node.arguments.length > 1 && node.arguments[1].type === "ObjectExpression" && hasSpyTrue2(node.arguments[1]);
const { absolutePath, redirectPath } = resolveMock(path, root, options.previewConfigPath);
const pathWithoutExtension = path.replace(/\.[^/.]+$/, "");
const basenameAbsolutePath = basename(absolutePath);
const basenamePath = basename(path);
const pathWithoutExtensionAndBasename = basenameAbsolutePath === basenamePath ? pathWithoutExtension : path;
mocks.push({
path: pathWithoutExtensionAndBasename,
absolutePath,
redirectPath,
spy
});
}
});
if (!options.coreOptions?.disableTelemetry) {
telemetry(
"mocking",
{
modulesMocked: mocks.length,
modulesSpied: mocks.map((mock) => mock.spy).filter(Boolean).length,
modulesManuallyMocked: mocks.map((mock) => !!mock.redirectPath).filter(Boolean).length
},
{ configDir: options.configDir }
);
}
return mocks;
} catch (error) {
logger.debug("Error extracting mock calls", error);
return [];
}
}
__name(extractMockCalls, "extractMockCalls");
// src/core-server/mocking-utils/resolve.ts
var require2 = createRequire(import.meta.url);
function findPackageJson(specifier, basedir) {
const packageJsonPath = require2.resolve(`${specifier}/package.json`, { paths: [basedir] });
return {
path: packageJsonPath,
data: JSON.parse(readFileSync2(packageJsonPath, "utf-8"))
};
}
__name(findPackageJson, "findPackageJson");
function resolveExternalModule(path, root) {
const parts = path.split("/");
const packageName = path.startsWith("@") ? `${parts[0]}/${parts[1]}` : parts[0];
const entry = `.${path.slice(packageName.length)}`;
const { path: packageJsonPath, data: pkg } = findPackageJson(packageName, root);
const packageDir = dirname(packageJsonPath);
if (pkg.exports) {
const result = o(pkg, entry, {
browser: true
});
if (result) {
return join(packageDir, result[0]);
}
}
return require2.resolve(path, { paths: [root] });
}
__name(resolveExternalModule, "resolveExternalModule");
function getIsExternal(path, importer) {
try {
return !isAbsolute(path) && isModuleDirectory(require2.resolve(path, { paths: [importer] }));
} catch (e2) {
return false;
}
}
__name(getIsExternal, "getIsExternal");
function resolveMock(path, root, importer) {
const isExternal = getIsExternal(path, root);
const externalPath = isExternal ? path : null;
const absolutePath = isExternal ? resolveExternalModule(path, root) : require2.resolve(path, { paths: [dirname(importer)] });
const normalizedAbsolutePath = resolve(absolutePath);
const redirectPath = findMockRedirect(root, normalizedAbsolutePath, externalPath);
return {
absolutePath: normalizedAbsolutePath,
redirectPath
// will be null if no __mocks__ file is found
};
}
__name(resolveMock, "resolveMock");
function getRealPath(path, preserveSymlinks) {
try {
return preserveSymlinks ? realpathSync(path) : path;
} catch {
return path;
}
}
__name(getRealPath, "getRealPath");
function resolveWithExtensions(path, from) {
const extensions = [".js", ".ts", ".tsx", ".mjs", ".cjs", ".svelte", ".vue"];
for (const extension of extensions) {
try {
return require2.resolve(path + extension, { paths: [from] });
} catch (e2) {
continue;
}
}
return require2.resolve(path, { paths: [from] });
}
__name(resolveWithExtensions, "resolveWithExtensions");
export {
resolveExternalModule,
getIsExternal,
getRealPath,
resolveWithExtensions,
babelParser,
rewriteSbMockImportCalls,
extractMockCalls
};