create-backbone-template 0.1.0
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.
- package/README.md +33 -0
- package/bin/create-backbone-template.js +5 -0
- package/package.json +30 -0
- package/src/create-backbone-template.js +204 -0
- package/template/.agents/skills/agent-browser/SKILL.md +55 -0
- package/template/.agents/skills/create-plan/SKILL.md +52 -0
- package/template/.agents/skills/create-plan/agents/openai.yaml +4 -0
- package/template/.agents/skills/create-pr-presentation/SKILL.md +86 -0
- package/template/.agents/skills/create-pr-presentation/agents/openai.yaml +4 -0
- package/template/.agents/skills/implement-plan/SKILL.md +26 -0
- package/template/.agents/skills/implement-plan/agents/openai.yaml +4 -0
- package/template/.agents/skills/review-plan/SKILL.md +38 -0
- package/template/.agents/skills/review-plan/agents/openai.yaml +4 -0
- package/template/.env.schema +30 -0
- package/template/.env.test +6 -0
- package/template/.oxlintrc.json +67 -0
- package/template/.vscode/extensions.json +3 -0
- package/template/.vscode/settings.json +23 -0
- package/template/AGENTS.md +55 -0
- package/template/Cargo.lock +2648 -0
- package/template/Cargo.toml +29 -0
- package/template/Justfile +140 -0
- package/template/README.md +72 -0
- package/template/TODO.md +1 -0
- package/template/_gitignore +12 -0
- package/template/buf.gen.yaml +7 -0
- package/template/buf.yaml +10 -0
- package/template/client/.oxfmtrc.json +8 -0
- package/template/client/.oxlintrc.json +57 -0
- package/template/client/README.md +19 -0
- package/template/client/_gitignore +5 -0
- package/template/client/index.html +12 -0
- package/template/client/package.json +47 -0
- package/template/client/packages/design-system/package.json +19 -0
- package/template/client/packages/design-system/src/index.ts +2 -0
- package/template/client/packages/design-system-basic/package.json +18 -0
- package/template/client/packages/design-system-basic/src/button.stories.tsx +50 -0
- package/template/client/packages/design-system-basic/src/button.tsx +26 -0
- package/template/client/packages/design-system-basic/src/empty-state.stories.tsx +18 -0
- package/template/client/packages/design-system-basic/src/empty-state.tsx +17 -0
- package/template/client/packages/design-system-basic/src/form-field.stories.tsx +15 -0
- package/template/client/packages/design-system-basic/src/form-field.tsx +10 -0
- package/template/client/packages/design-system-basic/src/form.stories.tsx +27 -0
- package/template/client/packages/design-system-basic/src/form.tsx +9 -0
- package/template/client/packages/design-system-basic/src/heading.stories.tsx +14 -0
- package/template/client/packages/design-system-basic/src/heading.tsx +25 -0
- package/template/client/packages/design-system-basic/src/index.tsx +15 -0
- package/template/client/packages/design-system-basic/src/inline.stories.tsx +13 -0
- package/template/client/packages/design-system-basic/src/inline.tsx +5 -0
- package/template/client/packages/design-system-basic/src/layout.stories.tsx +24 -0
- package/template/client/packages/design-system-basic/src/layout.tsx +14 -0
- package/template/client/packages/design-system-basic/src/loader.stories.tsx +8 -0
- package/template/client/packages/design-system-basic/src/loader.tsx +11 -0
- package/template/client/packages/design-system-basic/src/navigation.stories.tsx +16 -0
- package/template/client/packages/design-system-basic/src/navigation.tsx +18 -0
- package/template/client/packages/design-system-basic/src/notice.stories.tsx +13 -0
- package/template/client/packages/design-system-basic/src/notice.tsx +5 -0
- package/template/client/packages/design-system-basic/src/stack.stories.tsx +17 -0
- package/template/client/packages/design-system-basic/src/stack.tsx +5 -0
- package/template/client/packages/design-system-basic/src/styles.css +254 -0
- package/template/client/packages/design-system-basic/src/text-input.stories.tsx +13 -0
- package/template/client/packages/design-system-basic/src/text-input.tsx +5 -0
- package/template/client/packages/design-system-basic/src/text.stories.tsx +21 -0
- package/template/client/packages/design-system-basic/src/text.tsx +5 -0
- package/template/client/packages/design-system-contract/package.json +15 -0
- package/template/client/packages/design-system-contract/src/button.ts +10 -0
- package/template/client/packages/design-system-contract/src/empty-state.ts +9 -0
- package/template/client/packages/design-system-contract/src/form-field.ts +9 -0
- package/template/client/packages/design-system-contract/src/form.ts +9 -0
- package/template/client/packages/design-system-contract/src/heading.ts +9 -0
- package/template/client/packages/design-system-contract/src/index.ts +13 -0
- package/template/client/packages/design-system-contract/src/inline.ts +7 -0
- package/template/client/packages/design-system-contract/src/layout.ts +8 -0
- package/template/client/packages/design-system-contract/src/loader.ts +7 -0
- package/template/client/packages/design-system-contract/src/navigation.ts +13 -0
- package/template/client/packages/design-system-contract/src/notice.ts +8 -0
- package/template/client/packages/design-system-contract/src/stack.ts +8 -0
- package/template/client/packages/design-system-contract/src/text-input.ts +5 -0
- package/template/client/packages/design-system-contract/src/text.ts +9 -0
- package/template/client/packages/design-system-lint/fixtures/invalid/external-ui-import.tsx +5 -0
- package/template/client/packages/design-system-lint/fixtures/invalid/raw-dom-jsx.tsx +3 -0
- package/template/client/packages/design-system-lint/fixtures/invalid/two-violations.tsx +7 -0
- package/template/client/packages/design-system-lint/fixtures/valid/design-system-only.tsx +13 -0
- package/template/client/packages/design-system-lint/package.json +23 -0
- package/template/client/packages/design-system-lint/src/check-design-system-architecture.ts +22 -0
- package/template/client/packages/design-system-lint/src/design-system-architecture.ts +286 -0
- package/template/client/packages/design-system-lint/src/oxlint-plugin.ts +11 -0
- package/template/client/packages/design-system-lint/src/page-architecture.ts +382 -0
- package/template/client/packages/design-system-lint/src/rules.ts +111 -0
- package/template/client/packages/design-system-lint/test/design-system-architecture.test.ts +243 -0
- package/template/client/packages/design-system-lint/test/oxlint-fixtures.test.ts +159 -0
- package/template/client/packages/design-system-lint/test/page-architecture.test.ts +175 -0
- package/template/client/packages/design-system-lint/test/rules.test.ts +65 -0
- package/template/client/packages/design-system-lint/tsconfig.json +29 -0
- package/template/client/src/App.tsx +77 -0
- package/template/client/src/design-system-components.test.tsx +75 -0
- package/template/client/src/gen/helloworld/v1/helloworld_pb.ts +63 -0
- package/template/client/src/main.tsx +18 -0
- package/template/client/src/pages/hello/hello-page.stories.tsx +20 -0
- package/template/client/src/pages/hello/hello-page.test.tsx +90 -0
- package/template/client/src/pages/hello/hello-page.tsx +126 -0
- package/template/client/src/pages/page.ts +20 -0
- package/template/client/src/testing/create-preview-events.test.ts +36 -0
- package/template/client/src/testing/create-preview-events.ts +30 -0
- package/template/client/src/vite-env.d.ts +1 -0
- package/template/client/tsconfig.json +32 -0
- package/template/client/vite.config.ts +21 -0
- package/template/client/vite.ladle.config.ts +5 -0
- package/template/e2e/.gherkin-lintrc +20 -0
- package/template/e2e/.oxfmtrc.json +15 -0
- package/template/e2e/.oxlintrc.json +37 -0
- package/template/e2e/_gitignore +4 -0
- package/template/e2e/features/helloworld.feature +10 -0
- package/template/e2e/package.json +42 -0
- package/template/e2e/playwright.config.ts +16 -0
- package/template/e2e/support/app-gherkin.ts +4 -0
- package/template/e2e/support/fixtures.ts +236 -0
- package/template/e2e/support/gherkin-fixtures/duplicate-id.feature +9 -0
- package/template/e2e/support/gherkin-fixtures/duplicate-id.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/extra-implementation.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/extra-step.spec.ts +10 -0
- package/template/e2e/support/gherkin-fixtures/happy-path.spec.ts +4 -0
- package/template/e2e/support/gherkin-fixtures/missing-id.feature +4 -0
- package/template/e2e/support/gherkin-fixtures/missing-id.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/missing-implementation.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/missing-step.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/playwright.config.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/scenario-outline.feature +9 -0
- package/template/e2e/support/gherkin-fixtures/scenario-outline.spec.ts +7 -0
- package/template/e2e/support/gherkin-fixtures/step-mismatch.spec.ts +9 -0
- package/template/e2e/support/gherkin-fixtures/valid-implementations.ts +23 -0
- package/template/e2e/support/gherkin-fixtures/valid-scenarios.feature +26 -0
- package/template/e2e/support/gherkin.test.ts +184 -0
- package/template/e2e/support/gherkin.ts +321 -0
- package/template/e2e/support/oxlint-plugin.test.ts +328 -0
- package/template/e2e/support/oxlint-plugin.ts +485 -0
- package/template/e2e/tests/helloworld.spec.ts +39 -0
- package/template/e2e/tsconfig.json +26 -0
- package/template/e2e/tsconfig.oxlint-plugin.json +12 -0
- package/template/package.json +9 -0
- package/template/pnpm-lock.yaml +10723 -0
- package/template/pnpm-workspace.yaml +8 -0
- package/template/pr-slide/README.md +95 -0
- package/template/pr-slide/package.json +23 -0
- package/template/pr-slide/src/cli.js +262 -0
- package/template/pr-slide/src/generate-pr-deck.js +833 -0
- package/template/pr-slide/src/git-context.js +91 -0
- package/template/pr-slide/src/presentation-paths.js +9 -0
- package/template/pr-slide/src/presentations.js +53 -0
- package/template/pr-slide/test/generate-pr-deck.test.js +118 -0
- package/template/pr-slide/test/presentation-paths.test.js +14 -0
- package/template/pr-slide/test/presentations.test.js +50 -0
- package/template/proto/helloworld/v1/helloworld.proto +15 -0
- package/template/scripts/run-e2e.sh +10 -0
- package/template/server/Cargo.toml +26 -0
- package/template/server/build.rs +9 -0
- package/template/server/dylint/backbone_server_lints/.cargo/config.toml +6 -0
- package/template/server/dylint/backbone_server_lints/Cargo.lock +1581 -0
- package/template/server/dylint/backbone_server_lints/Cargo.toml +21 -0
- package/template/server/dylint/backbone_server_lints/README.md +5 -0
- package/template/server/dylint/backbone_server_lints/_gitignore +1 -0
- package/template/server/dylint/backbone_server_lints/rust-toolchain +3 -0
- package/template/server/dylint/backbone_server_lints/src/lib.rs +612 -0
- package/template/server/dylint/backbone_server_lints/ui/lib.rs +4 -0
- package/template/server/dylint/backbone_server_lints/ui/lib.stderr +10 -0
- package/template/server/dylint/backbone_server_lints/ui/long_file.rs +303 -0
- package/template/server/dylint/backbone_server_lints/ui/long_file.stderr +6 -0
- package/template/server/dylint/backbone_server_lints/ui/main.rs +59 -0
- package/template/server/dylint/backbone_server_lints/ui/main.stderr +85 -0
- package/template/server/migrations/20260520120000_create_projects.sql +12 -0
- package/template/server/migrations/20260524160000_create_hello_world_inputs.sql +12 -0
- package/template/server/src/config.rs +27 -0
- package/template/server/src/db/hello_world.rs +34 -0
- package/template/server/src/db/hello_world_tests.rs +11 -0
- package/template/server/src/db/mod.rs +39 -0
- package/template/server/src/lib.rs +10 -0
- package/template/server/src/main.rs +43 -0
- package/template/server/src/rpc/greeter/mod.rs +31 -0
- package/template/server/src/rpc/greeter/say_hello.rs +27 -0
- package/template/server/src/rpc/mod.rs +8 -0
- package/template/server/src/state.rs +13 -0
- package/template/skills-lock.json +11 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backbone/design-system-lint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/src/oxlint-plugin.d.ts",
|
|
9
|
+
"default": "./dist/src/oxlint-plugin.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc --project tsconfig.json",
|
|
14
|
+
"check:architecture": "node dist/src/check-design-system-architecture.js",
|
|
15
|
+
"test": "pnpm run build && node --test \"dist/test/**/*.test.js\"",
|
|
16
|
+
"test:prepared": "node --test \"dist/test/**/*.test.js\""
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^25.9.1",
|
|
20
|
+
"oxlint": "^1.66.0",
|
|
21
|
+
"typescript": "^6.0.3"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import { checkDesignSystemArchitecture } from "./design-system-architecture.js"
|
|
3
|
+
import { checkPageArchitecture } from "./page-architecture.js"
|
|
4
|
+
|
|
5
|
+
const designSystemResult = checkDesignSystemArchitecture({
|
|
6
|
+
contractSrcDir: path.resolve("../design-system-contract/src"),
|
|
7
|
+
implementationSrcDir: path.resolve("../design-system-basic/src"),
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const pageResult = checkPageArchitecture({
|
|
11
|
+
pagesSrcDir: path.resolve("../../src/pages"),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const errors = [...designSystemResult.errors, ...pageResult.errors]
|
|
15
|
+
|
|
16
|
+
if (errors.length > 0) {
|
|
17
|
+
for (const error of errors) {
|
|
18
|
+
console.error(error)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
process.exitCode = 1
|
|
22
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import ts from "typescript"
|
|
4
|
+
|
|
5
|
+
export type DesignSystemArchitecturePaths = {
|
|
6
|
+
contractSrcDir: string
|
|
7
|
+
implementationSrcDir: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type DesignSystemArchitectureResult = {
|
|
11
|
+
errors: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type ComponentFile = {
|
|
15
|
+
absolutePath: string
|
|
16
|
+
componentPath: string
|
|
17
|
+
relativePath: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function checkDesignSystemArchitecture(
|
|
21
|
+
paths: DesignSystemArchitecturePaths,
|
|
22
|
+
): DesignSystemArchitectureResult {
|
|
23
|
+
const contractFiles = findComponentFiles(paths.contractSrcDir, ".ts")
|
|
24
|
+
const implementationFiles = findComponentFiles(paths.implementationSrcDir, ".tsx")
|
|
25
|
+
const errors = [
|
|
26
|
+
...checkMatchingComponentFiles(contractFiles, implementationFiles),
|
|
27
|
+
...checkBarrelExports(paths.contractSrcDir, "index.ts", contractFiles, "Contract"),
|
|
28
|
+
...checkBarrelExports(
|
|
29
|
+
paths.implementationSrcDir,
|
|
30
|
+
"index.tsx",
|
|
31
|
+
implementationFiles,
|
|
32
|
+
"Implementation",
|
|
33
|
+
),
|
|
34
|
+
...checkContractFiles(contractFiles),
|
|
35
|
+
...checkImplementationFiles(implementationFiles, paths.implementationSrcDir),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
return { errors }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function findComponentFiles(srcDir: string, extension: ".ts" | ".tsx") {
|
|
42
|
+
if (!fs.existsSync(srcDir)) {
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return findFiles(srcDir)
|
|
47
|
+
.filter((filePath) => isComponentFile(filePath, extension))
|
|
48
|
+
.map((absolutePath) => {
|
|
49
|
+
const relativePath = normalizePath(path.relative(srcDir, absolutePath))
|
|
50
|
+
const componentPath = relativePath.slice(0, -extension.length)
|
|
51
|
+
|
|
52
|
+
return { absolutePath, componentPath, relativePath }
|
|
53
|
+
})
|
|
54
|
+
.sort((left, right) => left.componentPath.localeCompare(right.componentPath))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function findFiles(rootDir: string): string[] {
|
|
58
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true })
|
|
59
|
+
const files: string[] = []
|
|
60
|
+
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
const absolutePath = path.join(rootDir, entry.name)
|
|
63
|
+
|
|
64
|
+
if (entry.isDirectory()) {
|
|
65
|
+
files.push(...findFiles(absolutePath))
|
|
66
|
+
} else if (entry.isFile()) {
|
|
67
|
+
files.push(absolutePath)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return files
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isComponentFile(filePath: string, extension: ".ts" | ".tsx") {
|
|
75
|
+
const fileName = path.basename(filePath)
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
fileName !== `index${extension}` &&
|
|
79
|
+
!fileName.endsWith(".stories.tsx") &&
|
|
80
|
+
fileName.endsWith(extension)
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function checkMatchingComponentFiles(
|
|
85
|
+
contractFiles: ComponentFile[],
|
|
86
|
+
implementationFiles: ComponentFile[],
|
|
87
|
+
) {
|
|
88
|
+
const errors: string[] = []
|
|
89
|
+
const contractComponentPaths = new Set(contractFiles.map((file) => file.componentPath))
|
|
90
|
+
const implementationComponentPaths = new Set(
|
|
91
|
+
implementationFiles.map((file) => file.componentPath),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
for (const componentPath of implementationComponentPaths) {
|
|
95
|
+
if (!contractComponentPaths.has(componentPath)) {
|
|
96
|
+
errors.push(
|
|
97
|
+
`Component "${componentPath}" exists in implementation but is missing from contract.`,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (const componentPath of contractComponentPaths) {
|
|
103
|
+
if (!implementationComponentPaths.has(componentPath)) {
|
|
104
|
+
errors.push(
|
|
105
|
+
`Component "${componentPath}" exists in contract but is missing from implementation.`,
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return errors
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function checkContractFiles(files: ComponentFile[]) {
|
|
114
|
+
return files.flatMap(checkContractExports)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function checkImplementationFiles(files: ComponentFile[], implementationSrcDir: string) {
|
|
118
|
+
return files.flatMap((file) => [
|
|
119
|
+
...checkImplementationExport(file),
|
|
120
|
+
...checkColocatedStory(file, implementationSrcDir),
|
|
121
|
+
])
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function checkBarrelExports(
|
|
125
|
+
srcDir: string,
|
|
126
|
+
barrelFileName: "index.ts" | "index.tsx",
|
|
127
|
+
componentFiles: ComponentFile[],
|
|
128
|
+
packageName: "Contract" | "Implementation",
|
|
129
|
+
) {
|
|
130
|
+
const barrelRelativePath = barrelFileName
|
|
131
|
+
const barrelAbsolutePath = path.join(srcDir, barrelFileName)
|
|
132
|
+
const expectedExports = componentFiles.map((file) => `./${file.componentPath}`).sort()
|
|
133
|
+
const actualExports = getBarrelExports(barrelAbsolutePath)
|
|
134
|
+
const errors: string[] = []
|
|
135
|
+
|
|
136
|
+
for (const exportPath of expectedExports) {
|
|
137
|
+
if (!actualExports.has(exportPath)) {
|
|
138
|
+
errors.push(`${packageName} barrel "${barrelRelativePath}" must export "${exportPath}".`)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const exportPath of actualExports) {
|
|
143
|
+
if (!expectedExports.includes(exportPath)) {
|
|
144
|
+
errors.push(`${packageName} barrel "${barrelRelativePath}" must not export "${exportPath}".`)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return errors
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function checkContractExports(file: ComponentFile) {
|
|
152
|
+
const actualExports = getNamedExports(file.absolutePath)
|
|
153
|
+
const componentName = toPascalCase(path.basename(file.componentPath))
|
|
154
|
+
const expectedExports = [`${componentName}Component`, `${componentName}Props`].sort()
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
actualExports.length === 2 &&
|
|
158
|
+
[...actualExports].sort().join("\n") === expectedExports.join("\n")
|
|
159
|
+
) {
|
|
160
|
+
return []
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return [
|
|
164
|
+
`Contract component file "${file.relativePath}" must export exactly "${expectedExports[0]}" and "${expectedExports[1]}".`,
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function checkImplementationExport(file: ComponentFile) {
|
|
169
|
+
const actualExports = getNamedExports(file.absolutePath)
|
|
170
|
+
const expectedExport = toPascalCase(path.basename(file.componentPath))
|
|
171
|
+
|
|
172
|
+
if (actualExports.length === 1 && actualExports[0] === expectedExport) {
|
|
173
|
+
return []
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return [
|
|
177
|
+
`Implementation component file "${file.relativePath}" must export exactly "${expectedExport}".`,
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function checkColocatedStory(file: ComponentFile, implementationSrcDir: string) {
|
|
182
|
+
const expectedStoryPath = `${file.componentPath}.stories.tsx`
|
|
183
|
+
const absoluteStoryPath = path.join(implementationSrcDir, expectedStoryPath)
|
|
184
|
+
|
|
185
|
+
if (fs.existsSync(absoluteStoryPath)) {
|
|
186
|
+
return []
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return [
|
|
190
|
+
`Implementation component "${file.componentPath}" must have a colocated story file at "${expectedStoryPath}".`,
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getBarrelExports(filePath: string) {
|
|
195
|
+
if (!fs.existsSync(filePath)) {
|
|
196
|
+
return new Set<string>()
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const sourceText = fs.readFileSync(filePath, "utf8")
|
|
200
|
+
const sourceFile = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true)
|
|
201
|
+
const exports = new Set<string>()
|
|
202
|
+
|
|
203
|
+
for (const statement of sourceFile.statements) {
|
|
204
|
+
if (!ts.isExportDeclaration(statement) || statement.moduleSpecifier === undefined) {
|
|
205
|
+
continue
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
209
|
+
exports.add(statement.moduleSpecifier.text)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return exports
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function getNamedExports(filePath: string) {
|
|
217
|
+
const sourceText = fs.readFileSync(filePath, "utf8")
|
|
218
|
+
const sourceFile = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true)
|
|
219
|
+
const exports: string[] = []
|
|
220
|
+
|
|
221
|
+
for (const statement of sourceFile.statements) {
|
|
222
|
+
const exportedDeclarationName = getExportedDeclarationName(statement)
|
|
223
|
+
|
|
224
|
+
if (exportedDeclarationName !== undefined) {
|
|
225
|
+
exports.push(exportedDeclarationName)
|
|
226
|
+
} else if (ts.isExportDeclaration(statement) && statement.exportClause !== undefined) {
|
|
227
|
+
if (ts.isNamedExports(statement.exportClause)) {
|
|
228
|
+
exports.push(...statement.exportClause.elements.map((element) => element.name.text))
|
|
229
|
+
} else {
|
|
230
|
+
exports.push("*")
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return exports.sort()
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function getExportedDeclarationName(statement: ts.Statement) {
|
|
239
|
+
if (!hasExportModifier(statement)) {
|
|
240
|
+
return undefined
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (ts.isVariableStatement(statement)) {
|
|
244
|
+
const firstDeclaration = statement.declarationList.declarations[0]
|
|
245
|
+
|
|
246
|
+
if (
|
|
247
|
+
firstDeclaration !== undefined &&
|
|
248
|
+
statement.declarationList.declarations.length === 1 &&
|
|
249
|
+
ts.isIdentifier(firstDeclaration.name)
|
|
250
|
+
) {
|
|
251
|
+
return firstDeclaration.name.text
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (
|
|
256
|
+
(ts.isFunctionDeclaration(statement) ||
|
|
257
|
+
ts.isClassDeclaration(statement) ||
|
|
258
|
+
ts.isInterfaceDeclaration(statement) ||
|
|
259
|
+
ts.isTypeAliasDeclaration(statement)) &&
|
|
260
|
+
statement.name !== undefined
|
|
261
|
+
) {
|
|
262
|
+
return statement.name.text
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return "*"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function hasExportModifier(statement: ts.Statement) {
|
|
269
|
+
return (
|
|
270
|
+
ts.canHaveModifiers(statement) &&
|
|
271
|
+
ts
|
|
272
|
+
.getModifiers(statement)
|
|
273
|
+
?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) === true
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function toPascalCase(fileName: string) {
|
|
278
|
+
return fileName
|
|
279
|
+
.split("-")
|
|
280
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
281
|
+
.join("")
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function normalizePath(filePath: string) {
|
|
285
|
+
return filePath.split(path.sep).join("/")
|
|
286
|
+
}
|