build(#10336): make .storybook as an individual TypeScript project
This commit is contained in:
parent
bf527cd6e7
commit
cc3fbefc83
|
@ -1,8 +1,9 @@
|
||||||
# (cd path/to/frontend; pnpm tsc --jsx react --jsxFactory h .storybook/generate.tsx && node .storybook/generate.js)
|
# (cd path/to/frontend; pnpm tsc -p .storybook)
|
||||||
|
# (cd path/to/frontend; node .storybook/generate.js)
|
||||||
/generate.js
|
/generate.js
|
||||||
# (cd path/to/frontend; pnpm tsc .storybook/preload-locale.ts && node .storybook/preload-locale.js)
|
# (cd path/to/frontend; node .storybook/preload-locale.js)
|
||||||
/preload-locale.js
|
/preload-locale.js
|
||||||
/locale.ts
|
/locale.ts
|
||||||
# (cd path/to/frontend; pnpm tsc .storybook/preload-theme.ts && node .storybook/preload-theme.js)
|
# (cd path/to/frontend; node .storybook/preload-theme.js)
|
||||||
/preload-theme.js
|
/preload-theme.js
|
||||||
/themes.ts
|
/themes.ts
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { basename, dirname } from 'node:path/posix';
|
||||||
import { promisify } from 'node:util';
|
import { promisify } from 'node:util';
|
||||||
import { GENERATOR, type State, generate } from 'astring';
|
import { GENERATOR, type State, generate } from 'astring';
|
||||||
import type * as estree from 'estree';
|
import type * as estree from 'estree';
|
||||||
import * as glob from 'glob';
|
import glob from 'glob';
|
||||||
import { format } from 'prettier';
|
import { format } from 'prettier';
|
||||||
|
|
||||||
interface SatisfiesExpression extends estree.BaseExpression {
|
interface SatisfiesExpression extends estree.BaseExpression {
|
||||||
|
@ -16,23 +16,69 @@ interface SatisfiesExpression extends estree.BaseExpression {
|
||||||
const generator = {
|
const generator = {
|
||||||
...GENERATOR,
|
...GENERATOR,
|
||||||
SatisfiesExpression(node: SatisfiesExpression, state: State) {
|
SatisfiesExpression(node: SatisfiesExpression, state: State) {
|
||||||
if (node.expression.type === 'ArrowFunctionExpression') {
|
switch (node.expression.type) {
|
||||||
state.write('(');
|
case 'ArrowFunctionExpression': {
|
||||||
this[node.expression.type](node.expression, state);
|
state.write('(');
|
||||||
state.write(')');
|
this[node.expression.type](node.expression, state);
|
||||||
} else {
|
state.write(')');
|
||||||
this[node.expression.type](node.expression, state);
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// @ts-ignore
|
||||||
|
this[node.expression.type](node.expression, state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state.write(' satisfies ');
|
state.write(' satisfies ');
|
||||||
this[node.reference.type](node.reference, state);
|
this[node.reference.type](node.reference, state);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SplitCamel<T extends string, YC extends string = '', YN extends readonly string[] = []> = T extends `${infer XH}${infer XR}`
|
||||||
|
? XR extends ''
|
||||||
|
? [...YN, Uncapitalize<`${YC}${XH}`>]
|
||||||
|
: XH extends Uppercase<XH>
|
||||||
|
? SplitCamel<XR, Lowercase<XH>, [...YN, YC]>
|
||||||
|
: SplitCamel<XR, `${YC}${XH}`, YN>
|
||||||
|
: YN;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
type SplitKebab<T extends string> = T extends `${infer XH}-${infer XR}`
|
||||||
|
? [XH, ...SplitKebab<XR>]
|
||||||
|
: [T];
|
||||||
|
|
||||||
|
type ToKebab<T extends readonly string[]> = T extends readonly [infer XO extends string]
|
||||||
|
? XO
|
||||||
|
: T extends readonly [infer XH extends string, ...infer XR extends readonly string[]]
|
||||||
|
? `${XH}${XR extends readonly string[] ? `-${ToKebab<XR>}` : ''}`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
type ToPascal<T extends readonly string[]> = T extends readonly [infer XH extends string, ...infer XR extends readonly string[]]
|
||||||
|
? `${Capitalize<XH>}${ToPascal<XR>}`
|
||||||
|
: '';
|
||||||
|
|
||||||
function h<T extends estree.Node>(component: T['type'], props: Omit<T, 'type'>): T {
|
function h<T extends estree.Node>(component: T['type'], props: Omit<T, 'type'>): T {
|
||||||
const type = component.replace(/(?:^|-)([a-z])/g, (_, c) => c.toUpperCase());
|
const type = component.replace(/(?:^|-)([a-z])/g, (_, c) => c.toUpperCase());
|
||||||
return Object.assign(props, { type }) as T;
|
return Object.assign(props, { type }) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace JSX {
|
||||||
|
type Element = never;
|
||||||
|
type ElementClass = never;
|
||||||
|
type ElementAttributesProperty = never;
|
||||||
|
type ElementChildrenAttribute = never;
|
||||||
|
type IntrinsicAttributes = never;
|
||||||
|
type IntrinsicClassAttributes<T> = never;
|
||||||
|
type IntrinsicElements = {
|
||||||
|
[T in keyof typeof generator as ToKebab<SplitCamel<Uncapitalize<T>>>]: {
|
||||||
|
[K in keyof Omit<Parameters<typeof generator[T]>[0], 'type'>]?: Parameters<typeof generator[T]>[0][K];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function toStories(component: string): string {
|
function toStories(component: string): string {
|
||||||
const msw = `${component.slice(0, -'.vue'.length)}.msw`;
|
const msw = `${component.slice(0, -'.vue'.length)}.msw`;
|
||||||
const implStories = `${component.slice(0, -'.vue'.length)}.stories.impl`;
|
const implStories = `${component.slice(0, -'.vue'.length)}.stories.impl`;
|
||||||
|
@ -52,14 +98,14 @@ function toStories(component: string): string {
|
||||||
<property
|
<property
|
||||||
key={<identifier name="layout" />}
|
key={<identifier name="layout" />}
|
||||||
value={<literal value={`${dir}/`.startsWith('src/pages/') ? 'fullscreen' : 'centered'} />}
|
value={<literal value={`${dir}/`.startsWith('src/pages/') ? 'fullscreen' : 'centered'} />}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
...hasMsw
|
...hasMsw
|
||||||
? [
|
? [
|
||||||
<property
|
<property
|
||||||
key={<identifier name="msw" />}
|
key={<identifier name="msw" />}
|
||||||
value={<identifier name="msw" />}
|
value={<identifier name="msw" />}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
shorthand
|
shorthand
|
||||||
/>,
|
/>,
|
||||||
]
|
]
|
||||||
|
@ -107,13 +153,12 @@ function toStories(component: string): string {
|
||||||
specifiers={[
|
specifiers={[
|
||||||
<import-default-specifier
|
<import-default-specifier
|
||||||
local={identifier}
|
local={identifier}
|
||||||
imported={identifier}
|
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>,
|
/>,
|
||||||
],
|
],
|
||||||
<variable-declaration
|
<variable-declaration
|
||||||
kind="const"
|
kind={"const" as const}
|
||||||
declarations={[
|
declarations={[
|
||||||
<variable-declarator
|
<variable-declarator
|
||||||
id={<identifier name="meta" />}
|
id={<identifier name="meta" />}
|
||||||
|
@ -125,12 +170,12 @@ function toStories(component: string): string {
|
||||||
<property
|
<property
|
||||||
key={<identifier name="title" />}
|
key={<identifier name="title" />}
|
||||||
value={literal}
|
value={literal}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
<property
|
<property
|
||||||
key={<identifier name="component" />}
|
key={<identifier name="component" />}
|
||||||
value={identifier}
|
value={identifier}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -148,7 +193,7 @@ function toStories(component: string): string {
|
||||||
<export-named-declaration
|
<export-named-declaration
|
||||||
declaration={
|
declaration={
|
||||||
<variable-declaration
|
<variable-declaration
|
||||||
kind="const"
|
kind={"const" as const}
|
||||||
declarations={[
|
declarations={[
|
||||||
<variable-declarator
|
<variable-declarator
|
||||||
id={<identifier name="Default" />}
|
id={<identifier name="Default" />}
|
||||||
|
@ -169,7 +214,7 @@ function toStories(component: string): string {
|
||||||
<property
|
<property
|
||||||
key={<identifier name="argTypes" />}
|
key={<identifier name="argTypes" />}
|
||||||
value={<identifier name="argTypes" />}
|
value={<identifier name="argTypes" />}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
shorthand
|
shorthand
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
|
@ -190,13 +235,13 @@ function toStories(component: string): string {
|
||||||
<property
|
<property
|
||||||
key={identifier}
|
key={identifier}
|
||||||
value={identifier}
|
value={identifier}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
shorthand
|
shorthand
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
<property
|
<property
|
||||||
key={<identifier name="props" />}
|
key={<identifier name="props" />}
|
||||||
|
@ -213,12 +258,12 @@ function toStories(component: string): string {
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
<property
|
<property
|
||||||
key={<identifier name="template" />}
|
key={<identifier name="template" />}
|
||||||
value={<literal value={`<${identifier.name} v-bind="$props" />`} />}
|
value={<literal value={`<${identifier.name} v-bind="$props" />`} />}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -230,12 +275,12 @@ function toStories(component: string): string {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
method
|
method
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
<property
|
<property
|
||||||
key={<identifier name="parameters" />}
|
key={<identifier name="parameters" />}
|
||||||
value={parameters}
|
value={parameters}
|
||||||
kind="init"
|
kind={"init" as const}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"allowUnusedLabels": false,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"jsxFactory": "h"
|
||||||
|
},
|
||||||
|
"files": ["./generate.tsx", "./preload-locale.ts", "./preload-theme.ts"]
|
||||||
|
}
|
|
@ -43,5 +43,8 @@
|
||||||
".eslintrc.js",
|
".eslintrc.js",
|
||||||
"./**/*.ts",
|
"./**/*.ts",
|
||||||
"./**/*.vue"
|
"./**/*.vue"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
".storybook/**/*",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue