Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ OPENAPI_SPEC ?= spec/openapi.json
# Place one consolidated PHONY declaration near the top of the file
.PHONY: all clean be fe fe-build openapi gen docker-up docker-down
.PHONY: local-k8s-up local-k8s-down local-k8s-status local-k8s-logs
.PHONY: fmt lint test test-rust test-frontend test-workflow-contracts test-scripts typecheck deps lockfile
.PHONY: fmt lint docs-check test test-rust test-frontend test-workflow-contracts test-scripts typecheck deps lockfile
.PHONY: lint-specs audit audit-node rust-audit
.PHONY: check-fmt markdownlint markdownlint-docs mermaid-lint nixie yamllint
.PHONY: spelling spelling-phrase-check spelling-config spelling-config-write spelling-helper-test
Expand All @@ -75,7 +75,7 @@ OPENAPI_SPEC ?= spec/openapi.json
workspace-sync:
./scripts/sync_workspace_members.py

all: check-fmt lint test spelling
all: check-fmt lint docs-check test spelling

clean:
cargo clean --manifest-path backend/Cargo.toml
Expand Down Expand Up @@ -216,6 +216,12 @@ PG_EMBED_SETUP_UNPRIV_VERSION ?= 0.5.1
NEXTEST_TEST_THREADS ?= 1


# Zero-tolerance documentation gate: TypeDoc's notDocumented validation over
# the frontend-pwa, packages/types, and packages/tokens surfaces (their
# typedoc.json files). Emits no documentation artefacts.
docs-check:
pnpm run docs:check

test: test-rust test-frontend test-scripts

