@uniweb/build 0.1.4 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
@@ -42,13 +42,13 @@
42
42
  "sharp": "^0.33.2"
43
43
  },
44
44
  "optionalDependencies": {
45
- "@uniweb/content-reader": "1.0.2"
45
+ "@uniweb/content-reader": "1.0.3"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
49
49
  "react": "^18.0.0 || ^19.0.0",
50
50
  "react-dom": "^18.0.0 || ^19.0.0",
51
- "@uniweb/core": "0.1.2"
51
+ "@uniweb/core": "0.1.4"
52
52
  },
53
53
  "peerDependenciesMeta": {
54
54
  "vite": {
package/src/docs.js ADDED
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Documentation Generator
3
+ *
4
+ * Generates markdown documentation from foundation schema.json
5
+ * or directly from component meta files.
6
+ */
7
+
8
+ import { readFile, writeFile } from 'node:fs/promises'
9
+ import { existsSync } from 'node:fs'
10
+ import { join } from 'node:path'
11
+ import { buildSchema } from './schema.js'
12
+
13
+ /**
14
+ * Generate markdown documentation for a single component
15
+ *
16
+ * @param {string} name - Component name
17
+ * @param {Object} meta - Component metadata
18
+ * @returns {string} Markdown content
19
+ */
20
+ function generateComponentDocs(name, meta) {
21
+ const lines = []
22
+
23
+ // Component header
24
+ lines.push(`## ${name}`)
25
+ lines.push('')
26
+
27
+ // Description
28
+ if (meta.description) {
29
+ lines.push(meta.description)
30
+ lines.push('')
31
+ }
32
+
33
+ // Category badge
34
+ if (meta.category) {
35
+ lines.push(`**Category:** ${meta.category}`)
36
+ lines.push('')
37
+ }
38
+
39
+ // Content Elements
40
+ if (meta.elements && Object.keys(meta.elements).length > 0) {
41
+ lines.push('### Content Elements')
42
+ lines.push('')
43
+ lines.push('| Element | Label | Required | Description |')
44
+ lines.push('|---------|-------|----------|-------------|')
45
+
46
+ for (const [key, element] of Object.entries(meta.elements)) {
47
+ const label = element.label || key
48
+ const required = element.required ? 'Yes' : ''
49
+ const description = element.description || ''
50
+ lines.push(`| \`${key}\` | ${label} | ${required} | ${description} |`)
51
+ }
52
+ lines.push('')
53
+ }
54
+
55
+ // Parameters/Properties
56
+ if (meta.properties && Object.keys(meta.properties).length > 0) {
57
+ lines.push('### Parameters')
58
+ lines.push('')
59
+ lines.push('| Parameter | Type | Default | Description |')
60
+ lines.push('|-----------|------|---------|-------------|')
61
+
62
+ for (const [key, prop] of Object.entries(meta.properties)) {
63
+ const type = prop.type || 'string'
64
+ const defaultVal = prop.default !== undefined ? `\`${prop.default}\`` : ''
65
+ let description = prop.label || ''
66
+
67
+ // Add options for select type
68
+ if (prop.type === 'select' && prop.options) {
69
+ const optionValues = prop.options.map(o =>
70
+ typeof o === 'object' ? o.value : o
71
+ ).join(', ')
72
+ description += description ? ` (${optionValues})` : optionValues
73
+ }
74
+
75
+ lines.push(`| \`${key}\` | ${type} | ${defaultVal} | ${description} |`)
76
+ }
77
+ lines.push('')
78
+ }
79
+
80
+ // Presets
81
+ if (meta.presets && meta.presets.length > 0) {
82
+ lines.push('### Presets')
83
+ lines.push('')
84
+
85
+ for (const preset of meta.presets) {
86
+ const settings = preset.settings
87
+ ? Object.entries(preset.settings)
88
+ .map(([k, v]) => `${k}: ${v}`)
89
+ .join(', ')
90
+ : ''
91
+ lines.push(`- **${preset.name}** - ${preset.label || ''} ${settings ? `(${settings})` : ''}`)
92
+ }
93
+ lines.push('')
94
+ }
95
+
96
+ return lines.join('\n')
97
+ }
98
+
99
+ /**
100
+ * Generate full markdown documentation for a foundation
101
+ *
102
+ * @param {Object} schema - Foundation schema object
103
+ * @param {Object} options - Generation options
104
+ * @param {string} [options.title] - Document title
105
+ * @returns {string} Complete markdown documentation
106
+ */
107
+ export function generateDocsFromSchema(schema, options = {}) {
108
+ const { title = 'Foundation Components' } = options
109
+ const lines = []
110
+
111
+ // Header
112
+ lines.push(`# ${title}`)
113
+ lines.push('')
114
+
115
+ // Foundation info
116
+ const foundationMeta = schema._self
117
+ if (foundationMeta) {
118
+ if (foundationMeta.name) {
119
+ lines.push(`**${foundationMeta.name}**`)
120
+ lines.push('')
121
+ }
122
+ if (foundationMeta.description) {
123
+ lines.push(foundationMeta.description)
124
+ lines.push('')
125
+ }
126
+ }
127
+
128
+ lines.push('---')
129
+ lines.push('')
130
+
131
+ // Table of contents
132
+ const componentNames = Object.keys(schema).filter(k => k !== '_self')
133
+
134
+ if (componentNames.length > 0) {
135
+ lines.push('## Components')
136
+ lines.push('')
137
+ for (const name of componentNames) {
138
+ const meta = schema[name]
139
+ const title = meta.title || name
140
+ lines.push(`- [${title}](#${name.toLowerCase()}) - ${meta.description || ''}`)
141
+ }
142
+ lines.push('')
143
+ lines.push('---')
144
+ lines.push('')
145
+ }
146
+
147
+ // Component documentation
148
+ for (const name of componentNames) {
149
+ const meta = schema[name]
150
+ lines.push(generateComponentDocs(name, meta))
151
+ lines.push('---')
152
+ lines.push('')
153
+ }
154
+
155
+ // Footer
156
+ lines.push('*Generated from foundation schema*')
157
+
158
+ return lines.join('\n')
159
+ }
160
+
161
+ /**
162
+ * Generate documentation for a foundation directory
163
+ *
164
+ * Can read from existing schema.json or build schema from source.
165
+ *
166
+ * @param {string} foundationDir - Path to foundation directory
167
+ * @param {Object} options - Options
168
+ * @param {string} [options.output] - Output file path (default: COMPONENTS.md)
169
+ * @param {boolean} [options.fromSource] - Build schema from source instead of dist
170
+ * @returns {Promise<{outputPath: string, componentCount: number}>}
171
+ */
172
+ export async function generateDocs(foundationDir, options = {}) {
173
+ const {
174
+ output = 'COMPONENTS.md',
175
+ fromSource = false,
176
+ } = options
177
+
178
+ let schema
179
+
180
+ // Try to load schema.json from dist
181
+ const schemaPath = join(foundationDir, 'dist', 'schema.json')
182
+
183
+ if (!fromSource && existsSync(schemaPath)) {
184
+ // Load from existing schema.json
185
+ const schemaContent = await readFile(schemaPath, 'utf-8')
186
+ schema = JSON.parse(schemaContent)
187
+ } else {
188
+ // Build schema from source
189
+ const srcDir = join(foundationDir, 'src')
190
+ if (!existsSync(srcDir)) {
191
+ throw new Error(`Source directory not found: ${srcDir}`)
192
+ }
193
+ schema = await buildSchema(srcDir)
194
+ }
195
+
196
+ // Get foundation name for title
197
+ const pkgPath = join(foundationDir, 'package.json')
198
+ let title = 'Foundation Components'
199
+ if (existsSync(pkgPath)) {
200
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'))
201
+ if (pkg.name) {
202
+ title = `${pkg.name} Components`
203
+ }
204
+ }
205
+
206
+ // Generate markdown
207
+ const markdown = generateDocsFromSchema(schema, { title })
208
+
209
+ // Write output
210
+ const outputPath = join(foundationDir, output)
211
+ await writeFile(outputPath, markdown)
212
+
213
+ // Count components
214
+ const componentCount = Object.keys(schema).filter(k => k !== '_self').length
215
+
216
+ return { outputPath, componentCount }
217
+ }
package/src/index.js CHANGED
@@ -40,5 +40,11 @@ export {
40
40
  prerenderSite,
41
41
  } from './prerender.js'
42
42
 
43
+ // Documentation generation
44
+ export {
45
+ generateDocs,
46
+ generateDocsFromSchema,
47
+ } from './docs.js'
48
+
43
49
  // Default export is the combined Vite plugin
44
50
  export { default } from './vite-foundation-plugin.js'