@meistrari/tela-build 1.38.0 → 1.38.2
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.
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { existsSync, writeFileSync, mkdirSync, lstatSync, readFileSync, symlinkSync } from 'node:fs'
|
|
3
3
|
import { defineNuxtModule, createResolver } from '@nuxt/kit'
|
|
4
|
-
import { dirname,
|
|
4
|
+
import { dirname, resolve } from 'pathe'
|
|
5
5
|
import { collectComponentDocs, generateMarkdown, generateDocsToDirectory } from '../../lib/doc-generator'
|
|
6
|
-
import { telaBuildSkill } from '../../lib/tela-build-skill'
|
|
7
6
|
import { ensureOverlayTsconfig } from '../../lib/extractors/volar-extract'
|
|
8
7
|
|
|
9
8
|
export interface TelaBuildDocsOptions {
|
|
@@ -13,11 +12,6 @@ export interface TelaBuildDocsOptions {
|
|
|
13
12
|
enabled?: boolean
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
interface IgnoreTarget {
|
|
17
|
-
path: string
|
|
18
|
-
kind: 'dir' | 'file'
|
|
19
|
-
}
|
|
20
|
-
|
|
21
15
|
export default defineNuxtModule<TelaBuildDocsOptions>({
|
|
22
16
|
meta: {
|
|
23
17
|
name: 'tela-build-docs',
|
|
@@ -53,7 +47,7 @@ export default defineNuxtModule<TelaBuildDocsOptions>({
|
|
|
53
47
|
reset: '\x1B[0m',
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
function
|
|
50
|
+
async function generateDocs() {
|
|
57
51
|
if (hasGenerated) {
|
|
58
52
|
return // Only generate once
|
|
59
53
|
}
|
|
@@ -69,81 +63,74 @@ export default defineNuxtModule<TelaBuildDocsOptions>({
|
|
|
69
63
|
|
|
70
64
|
logger.log(`${colors.gray}[tela/build] ${colors.cyan}◎${colors.gray} Scanning components from ${layerPath}${colors.reset}`)
|
|
71
65
|
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
try {
|
|
67
|
+
const repositoryRoot = resolveRepositoryRoot(nuxt.options.rootDir, nuxt.options.workspaceDir)
|
|
74
68
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (!options.outDir) {
|
|
78
|
-
ensureClaudeSymlink(repositoryRoot, logger, colors)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
catch (symlinkError: any) {
|
|
82
|
-
logger.log(`${colors.gray}[tela/build] ${colors.orange}✗${colors.gray} Could not create .claude symlink: ${symlinkError.message}${colors.reset}`)
|
|
69
|
+
if (!options.outDir) {
|
|
70
|
+
ensureClaudeSymlink(repositoryRoot, logger, colors)
|
|
83
71
|
}
|
|
72
|
+
}
|
|
73
|
+
catch (symlinkError: any) {
|
|
74
|
+
logger.log(`${colors.gray}[tela/build] ${colors.orange}✗${colors.gray} Could not create .claude symlink: ${symlinkError.message}${colors.reset}`)
|
|
75
|
+
}
|
|
84
76
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch {}
|
|
92
|
-
|
|
93
|
-
// Collect component documentation with stories
|
|
94
|
-
logger.log(`${colors.gray}[tela/build] ${colors.yellow}◒${colors.gray} Analyzing TypeScript types${colors.reset}`)
|
|
95
|
-
// Pass the app's root directory so vue-docgen-api can find node_modules
|
|
96
|
-
const { docs: componentDocs, typeResolver } = await collectComponentDocs(layerPath, nuxt.options.rootDir)
|
|
97
|
-
|
|
98
|
-
// Generate documentation (directory-first unless outFile explicitly set)
|
|
99
|
-
logger.log(`${colors.gray}[tela/build] ${colors.orange}◐${colors.gray} Generating documentation for ${componentDocs.length} components${colors.reset}`)
|
|
100
|
-
|
|
101
|
-
const baseDir = repositoryRoot
|
|
102
|
-
|
|
103
|
-
if (options.outFile) {
|
|
104
|
-
// Single-file mode (legacy)
|
|
105
|
-
const outPath = resolve(nuxt.options.rootDir, options.outFile)
|
|
106
|
-
const outDir = resolve(outPath, '..')
|
|
107
|
-
if (!existsSync(outDir)) {
|
|
108
|
-
mkdirSync(outDir, { recursive: true })
|
|
109
|
-
}
|
|
110
|
-
const markdown = generateMarkdown(componentDocs, typeResolver)
|
|
111
|
-
writeFileSync(outPath, markdown, 'utf-8')
|
|
112
|
-
// Skip auto-gitignore for legacy outFile — the path is user-managed and may be intentionally tracked
|
|
113
|
-
logger.log(`${colors.gray}[tela/build] ${colors.green}●${colors.gray} Documentation complete → ${outPath}${colors.reset}`)
|
|
77
|
+
// Prepare tsconfig overlay (safe even if Volar is disabled; creation is idempotent)
|
|
78
|
+
try {
|
|
79
|
+
if (nuxt.options.rootDir) {
|
|
80
|
+
ensureOverlayTsconfig(nuxt.options.rootDir, layerPath)
|
|
114
81
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
82
|
+
}
|
|
83
|
+
catch {}
|
|
84
|
+
|
|
85
|
+
// Collect component documentation with stories
|
|
86
|
+
logger.log(`${colors.gray}[tela/build] ${colors.yellow}◒${colors.gray} Analyzing TypeScript types${colors.reset}`)
|
|
87
|
+
// Pass the app's root directory so vue-docgen-api can find node_modules
|
|
88
|
+
const { docs: componentDocs, typeResolver } = await collectComponentDocs(layerPath, nuxt.options.rootDir)
|
|
89
|
+
|
|
90
|
+
// Generate documentation (directory-first unless outFile explicitly set)
|
|
91
|
+
logger.log(`${colors.gray}[tela/build] ${colors.orange}◐${colors.gray} Generating documentation for ${componentDocs.length} components${colors.reset}`)
|
|
92
|
+
|
|
93
|
+
const baseDir = repositoryRoot
|
|
94
|
+
|
|
95
|
+
if (options.outFile) {
|
|
96
|
+
// Single-file mode (legacy)
|
|
97
|
+
const outPath = resolve(nuxt.options.rootDir, options.outFile)
|
|
98
|
+
const outDir = resolve(outPath, '..')
|
|
99
|
+
if (!existsSync(outDir)) {
|
|
100
|
+
mkdirSync(outDir, { recursive: true })
|
|
126
101
|
}
|
|
102
|
+
const markdown = generateMarkdown(componentDocs, typeResolver)
|
|
103
|
+
writeFileSync(outPath, markdown, 'utf-8')
|
|
104
|
+
// Skip auto-gitignore for legacy outFile — the path is user-managed and may be intentionally tracked
|
|
105
|
+
logger.log(`${colors.gray}[tela/build] ${colors.green}●${colors.gray} Documentation complete → ${outPath}${colors.reset}`)
|
|
127
106
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
107
|
+
else {
|
|
108
|
+
// Directory output: single Skill (tela-build) + supporting component pages
|
|
109
|
+
const outputDirs = resolveOutputDirectories(baseDir, options.outDir)
|
|
110
|
+
for (const dir of outputDirs) {
|
|
111
|
+
generateDocsToDirectory(componentDocs, typeResolver, dir, layerPath)
|
|
132
112
|
}
|
|
113
|
+
logger.log(`${colors.gray}[tela/build] ${colors.green}●${colors.gray} Documentation complete → ${outputDirs.join(', ')}${colors.reset}`)
|
|
133
114
|
}
|
|
134
|
-
}
|
|
115
|
+
}
|
|
116
|
+
catch (error: any) {
|
|
117
|
+
console.log(`${colors.gray}[tela/build] ${colors.orange}✗${colors.gray} Generation failed: ${error.message}${colors.reset}`)
|
|
118
|
+
if (nuxt.options.dev) {
|
|
119
|
+
console.error(error)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
135
122
|
}
|
|
136
123
|
|
|
137
124
|
// Generate once on server ready for dev
|
|
138
125
|
if (nuxt.options.dev) {
|
|
139
|
-
nuxt.hook('ready', () => {
|
|
140
|
-
|
|
126
|
+
nuxt.hook('ready', async () => {
|
|
127
|
+
await generateDocs()
|
|
141
128
|
})
|
|
142
129
|
}
|
|
143
130
|
else {
|
|
144
131
|
// Generate before production build
|
|
145
|
-
nuxt.hook('nitro:build:before', () => {
|
|
146
|
-
|
|
132
|
+
nuxt.hook('nitro:build:before', async () => {
|
|
133
|
+
await generateDocs()
|
|
147
134
|
})
|
|
148
135
|
}
|
|
149
136
|
},
|
|
@@ -215,35 +202,6 @@ function isRepositoryRoot(directory: string): boolean {
|
|
|
215
202
|
}
|
|
216
203
|
}
|
|
217
204
|
|
|
218
|
-
function ensurePathsIgnored(repositoryRoot: string, targets: IgnoreTarget[]): void {
|
|
219
|
-
const gitignorePath = resolve(repositoryRoot, '.gitignore')
|
|
220
|
-
const existingLines = existsSync(gitignorePath)
|
|
221
|
-
? readFileSync(gitignorePath, 'utf-8').split('\n')
|
|
222
|
-
: []
|
|
223
|
-
const existingEntries = new Set(existingLines.map(line => line.trim()).filter(Boolean))
|
|
224
|
-
const entriesToAdd = targets
|
|
225
|
-
.map(target => toGitignoreEntry(repositoryRoot, target))
|
|
226
|
-
.filter(entry => !existingEntries.has(entry))
|
|
227
|
-
|
|
228
|
-
if (entriesToAdd.length === 0) {
|
|
229
|
-
return
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const nextLines = [...existingLines]
|
|
233
|
-
if (nextLines.length > 0 && nextLines[nextLines.length - 1] !== '') {
|
|
234
|
-
nextLines.push('')
|
|
235
|
-
}
|
|
236
|
-
nextLines.push(...entriesToAdd)
|
|
237
|
-
|
|
238
|
-
writeFileSync(gitignorePath, `${nextLines.join('\n')}\n`, 'utf-8')
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function toGitignoreEntry(repositoryRoot: string, target: IgnoreTarget): string {
|
|
242
|
-
const relativePath = relative(repositoryRoot, target.path).replace(/\\/g, '/')
|
|
243
|
-
const normalizedPath = relativePath.startsWith('.') ? relativePath : `/${relativePath}`
|
|
244
|
-
return target.kind === 'dir' ? `${normalizedPath}/` : normalizedPath
|
|
245
|
-
}
|
|
246
|
-
|
|
247
205
|
export function ensureClaudeSymlink(
|
|
248
206
|
repositoryRoot: string,
|
|
249
207
|
logger: Pick<Console, 'log'>,
|