@kudzujs/core 0.16.26 → 0.16.28

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 CHANGED
@@ -14,7 +14,7 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
14
14
 
15
15
  > Experimental `0.16.x`: the compiler API and supported TSX surface may change.
16
16
 
17
- **Current release: [0.16.26](https://github.com/kudzujs/kudzu/releases/tag/v0.16.26).** Write reusable components, native event handlers, and pure collection expressions; Kudzu specializes supported source into static content and direct browser updates.
17
+ **Current release: [0.16.28](https://github.com/kudzujs/kudzu/releases/tag/v0.16.28).** Write reusable components, native event handlers, and pure collection expressions; Kudzu specializes supported source into static content and direct browser updates.
18
18
 
19
19
  - [Documentation](https://kudzujs.cloud/docs)
20
20
  - [Installation guide](https://kudzujs.cloud/docs#install)
@@ -130,6 +130,26 @@ A static sibling outside an enhanced-navigation group ships no JavaScript merely
130
130
  because another page is interactive. Shared layout effects or explicit navigation
131
131
  groups have their own lifetime; native anchors remain the default.
132
132
 
133
+ ## Verify
134
+
135
+ A successful build validates supported source and emits deployable outputs; it
136
+ does not verify browser behavior or accessibility. Check visible DOM and relevant
137
+ interactions, labels, status updates, keyboard focus, and responsive layouts in a
138
+ browser as needed. Binding comments and inert templates mean raw HTML string
139
+ matches or tag stripping are not reliable checks of rendered text.
140
+
141
+ Normal builds also scan generated route HTML after `afterBuild`, reporting counts
142
+ with/without script or modulepreload text markers and unreadable files, with up to
143
+ five paths per category (long paths are truncated). This is a literal text scan,
144
+ not proof of script freedom: comments and inert content can match, inline event
145
+ attributes are not checked, and extra public HTML files are outside the route
146
+ inventory. Quiet and JSON builds omit this summary.
147
+
148
+ Keep checks bounded and report concise counts and failing paths rather than
149
+ repeatedly dumping minified artifacts. A missing tool or truncated response is
150
+ not a pass. After source changes, rerun affected checks. Optional compiler/artifact
151
+ reports and their limits are documented under [Build output](https://kudzujs.cloud/docs#build).
152
+
133
153
  ## How It Works
134
154
 
135
155
  ```text
@@ -59,12 +59,16 @@ export async function buildWithSession(project, { changedFiles, quiet = false, m
59
59
  try {
60
60
  await recoverOutput(outputDirectory, backupOutput)
61
61
  await rm(stagedOutput, { recursive: true, force: true })
62
- const { result, pageCount, behaviorCount, cache, inspectionData, explanation } = await buildInto(project, stagedOutput, { changedFiles, minify, quiet, retainCache, explanationRoute })
62
+ const { result, pageCount, behaviorCount, cache, inspectionData, explanation, htmlSummary } = await buildInto(project, stagedOutput, { changedFiles, minify, quiet, retainCache, explanationRoute })
63
63
  const promoteStarted = project.timings ? performance.now() : 0
64
64
  await promoteOutput(stagedOutput, outputDirectory, backupOutput)
65
65
  addTiming(project.timings, "writeMs", promoteStarted)
66
66
  project.buildCache = retainCache ? cache : undefined
67
- if (!quiet) console.log(`Built ${pageCount} page(s), ${behaviorCount} interactive page(s) into dist/`)
67
+ if (!quiet) {
68
+ console.log(`Built ${pageCount} page(s), ${behaviorCount} interactive page(s) into dist/`)
69
+ console.log(htmlSummary)
70
+ console.log("Browser behavior and accessibility need verification: https://kudzujs.cloud/docs#build")
71
+ }
68
72
  return explanationRoute ? explanation : inspection ? createInspectionReport(inspectionData) : result
69
73
  } catch (error) {
70
74
  const normalized = normalizeDiagnosticError(error, root)
@@ -550,6 +554,34 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
550
554
  if (typeof config.afterBuild !== "function") throw new Error("kudzu.config afterBuild must be a function")
551
555
  await config.afterBuild({ root, outDir: outputDirectory, sourceDir: sourceDirectory, base, routes: plans.map(plan => plan.route), plans, rewrites: sortedRewrites, artifacts })
552
556
  }
557
+ let htmlSummary
558
+ if (!quiet) {
559
+ const counts = { "With markers": 0, Unreadable: 0 }
560
+ const samples = { "With markers": [], Unreadable: [] }
561
+ // Scan final route files, not compiler closure metadata or a previous build's scratch report.
562
+ const outputs = routeRecords.map(record => record.output).sort()
563
+ for (let offset = 0; offset < outputs.length; offset += 64) {
564
+ const batch = outputs.slice(offset, offset + 64)
565
+ const categories = await Promise.all(batch.map(async output => {
566
+ try {
567
+ const html = await readFile(join(outputDirectory, output, "index.html"), "utf8")
568
+ if (/<script(?=[\s/>])|<link(?=[\s/>])[^>]*\bmodulepreload\b/i.test(html)) return "With markers"
569
+ } catch {
570
+ return "Unreadable"
571
+ }
572
+ }))
573
+ for (const [index, category] of categories.entries()) {
574
+ if (!category) continue
575
+ counts[category]++
576
+ if (samples[category].length < 5) {
577
+ const path = join("dist", batch[index], "index.html").replaceAll(sep, "/")
578
+ samples[category].push(JSON.stringify(path.length > 240 ? `${path.slice(0, 240)}...` : path))
579
+ }
580
+ }
581
+ }
582
+ htmlSummary = `Route HTML scan: ${routeRecords.length - counts["With markers"] - counts.Unreadable} without script/modulepreload text markers, ${counts["With markers"]} with markers, ${counts.Unreadable} unreadable.`
583
+ for (const category of Object.keys(counts)) if (counts[category]) htmlSummary += `\n ${category}: ${samples[category].join(", ")}${counts[category] > 5 ? ` (+${counts[category] - 5} more)` : ""}`
584
+ }
553
585
  addTiming(project.timings, "writeMs", writeStarted)
554
586
 
555
587
  let explanation
@@ -567,6 +599,7 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
567
599
  result: { sourceResults, incremental },
568
600
  inspectionData: { sourceFiles: sourceFiles.map(file => relative(root, file).replaceAll(sep, "/")), sourceResults, compatibility, artifacts },
569
601
  explanation,
602
+ htmlSummary,
570
603
  pageCount: routeRecords.length,
571
604
  behaviorCount,
572
605
  cache: { pageRenders, pageSources, placeholders, sourceResults: sourceResultsByFile }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.16.26",
3
+ "version": "0.16.28",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",