@suss/contract-storybook 0.20.0 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +81 -0
  2. package/package.json +3 -3
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # @suss/contract-storybook
2
+
3
+ Generate suss `BehavioralSummary[]` from [Storybook](https://storybook.js.org/) CSF3 story files. A story is a specification somebody wrote by hand: this component supports this prop configuration. Reading stories as contracts lets you ask whether a component accepts the args every story supplies, and whether every branch inferred from the component has a story that reaches it.
4
+
5
+ ## What this package reads
6
+
7
+ `@suss/contract-storybook` parses `.stories.ts` and `.stories.tsx` files with ts-morph and looks at two things in each one.
8
+
9
+ The default export gives the component under test. The reader walks the default-export symbol's declarations for an object literal with a `component` property, which covers `export default { component: Button }`, `const meta = { component: Button }; export default meta;`, and `export default { ... } satisfies Meta<typeof Button>`. Parentheses, `as` expressions, and an identifier pointing at a local variable are followed through to the literal. A file whose default export never resolves to such an object is skipped, and the rest of the run continues.
10
+
11
+ Every other named export whose initializer resolves to an object literal is a story. Its `args` object literal becomes the story's arguments, with each property's value recorded as the source text you wrote. A shorthand property (`{ disabled }`) records its own name.
12
+
13
+ ## What it produces
14
+
15
+ One `component`-kind summary per named story export:
16
+
17
+ - `identity.name` is `Component.Story`, with `exportPath` set to the story's export name and a function-call boundary binding: `transport: "in-process"`, `recognition: "react"`, and the component identifier as the export name.
18
+ - One input per arg. The input's `role` is the arg name, and its shape is a `ref` whose name is the arg's source text, so a reader can see the concrete value that was written.
19
+ - One default transition whose output is a render of the component. The reader does not evaluate the render, so the rendered tree is left unset.
20
+ - `metadata.component.storybook` with the story name, the component name, the args map, and `provenance: "independent"`, which is what makes a story usable as a check against an inferred component summary rather than a restatement of it.
21
+ - Confidence is `derived` at `medium`. Stories are written by people and are authoritative where they speak, and they do not enumerate everything a component does.
22
+
23
+ ## What it does not read
24
+
25
+ - **`play` functions.** The event sequence that exercises an interactive story is not captured.
26
+ - **`argTypes`.** Per-arg control types and option lists would inform stricter type checking and are not read today.
27
+ - **`decorators` and `parameters`.** Storybook runtime plumbing rather than component behavior.
28
+ - **CSF1 and MDX stories.** CSF3 is the supported format.
29
+ - **The component's own module.** The reader keeps the `component` identifier as written and does not follow the import to where the component is defined.
30
+ - **Arg values as structured shapes.** An arg's value stays source text inside a `ref` shape rather than being parsed into a `TypeShape`.
31
+
32
+ ## Worked example
33
+
34
+ ```tsx
35
+ // Button.stories.tsx
36
+ import { Button } from "./Button";
37
+
38
+ export default { component: Button };
39
+
40
+ export const Primary = {
41
+ args: { variant: "primary", disabled: false },
42
+ };
43
+
44
+ export const Disabled = {
45
+ args: { variant: "primary", disabled: true },
46
+ };
47
+ ```
48
+
49
+ ```sh
50
+ suss contract --from storybook src/components -o summaries/stories.json
51
+ suss check summaries/app.json summaries/stories.json
52
+ ```
53
+
54
+ The path may be one `.stories.ts[x]` file or a directory, which the CLI walks recursively for story files. Two summaries come out of the file above, `Button.Primary` and `Button.Disabled`, each with `variant` and `disabled` inputs.
55
+
56
+ Or programmatically, when you want control over the file set or the root that relative paths are computed against:
57
+
58
+ ```ts
59
+ import { generateSummariesFromStories } from "@suss/contract-storybook";
60
+
61
+ const summaries = generateSummariesFromStories(
62
+ ["src/components/Button.stories.tsx"],
63
+ { projectRoot: process.cwd() },
64
+ );
65
+ ```
66
+
67
+ ## Where it fits in suss
68
+
69
+ Depends on `@suss/behavioral-ir` (for the IR types it produces) and `@suss/adapter-typescript` (for export resolution), with `ts-morph` as a peer dependency. This is the one contract reader that parses TypeScript, because CSF is TypeScript. It still reads a declared artifact rather than inferring behavior from a component's implementation.
70
+
71
+ ## Coverage
72
+
73
+ ![coverage](../../../.github/badges/coverage-contract-storybook.svg)
74
+
75
+ ## License
76
+
77
+ Licensed under Apache 2.0. See [LICENSE](../../../LICENSE).
78
+
79
+ ---
80
+
81
+ For the format the summaries conform to, see [`docs/behavioral-summary-format.md`](../../../docs/behavioral-summary-format.md). For how a story is used as a contract, see [`docs/contracts.md`](../../../docs/contracts.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/contract-storybook",
3
- "version": "0.20.0",
3
+ "version": "0.21.1",
4
4
  "type": "module",
5
5
  "description": "Generate suss behavioral summaries from Storybook CSF story files.",
6
6
  "keywords": [
@@ -45,8 +45,8 @@
45
45
  "typecheck": "tsc --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "@suss/adapter-typescript": "0.20.0",
49
- "@suss/behavioral-ir": "0.20.0"
48
+ "@suss/adapter-typescript": "0.21.1",
49
+ "@suss/behavioral-ir": "0.21.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "tsup": "*",