Skip to content

Commit

Permalink
refactor: make story args extraction async (#1929)
Browse files Browse the repository at this point in the history
  • Loading branch information
fwouts committed Aug 15, 2023
1 parent 44917f2 commit 77b854f
Show file tree
Hide file tree
Showing 27 changed files with 780 additions and 764 deletions.
14 changes: 9 additions & 5 deletions api/src/rpcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export type ComputePropsResponse = {
props: {
[componentId: string]: ValueType;
};
args: {
[storyComponentId: string]: StoryArgs | null;
};
types: CollectedTypes;
};

Expand Down Expand Up @@ -44,10 +47,11 @@ export type Story = {
componentId: string;
start: number;
end: number;
args: {
start: number;
end: number;
value: SerializableValue;
} | null;
associatedComponentId: string | null;
};

export type StoryArgs = {
start: number;
end: number;
value: SerializableValue;
};
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@previewjs/properties": "workspace:*",
"@types/express": "^4.17.17",
"@types/fs-extra": "^11.0.1",
"@types/node": "^20.5.0",
"@types/node": "^20.4.10",
"cross-env": "^7.0.3",
"fs-extra": "^11.1.1",
"typescript": "^5.1.6",
Expand Down
12 changes: 7 additions & 5 deletions component-analyzer/api/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ export interface ComponentProps {
}

export interface Story extends BaseComponent {
args: {
start: number;
end: number;
value: SerializableValue;
} | null;
extractArgs: () => Promise<StoryArgs | null>;
associatedComponent: BasicComponent | null;
}

export type StoryArgs = {
start: number;
end: number;
value: SerializableValue;
};

export type BasicComponent = Pick<Component, "componentId" | "extractProps">;
156 changes: 78 additions & 78 deletions component-analyzer/react/src/extract-component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { ComponentAnalyzer } from "@previewjs/component-analyzer-api";
import { object, string, TRUE } from "@previewjs/serializable-values";
import { objectType, STRING_TYPE } from "@previewjs/type-analyzer";
import type {
Component,
ComponentAnalyzer,
Story,
} from "@previewjs/component-analyzer-api";
import { TRUE, object, string } from "@previewjs/serializable-values";
import { STRING_TYPE, objectType } from "@previewjs/type-analyzer";
import type { Reader, Writer } from "@previewjs/vfs";
import {
createFileSystemReader,
Expand All @@ -20,6 +24,12 @@ const ROOT_DIR = path.join(__dirname, "virtual");
const APP_TSX = path.join(ROOT_DIR, "App.tsx");
const APP_STORIES_TSX = path.join(ROOT_DIR, "App.stories.tsx");

function assertStory(story?: Story | Component): asserts story is Story {
if (!story || !("associatedComponent" in story)) {
throw new Error("Expected a story");
}
}

describe("extractReactComponents", () => {
const logger = createLogger(
{ level: "debug" },
Expand Down Expand Up @@ -278,7 +288,6 @@ export const NotStory = (props) => <Button {...props} />;
expect(extractedStories).toMatchObject([
{
componentId: "App.stories.tsx:Primary",
args: null,
associatedComponent: {
componentId: "App.tsx:default",
},
Expand All @@ -289,14 +298,9 @@ export const NotStory = (props) => <Button {...props} />;
},
]);
const story = extractedStories[0];
if (
!story ||
!("associatedComponent" in story) ||
!story.associatedComponent
) {
throw new Error();
}
expect(await story.associatedComponent.extractProps()).toEqual({
assertStory(story);
expect(await story.extractArgs()).toBeNull();
expect(await story.associatedComponent?.extractProps()).toEqual({
props: objectType({
label: STRING_TYPE,
}),
Expand Down Expand Up @@ -324,14 +328,16 @@ export const NotStory = (props) => <Button {...props} />;
expect(extractedStories).toMatchObject([
{
componentId: "App.stories.tsx:Primary",
args: null,
associatedComponent: null,
},
{
componentId: "App.stories.tsx:NotStory",
exported: true,
},
]);
const story = extractedStories[0];
assertStory(story);
expect(await story.extractArgs()).toBeNull();
});

it("detects CSF2 stories (exported with component)", async () => {
Expand Down Expand Up @@ -362,34 +368,28 @@ Primary.args = {
},
{
componentId: "App.stories.tsx:Primary",
args: {
value: object([
{
kind: "key",
key: string("primary"),
value: TRUE,
},
{
kind: "key",
key: string("label"),
value: string("Button"),
},
]),
},
associatedComponent: {
componentId: "App.tsx:default",
},
},
]);
const story = extractedStories[1];
if (
!story ||
!("associatedComponent" in story) ||
!story.associatedComponent
) {
throw new Error();
}
expect(await story.associatedComponent.extractProps()).toEqual({
assertStory(story);
expect(await story.extractArgs()).toMatchObject({
value: object([
{
kind: "key",
key: string("primary"),
value: TRUE,
},
{
kind: "key",
key: string("label"),
value: string("Button"),
},
]),
});
expect(await story.associatedComponent?.extractProps()).toEqual({
props: objectType({
label: STRING_TYPE,
}),
Expand Down Expand Up @@ -425,23 +425,25 @@ Primary.args = {
},
{
componentId: "App.stories.tsx:Primary",
args: {
value: object([
{
kind: "key",
key: string("primary"),
value: TRUE,
},
{
kind: "key",
key: string("label"),
value: string("Button"),
},
]),
},
associatedComponent: null,
},
]);
const story = extractedStories[1];
assertStory(story);
expect(await story.extractArgs()).toMatchObject({
value: object([
{
kind: "key",
key: string("primary"),
value: TRUE,
},
{
kind: "key",
key: string("label"),
value: string("Button"),
},
]),
});
});

it("detects CSF3 stories (exported with component)", async () => {
Expand Down Expand Up @@ -470,41 +472,36 @@ export function NotStory() {}
expect(extractedStories).toMatchObject([
{
componentId: "App.stories.tsx:Example",
args: {
value: object([
{
kind: "key",
key: string("label"),
value: string("Hello, World!"),
},
]),
},
associatedComponent: {
componentId: "App.tsx:default",
},
},
{
componentId: "App.stories.tsx:NoArgs",
args: null,
associatedComponent: {
componentId: "App.tsx:default",
},
},
]);
const story = extractedStories[0];
if (
!story ||
!("associatedComponent" in story) ||
!story.associatedComponent
) {
throw new Error();
}
expect(await story.associatedComponent.extractProps()).toEqual({
const [story1, story2] = extractedStories;
assertStory(story1);
assertStory(story2);
expect(await story1.extractArgs()).toMatchObject({
value: object([
{
kind: "key",
key: string("label"),
value: string("Hello, World!"),
},
]),
});
expect(await story1.associatedComponent?.extractProps()).toEqual({
props: objectType({
label: STRING_TYPE,
}),
types: {},
});
expect(await story2.extractArgs()).toBeNull();
});

it("detects CSF3 stories (exported with title)", async () => {
Expand Down Expand Up @@ -533,23 +530,26 @@ export function NotStory() {}
expect(extractedStories).toMatchObject([
{
componentId: "App.stories.tsx:Example",
args: {
value: object([
{
kind: "key",
key: string("label"),
value: string("Hello, World!"),
},
]),
},
associatedComponent: null,
},
{
componentId: "App.stories.tsx:NoArgs",
args: null,
associatedComponent: null,
},
]);
const [story1, story2] = extractedStories;
assertStory(story1);
assertStory(story2);
expect(await story1.extractArgs()).toMatchObject({
value: object([
{
kind: "key",
key: string("label"),
value: string("Hello, World!"),
},
]),
});
expect(await story2.extractArgs()).toBeNull();
});

function extract(absoluteFilePath: string) {
Expand Down
15 changes: 8 additions & 7 deletions component-analyzer/react/src/extract-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,14 @@ export async function extractReactComponents(
);
return {
...baseComponent,
args: storyArgs
? {
start: storyArgs.getStart(),
end: storyArgs.getEnd(),
value: await parseSerializableValue(storyArgs),
}
: null,
extractArgs: async () =>
storyArgs
? {
start: storyArgs.getStart(),
end: storyArgs.getEnd(),
value: await parseSerializableValue(storyArgs),
}
: null,
associatedComponent,
};
}
Expand Down
2 changes: 1 addition & 1 deletion config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"build": "tsc && unbuild"
},
"devDependencies": {
"@types/node": "^20.5.0",
"@types/node": "^20.4.10",
"typescript": "^5.1.6",
"unbuild": "^1.2.1",
"vite": "^4.4.9"
Expand Down
1 change: 0 additions & 1 deletion core/src/detect-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ async function detectComponentsCore(
componentId: story.componentId,
start,
end,
args: story.args,
associatedComponentId: story.associatedComponent?.componentId || null,
});
}
Expand Down
5 changes: 5 additions & 0 deletions core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export async function createWorkspace({
const propsPerComponentId: {
[componentId: string]: ValueType;
} = {};
const argsPerStoryComponentId: {
[storyComponentId: string]: RPCs.StoryArgs | null;
} = {};
let types: CollectedTypes = {};
for (const componentId of componentIds) {
const component = componentIdToDetectedComponent[componentId];
Expand All @@ -111,6 +114,7 @@ export async function createWorkspace({
props = UNKNOWN_TYPE;
componentTypes = {};
}
argsPerStoryComponentId[componentId] = await story.extractArgs();
} else {
const { filePath, name } = decodeComponentId(componentId);
throw new Error(`Component ${name} not detected in ${filePath}.`);
Expand All @@ -120,6 +124,7 @@ export async function createWorkspace({
}
return {
props: propsPerComponentId,
args: argsPerStoryComponentId,
types,
};
});
Expand Down
2 changes: 1 addition & 1 deletion daemon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@previewjs/api": "workspace:*",
"@previewjs/core": "workspace:*",
"@previewjs/loader": "workspace:*",
"@types/node": "^20.5.0",
"@types/node": "^20.4.10",
"exclusive-promises": "^1.0.3",
"exit-hook": "^3.2.0",
"is-wsl": "^3.0.0",
Expand Down
2 changes: 1 addition & 1 deletion framework-plugins/preact/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@previewjs/testing": "workspace:*",
"pino": "^8.15.0",
"pino-pretty": "^10.2.0",
"preact": "^10.17.0",
"preact": "^10.16.0",
"rimraf": "^5.0.1",
"unbuild": "^1.2.1",
"vite": "^4.4.9",
Expand Down
Loading

0 comments on commit 77b854f

Please sign in to comment.