From 12e463340765704d87170a85afaf03a8af1ce71a Mon Sep 17 00:00:00 2001
From: Jonah Henriksson <33059163+JonahPlusPlus@users.noreply.github.com>
Date: Wed, 13 Nov 2024 12:12:55 -0500
Subject: [PATCH] 1.0.0-beta.6: Improve code snippets and CD (#16)
* Improve code snippets
* Update solid.yml
* Fix CD expressions
* Generate empty args for render function
* Update versions
---
.github/workflows/solid-vite.yml | 2 +
.github/workflows/solid.yml | 6 +-
packages/frameworks/solid-vite/package.json | 2 +-
packages/renderers/solid/package.json | 2 +-
.../solid/src/docs/sourceDecorator.test.tsx | 71 +++++++++++
.../solid/src/docs/sourceDecorator.tsx | 117 ++++++++++++++++--
6 files changed, 182 insertions(+), 18 deletions(-)
diff --git a/.github/workflows/solid-vite.yml b/.github/workflows/solid-vite.yml
index 74dee7e..90d9853 100644
--- a/.github/workflows/solid-vite.yml
+++ b/.github/workflows/solid-vite.yml
@@ -6,12 +6,14 @@ on:
description: Publish?
required: false
type: boolean
+ default: false
workflow_dispatch:
inputs:
publish:
description: Publish?
required: false
type: boolean
+ default: false
defaults:
run:
working-directory: packages/frameworks/solid-vite
diff --git a/.github/workflows/solid.yml b/.github/workflows/solid.yml
index a848483..7f839eb 100644
--- a/.github/workflows/solid.yml
+++ b/.github/workflows/solid.yml
@@ -12,14 +12,13 @@ on:
- packages/renderers/solid/**
release:
types: [published]
- branches:
- - main
workflow_dispatch:
inputs:
publish:
description: Publish?
required: false
type: boolean
+ default: false
defaults:
run:
working-directory: packages/renderers/solid
@@ -43,4 +42,5 @@ jobs:
needs: solid-workflow
uses: ./.github/workflows/solid-vite.yml
with:
- publish: ${{ github.event_name == 'release' || inputs.publish }}
+ publish: ${{ (github.event_name == 'release') || (inputs.publish == true) }}
+ secrets: inherit
diff --git a/packages/frameworks/solid-vite/package.json b/packages/frameworks/solid-vite/package.json
index ad160d0..cc1aaf6 100644
--- a/packages/frameworks/solid-vite/package.json
+++ b/packages/frameworks/solid-vite/package.json
@@ -1,7 +1,7 @@
{
"name": "storybook-solidjs-vite",
"type": "module",
- "version": "1.0.0-beta.5",
+ "version": "1.0.0-beta.6",
"description": "Storybook for SolidJS and Vite: Develop SolidJS in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/packages/renderers/solid/package.json b/packages/renderers/solid/package.json
index 5445aa9..4250087 100644
--- a/packages/renderers/solid/package.json
+++ b/packages/renderers/solid/package.json
@@ -1,7 +1,7 @@
{
"name": "storybook-solidjs",
"type": "module",
- "version": "1.0.0-beta.5",
+ "version": "1.0.0-beta.6",
"description": "Storybook SolidJS renderer",
"keywords": [
"storybook"
diff --git a/packages/renderers/solid/src/docs/sourceDecorator.test.tsx b/packages/renderers/solid/src/docs/sourceDecorator.test.tsx
index 3a2f28e..ac50768 100644
--- a/packages/renderers/solid/src/docs/sourceDecorator.test.tsx
+++ b/packages/renderers/solid/src/docs/sourceDecorator.test.tsx
@@ -74,6 +74,77 @@ test('component with typescript', () => {
`);
});
+test('component with expression children', () => {
+ const newSrc = generateSolidSource(
+ 'Component',
+ '{ args: { children: { do: () => { return 32; } } } }',
+ );
+
+ expect(newSrc).toMatchInlineSnapshot(`
+ "{{
+ do: () => {
+ return 32;
+ }
+ }}"
+ `);
+});
+
+test('component with render function', () => {
+ const newSrc = generateSolidSource(
+ 'Component',
+ '{ render: () => Hello }',
+ );
+
+ expect(newSrc).toMatchInlineSnapshot(
+ `"Hello"`,
+ );
+});
+
+test('component with render function and args', () => {
+ const newSrc = generateSolidSource(
+ 'Component',
+ '{ args: { foo: 32 }, render: (args) => Hello }',
+ );
+
+ expect(newSrc).toMatchInlineSnapshot(`
+ "const args = {
+ foo: 32
+ };
+
+ Hello"
+ `);
+});
+
+test('component with render function and missing args', () => {
+ const newSrc = generateSolidSource(
+ 'Component',
+ '{ render: (args) => Hello }',
+ );
+
+ expect(newSrc).toMatchInlineSnapshot(`
+ "const args = {};
+
+ Hello"
+ `);
+});
+
+test('component with render function and args and ctx', () => {
+ const newSrc = generateSolidSource(
+ 'Component',
+ '{ args: { foo: 32 }, render: (args, ctx) => Hello }',
+ );
+
+ expect(newSrc).toMatchInlineSnapshot(`
+ "const args = {
+ foo: 32
+ };
+
+ var ctx;
+
+ Hello"
+ `);
+});
+
test('component missing story config', () => {
const newSrc = () => generateSolidSource('Component', '5 + 4');
diff --git a/packages/renderers/solid/src/docs/sourceDecorator.tsx b/packages/renderers/solid/src/docs/sourceDecorator.tsx
index 68e711d..896d7af 100644
--- a/packages/renderers/solid/src/docs/sourceDecorator.tsx
+++ b/packages/renderers/solid/src/docs/sourceDecorator.tsx
@@ -84,7 +84,65 @@ export const sourceDecorator = (
* Generate Solid JSX from story source.
*/
export function generateSolidSource(name: string, src: string): string {
- const { attributes, children } = parseProps(src);
+ const ast = parser.parseExpression(src, { plugins: ['jsx', 'typescript'] });
+ const { attributes, children, original } = parseArgs(ast);
+ const render = parseRender(ast);
+
+ // If there is a render function, display it to the best of our ability.
+ if (render) {
+ const { body, params } = render;
+ let newSrc = '';
+
+ // Add arguments declaration.
+ if (params[0]) {
+ const args = original ?? {
+ type: 'ObjectExpression',
+ properties: [],
+ };
+
+ const argsStatement = {
+ type: 'VariableDeclaration',
+ kind: 'const',
+ declarations: [
+ {
+ type: 'VariableDeclarator',
+ id: {
+ type: 'Identifier',
+ name: params[0],
+ },
+ init: args,
+ },
+ ],
+ };
+
+ newSrc += generate(argsStatement, { compact: false }).code + '\n\n';
+ }
+
+ // Add context declaration.
+ if (params[1]) {
+ const ctxStatement = {
+ type: 'VariableDeclaration',
+ kind: 'var',
+ declarations: [
+ {
+ type: 'VariableDeclarator',
+ id: {
+ type: 'Identifier',
+ name: params[1],
+ },
+ },
+ ],
+ };
+
+ newSrc += generate(ctxStatement, { compact: false }).code + '\n\n';
+ }
+
+ newSrc += generate(body, { compact: false }).code;
+
+ return newSrc;
+ }
+
+ // Otherwise, render a component with the arguments.
const selfClosing = children == null || children.length == 0;
@@ -138,49 +196,82 @@ function toJSXChild(node: any): object {
if (t.isExpression(node)) {
return {
type: 'JSXExpressionContainer',
- value: node,
+ expression: node,
};
}
return {
type: 'JSXExpressionContainer',
- value: t.jsxEmptyExpression(),
+ expression: t.jsxEmptyExpression(),
+ };
+}
+/** Story render function. */
+interface SolidRender {
+ body: object;
+ params: string[];
+}
+
+function parseRender(ast: any): SolidRender | null {
+ if (ast.type != 'ObjectExpression') throw 'Expected `ObjectExpression` type';
+ // Find render property.
+ const renderProp = ast.properties.find((v: any) => {
+ if (v.type != 'ObjectProperty') return false;
+ if (v.key.type != 'Identifier') return false;
+ return v.key.name == 'render';
+ }) as any | undefined;
+ if (!renderProp) return null;
+
+ const renderFn = renderProp.value;
+ if (
+ renderFn.type != 'ArrowFunctionExpression' &&
+ renderFn.type != 'FunctionExpression'
+ ) {
+ console.warn('`render` property is not a function, skipping...');
+ return null;
+ }
+
+ return {
+ body: renderFn.body,
+ params: renderFn.params.map((x: any) => x.name),
};
}
-interface SolidProps {
+/** Story arguments. */
+interface SolidArgs {
attributes: object[];
children: object[] | null;
+ original: object | null;
}
/**
- * Parses component properties from source expression.
+ * Parses component arguments from source expression.
*
* The source code will be in the form of a `Story` object.
*/
-function parseProps(src: string): SolidProps {
- const ast = parser.parseExpression(src, { plugins: ['jsx', 'typescript'] });
+function parseArgs(ast: any): SolidArgs {
if (ast.type != 'ObjectExpression') throw 'Expected `ObjectExpression` type';
// Find args property.
- const args_prop = ast.properties.find((v: any) => {
+ const argsProp = ast.properties.find((v: any) => {
if (v.type != 'ObjectProperty') return false;
if (v.key.type != 'Identifier') return false;
return v.key.name == 'args';
}) as any | undefined;
// No args, so there aren't any properties or children.
- if (!args_prop)
+ if (!argsProp)
return {
attributes: [],
children: null,
+ original: null,
};
// Get arguments.
- const args = args_prop.value;
- if (args.type != 'ObjectExpression') throw 'Expected `ObjectExpression` type';
+ const original = argsProp.value;
+ if (original.type != 'ObjectExpression')
+ throw 'Expected `ObjectExpression` type';
// Construct props object, where values are source code slices.
const attributes: object[] = [];
let children: object[] | null = null;
- for (const el of args.properties) {
+ for (const el of original.properties) {
let attr: object | null = null;
switch (el.type) {
@@ -210,7 +301,7 @@ function parseProps(src: string): SolidProps {
}
}
- return { attributes, children };
+ return { attributes, children, original };
}
/**