orphic-cypress
Version:
Set of utilities and typescript transformers to cover storybook stories with cypress component tests
184 lines • 5.76 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.segmentMdx = exports.safeKebabCase = exports.Fifo = void 0;
const React = __importStar(require("react"));
/**
* Check if the first prop of a
*/
const isRawMd = (childProps) => {
var _a, _b;
return childProps.mdxType === "pre" &&
((_b = (_a = childProps.children) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.className) === "language-md";
};
/**
* quick and dirty fifo
* @private
*/
class Fifo {
// TODO: babel was getting upset with `private` keyword
constructor(limit = 50, _cache = new Map()) {
this.limit = limit;
this._cache = _cache;
}
get(key) {
return this._cache.get(key);
}
set(key, val) {
if (this._cache.size === this.limit) {
this._cache.delete(this._cache.keys().next().value);
}
this._cache.set(key, val);
return val;
}
}
exports.Fifo = Fifo;
const cache = new Fifo();
/**
* simple kebab-case converter for space separated text,
* returns undefined if str is undefined or null
* @private
*/
const safeKebabCase = (str) => typeof str === "string" ? str.toLowerCase().replace(/ /g, "-") : null;
exports.safeKebabCase = safeKebabCase;
/**
* Split up an MDX files into headers for easy use in multiple parts of documentation
* or in multiple files, with some added perks.
*
* Currently, this breaks on any header such that a file like
* ~~~md
* # First Component
*
* Something
*
* ## Second Component
*
* ```md
* # Second header description
* This second component does stuff
* ```
* ~~~
* becomes essentially
* ```ts
* {
* "first-component": {
* full: [<h1>First Component</h1>,<p>Something</p>],
* body: [<p>Something</p>],
* md: "",
* },
* "second-component": {
* full: [<h1>Second Component</h1>,<p>Other</p>],
* body: [<code>....</code>],
* md: "# Second header description\nThis second component does stuff",
* },
* }
* ```
* Although actually they'll be functions at those locations that also have those properties,
* but is `() => full` at invocation. Note how it picks up md code blocks as raw text, suitable
* for story descriptions.
*
*
* Then you can use it like
* ```ts
* import mdx from "./some.mdx";
* const mdxObject = segmentMdx(mdx);
* // define FirstComponent...
* FirstComponent.parameters = {
* docs: {
* page: mdxObject['first-component'],
* }
* };
* // define SecondComponent...
* SecondComponent.parameters = {
* docs: {
* story: {
* description: mdxObject['second-component'].md,
* }
* }
* };
* ```
*
* And if you needed to combine them you could do something like
* ```ts
* docs: {
* page: () => [
* ...mdxObject["first-component"].full,
* ...mdxObject["second-component"].full,
* ]
* }
* ```
*
* Or, in an mdx file like so (real example):
* ```md
* import { Meta } from "@storybook/addon-docs";
* import readme from "../../README.md";
* import { segmentMdx } from "orphic-cypress";
*
* <Meta title="MockRequests/Overview" />
*
* <>{segmentMdx(readme)["intercepting-api-requests"].full}</>
*
* <-- more markdown -->
* # Further afield
* ```
*
* Uses a dead simple FIFO cache of size 50 just to avoid thinking about memory consumption issues.
*/
const segmentMdx = (mdx,
/** force skipping the cache */
force) => {
const fromCache = !force && cache.get(mdx);
if (fromCache)
return fromCache;
if (typeof mdx !== "function")
return cache.set(mdx, {});
const rendered = mdx({});
let currentId = "file";
const collection = {
file: { full: [], body: [], md: "" },
};
React.Children.forEach(rendered.props.children, (child) => {
const childrenOfChild = child.props.children;
if (/^h\d$/.test(child.props.mdxType)) {
// not sure why exactly the id is sometimes already present
currentId = child.props.id || (0, exports.safeKebabCase)(childrenOfChild) || "unknown";
collection[currentId] = { full: [child], body: [], md: "" };
}
else if (collection[currentId]) {
collection[currentId].full.push(child);
collection[currentId].body.push(child);
if (isRawMd(child.props)) {
const rawMd = childrenOfChild.props.children;
collection[currentId].md += rawMd;
}
}
});
return cache.set(mdx, Object.fromEntries(Object.entries(collection).map(([k, v]) => [
k,
Object.assign(() => v.full, v),
])));
};
exports.segmentMdx = segmentMdx;
//# sourceMappingURL=segment-mdx.js.map
;