@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// A screen is a declaration: data from `load`, columns, actions and labels, handed to the kit's patterns
|
||||
// (docs/how-to/compose-a-page.md in the platform's documentation). So a screen has no styling of its own: no `className`, no
|
||||
// colour value. React Aria is out of a screen's reach too, by the `ui-comes-from-the-kit` rule of
|
||||
// scripts/dep-rules.cjs. A screen that is truly domain-specific says so, and why, in its first lines:
|
||||
// `// kit:custom-ui <why>`. `pnpm boundaries` and this suite read the same marker.
|
||||
|
||||
import { readFileSync } from "node:fs"
|
||||
import { createRequire } from "node:module"
|
||||
import { join } from "node:path"
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const { buildForbidden, listCustomScreens, listScreens } = require("../scripts/dep-rules.cjs") as {
|
||||
buildForbidden(
|
||||
moduleIds: string[],
|
||||
custom?: string[],
|
||||
): { name: string; from: { path?: string; pathNot?: string | string[] }; to: { path?: string | string[] } }[]
|
||||
listCustomScreens(root: string): string[]
|
||||
listScreens(root: string): string[]
|
||||
}
|
||||
|
||||
const root = new URL("..", import.meta.url).pathname
|
||||
const COLOUR = /["'`](?:#[0-9a-fA-F]{3,8}|rgba?\(|hsla?\(|oklch\()/
|
||||
|
||||
/** What a declared screen may not hold, by file, with the way out in the message. */
|
||||
function styling(source: string): string[] {
|
||||
const found: string[] = []
|
||||
if (/<(?:button|input|select|textarea|table)(?:\s|>)/.test(source))
|
||||
found.push("raw control: compose kit primitives or patterns")
|
||||
if (/\bclassName=/.test(source)) found.push("className: use a pattern's slot, or a variant")
|
||||
if (COLOUR.test(source)) found.push("a colour value: the kit's roles carry every colour")
|
||||
return found
|
||||
}
|
||||
|
||||
describe("a screen is a declaration", () => {
|
||||
const custom = new Set(listCustomScreens(root))
|
||||
|
||||
it("holds no styling of its own unless it declares itself custom", () => {
|
||||
const problems = listScreens(root)
|
||||
.filter((file) => !custom.has(file))
|
||||
.flatMap((file) =>
|
||||
styling(readFileSync(join(root, file), "utf8")).map(
|
||||
(problem) => `${file}: ${problem}, or \`// kit:custom-ui <why>\``,
|
||||
),
|
||||
)
|
||||
expect(problems).toEqual([])
|
||||
})
|
||||
|
||||
it("catches what it means to", () => {
|
||||
expect(styling(`<p className="x" />`)).toHaveLength(1)
|
||||
expect(styling(`const c = "#123abc"`)).toHaveLength(1)
|
||||
expect(styling(`const c = "oklch(0.5 0 0)"`)).toHaveLength(1)
|
||||
expect(styling(`<a href="#section" />`)).toEqual([])
|
||||
expect(styling(`<button type="button" />`)).toHaveLength(1)
|
||||
expect(styling(`<PageHeader title={title} />`)).toEqual([])
|
||||
})
|
||||
|
||||
it("keeps React Aria behind the kit, for every screen that has not declared itself", () => {
|
||||
const rule = buildForbidden([], ["modules/x/ui/own.tsx"]).find(({ name }) => name === "ui-comes-from-the-kit")
|
||||
const target = new RegExp(rule?.to.path as string)
|
||||
expect(target.test("react-aria-components")).toBe(true)
|
||||
expect(target.test("node_modules/.pnpm/x/node_modules/@react-aria/button/dist/index.js")).toBe(true)
|
||||
expect(target.test("@conusai-kit/ui/patterns")).toBe(false)
|
||||
expect(rule?.from.pathNot).toEqual(["^modules/x/ui/own\\.tsx$"])
|
||||
})
|
||||
|
||||
it("leaves custom screens the exception", () => {
|
||||
expect(custom.size).toBeLessThan(listScreens(root).length / 2)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user