test-rust: workspace-sync prepare-pg-worker
Expand Down
2 changes: 2 additions & 0 deletions frontend-pwa/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ Object.freeze(usersQueryKey);
*
*/
export const usersQueryKeys = {
/** Key for the whole user collection; alias of {@link usersQueryKey}. */
all: usersQueryKey,
/** Key for a single user, scoped under the collection key. */
byId: (id: User['id']): readonly [...typeof usersQueryKey, User['id']] => {
const key = [...usersQueryKey, id] as const;

Expand Down
8 changes: 8 additions & 0 deletions frontend-pwa/src/api/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ function getContentTypeForBody(body: unknown): string | null {
if (isBinary(body)) return null;
return 'application/json';
}
/**
* Fetch wrapper used by the generated Orval client: sets a JSON content type
* only for plain-object bodies and rejects on non-2xx responses.
*/
export const customFetch = async <T>(input: string, init?: RequestInit): Promise<T> => {
const url = new URL(input, apiBase());

Expand Down Expand Up @@ -171,6 +175,10 @@ export const customFetchParsed = async <Schema extends z.ZodTypeAny>(
return schema.parse(data);
};

/**
* Like `customFetchParsed`, but returns Zod's safe-parse result instead of
* throwing, so callers can branch on validation failure.
*/
export const customFetchParsedSafe = async <Schema extends z.ZodTypeAny>(
input: string,
schema: Schema,
Expand Down
1 change: 1 addition & 0 deletions frontend-pwa/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { useQuery } from '@tanstack/react-query';
import { listUsers, usersQueryKey } from '../api/client';

/** Root application component: fetches the user list and renders the demo shell. */
export function App() {
const { data, isLoading, isError } = useQuery({
queryKey: usersQueryKey,
Expand Down
43 changes: 43 additions & 0 deletions frontend-pwa/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "https://typedoc.org/schema.json",
"tsconfig": "tsconfig.json",
"entryPoints": ["src"],
"entryPointStrategy": "expand",
"exclude": [
"**/*.d.ts",
"**/src/api/generated/**",
"**/*.gen.*",
"**/*.generated.*",
"**/__generated__/**",
"**/*.test.*",
"**/tests/**",
"**/fixtures/**"
],
"emit": "none",
"commentStyle": "jsdoc",
"excludeExternals": true,
"excludeInternal": true,
"excludePrivate": true,
"excludeProtected": true,
"validation": {
"notDocumented": true,
"notExported": false,
"invalidLink": false,
"invalidPath": false,
"rewrittenLink": false,
"unusedMergeModuleWith": false
},
"requiredToBeDocumented": [
"Enum",
"EnumMember",
"Variable",
"Function",
"Class",
"Interface",
"Property",
"Method",
"Accessor",
"TypeAlias"
],
"treatValidationWarningsAsErrors": true
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"fast-check": "^4.8.0",
"markdownlint-cli": "^0.48.0",
"puppeteer": "^23.11.1",
"typedoc": "^0.28.20",
"typescript": "5.9.2",
"validator": "^13.15.23",
"vite": "^7.3.5",
"vitest": "^4.1.8"
Expand All @@ -29,7 +31,8 @@
"test": "vitest run --config vitest.config.mjs",
"test:workspaces": "node ./scripts/run-workspace-script.mjs test",
"audit": "node ./scripts/run-workspace-script.mjs audit",
"audit:validate": "node security/validate-audit.js"
"audit:validate": "node security/validate-audit.js",
"docs:check": "typedoc --options frontend-pwa/typedoc.json && typedoc --options packages/types/typedoc.json && typedoc --options packages/tokens/typedoc.json"
},
"engines": {
"node": ">=22.18.0"
Expand Down Expand Up @@ -68,4 +71,4 @@
"uuid": "14.0.0"
}
}
}
}
5 changes: 4 additions & 1 deletion packages/tokens/build/validate-contrast.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { resolveToken } from '../src/utils/tokens.js';

// Load package settings for defaults.
/**
* @typedef {{name: string, version: string, contrastThreshold?: number}} PackageJson
* @typedef {object} PackageJson Package manifest fields the contrast validator reads.
* @property {string} name Package name, echoed in validation reports.
* @property {string} version Package version, echoed in validation reports.
* @property {number} [contrastThreshold] Optional override for the minimum contrast ratio.
*/
/** @type {PackageJson} */
const pkgJson = readJson(new URL('../package.json', import.meta.url));
Expand Down
10 changes: 10 additions & 0 deletions packages/tokens/src/utils/resolve-token.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ function isValidTokenValue(value) {
return value !== null && value !== undefined && typeof value === 'string';
}

/**
* Resolve a design-token reference like `{color.brand}` against a token tree.
*
* Follows nested references until a literal value is reached, so aliases of
* aliases resolve; a non-reference string is returned unchanged.
*
* @param {string} ref - Token reference or literal string.
* @param {object} tokens - Token tree supplying `{path: {value}}` leaves.
* @returns {string} The resolved literal token value.
*/
export function resolveToken(ref, tokens) {
if (typeof ref !== 'string') {
throw new TypeError('ref must be a string like "{path.to.token}" or a literal string');
Expand Down
13 changes: 13 additions & 0 deletions packages/tokens/tsconfig.typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowJs": true,
"checkJs": false,
"noEmit": true,
"skipLibCheck": true
},
"include": ["build/**/*.js", "build-utils/**/*.js", "src/utils/**/*.js"],
"exclude": ["node_modules"]
}
20 changes: 20 additions & 0 deletions packages/tokens/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://typedoc.org/schema.json",
"tsconfig": "tsconfig.typedoc.json",
"entryPoints": ["build", "build-utils", "src/utils"],
"entryPointStrategy": "expand",
"exclude": ["**/*.d.ts", "**/node_modules/**"],
"emit": "none",
"commentStyle": "jsdoc",
"excludeExternals": true,
"validation": {
"notDocumented": true,
"notExported": false,
"invalidLink": false,
"invalidPath": false,
"rewrittenLink": false,
"unusedMergeModuleWith": false
},
"requiredToBeDocumented": ["Variable", "Function", "Class", "Property", "Method", "Accessor"],
"treatValidationWarningsAsErrors": true
}
4 changes: 4 additions & 0 deletions packages/types/dist/src/user.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ export declare const UserIdSchema: z.ZodBranded<z.ZodString, "UserId">;
export type UserId = z.infer<typeof UserIdSchema>;
/** Runtime schema for a user record. */
export declare const UserSchema: z.ZodObject<{
/** Branded unique identifier for the user. */
id: z.ZodBranded<z.ZodString, "UserId">;
/** Human-readable name; trimmed and guaranteed non-empty by the schema. */
displayName: z.ZodString;
}, "strict", z.ZodTypeAny, {
id: string & z.BRAND<"UserId">;
Expand All @@ -24,7 +26,9 @@ export declare const UserSchema: z.ZodObject<{
export type User = z.infer<typeof UserSchema>;
/** Runtime schema for a list of user records. */
export declare const UsersSchema: z.ZodArray<z.ZodObject<{
/** Branded unique identifier for the user. */
id: z.ZodBranded<z.ZodString, "UserId">;
/** Human-readable name; trimmed and guaranteed non-empty by the schema. */
displayName: z.ZodString;
}, "strict", z.ZodTypeAny, {
id: string & z.BRAND<"UserId">;
Expand Down
2 changes: 2 additions & 0 deletions packages/types/src/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ export type UserId = z.infer<typeof UserIdSchema>;
/** Runtime schema for a user record. */
export const UserSchema = z
.object({
/** Branded unique identifier for the user. */
id: UserIdSchema,
/** Human-readable name; trimmed and guaranteed non-empty by the schema. */
displayName: z.string().trim().min(1, 'displayName must not be empty'),
})
.strict();
Expand Down
34 changes: 34 additions & 0 deletions packages/types/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "https://typedoc.org/schema.json",
"tsconfig": "tsconfig.json",
"entryPoints": ["src"],
"entryPointStrategy": "expand",
"exclude": ["**/*.d.ts", "**/dist/**"],
"emit": "none",
"commentStyle": "jsdoc",
"excludeExternals": true,
"excludeInternal": true,
"excludePrivate": true,
"excludeProtected": true,
"validation": {
"notDocumented": true,
"notExported": false,
"invalidLink": false,
"invalidPath": false,
"rewrittenLink": false,
"unusedMergeModuleWith": false
},
"requiredToBeDocumented": [
"Enum",
"EnumMember",
"Variable",
"Function",
"Class",
"Interface",
"Property",
"Method",
"Accessor",
"TypeAlias"
],
"treatValidationWarningsAsErrors": true
}
Loading
Loading