describe-me 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/src/tree.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { ManifestModule, ManifestTest } from '@describe-me/core/types'
2
+
3
+ export interface SuiteNode {
4
+ name: string
5
+ suites: Map<string, SuiteNode>
6
+ tests: ManifestTest[]
7
+ }
8
+
9
+ /** Nest a module's flat test list back into its `describe` hierarchy. */
10
+ export function buildTree(mod: ManifestModule): SuiteNode {
11
+ const root: SuiteNode = { name: '', suites: new Map(), tests: [] }
12
+ for (const test of mod.tests) {
13
+ let node = root
14
+ for (const part of test.path) {
15
+ let next = node.suites.get(part)
16
+ if (!next) {
17
+ node.suites.set(part, (next = { name: part, suites: new Map(), tests: [] }))
18
+ }
19
+
20
+ node = next
21
+ }
22
+
23
+ node.tests.push(test)
24
+ }
25
+
26
+ return root
27
+ }
@@ -0,0 +1,22 @@
1
+ import { el } from './el.js'
2
+
3
+ /** Render one serialized prop value, coloured by its type. */
4
+ export function valueCell(value: unknown): HTMLElement {
5
+ if (typeof value === 'string') {
6
+ if (value.startsWith('ƒ ')) {
7
+ return el('span', { class: 'val-fn' }, value)
8
+ }
9
+
10
+ return el('span', { class: 'val-string' }, JSON.stringify(value))
11
+ }
12
+
13
+ if (typeof value === 'number' || typeof value === 'boolean') {
14
+ return el('span', { class: `val-${typeof value}` }, String(value))
15
+ }
16
+
17
+ if (value === null || value === undefined) {
18
+ return el('span', { class: 'val-fn' }, String(value))
19
+ }
20
+
21
+ return el('span', {}, JSON.stringify(value))
22
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,85 @@
1
+ import { cpSync, existsSync, readFileSync, statSync, watch } from 'node:fs'
2
+ import { dirname, join, resolve, sep } from 'node:path'
3
+ import { defineConfig, type Plugin } from 'vite'
4
+
5
+ /** Where the manifest and snapshots live. The CLI sets this; the default is the example project. */
6
+ function dataDir(): string {
7
+ return resolve(process.env.DESCRIBE_ME_DIR ?? '../../examples/react-basic/.describe-me')
8
+ }
9
+
10
+ /**
11
+ * Dev: serves the data directory under `/__data` and pushes an HMR event when
12
+ * the manifest changes. Build: copies the data directory into the output, so
13
+ * the result is a self-contained static site.
14
+ */
15
+ function describeMeData(): Plugin {
16
+ const dir = dataDir()
17
+ let outDir = 'dist'
18
+
19
+ return {
20
+ name: 'describe-me:data',
21
+
22
+ configResolved(config) {
23
+ outDir = resolve(config.root, config.build.outDir)
24
+ },
25
+
26
+ configureServer(server) {
27
+ server.config.logger.info(`describe-me: serving data from ${dir}`)
28
+
29
+ let timer: NodeJS.Timeout | undefined
30
+
31
+ const notify = () => {
32
+ clearTimeout(timer)
33
+ timer = setTimeout(
34
+ () => server.ws.send({ type: 'custom', event: 'describe-me:update' }),
35
+ 150,
36
+ )
37
+ }
38
+
39
+ const watchTarget = existsSync(dir) ? dir : dirname(dir)
40
+
41
+ try {
42
+ watch(watchTarget, { recursive: true }, (_event, file) => {
43
+ if (!file || String(file).endsWith('manifest.json')) {
44
+ notify()
45
+ }
46
+ })
47
+ } catch (error) {
48
+ server.config.logger.warn(`describe-me: cannot watch ${watchTarget}: ${String(error)}`)
49
+ }
50
+
51
+ server.middlewares.use('/__data', (request, response, next) => {
52
+ const relative = decodeURIComponent((request.url ?? '/').split('?')[0])
53
+ const absolute = join(dir, relative)
54
+
55
+ if (
56
+ !absolute.startsWith(dir + sep) ||
57
+ !existsSync(absolute) ||
58
+ !statSync(absolute).isFile()
59
+ ) {
60
+ return next()
61
+ }
62
+
63
+ response.setHeader('Content-Type', 'application/json')
64
+ response.setHeader('Cache-Control', 'no-store')
65
+ response.end(readFileSync(absolute))
66
+ })
67
+ },
68
+
69
+ closeBundle() {
70
+ if (!existsSync(dir)) {
71
+ this.warn(`describe-me: no data at ${dir}; run vitest first`)
72
+ return
73
+ }
74
+
75
+ cpSync(dir, join(outDir, '__data'), { recursive: true })
76
+ },
77
+ }
78
+ }
79
+
80
+ export default defineConfig({
81
+ // Relative asset URLs, so the site works from any sub-path (GitHub Pages, S3 prefixes).
82
+ base: './',
83
+ plugins: [describeMeData()],
84
+ server: { port: 6006, strictPort: false, open: false },
85
+ })