diff --git a/.changeset/friendly-hotels-behave.md b/.changeset/friendly-hotels-behave.md new file mode 100644 index 0000000000..70063cd821 --- /dev/null +++ b/.changeset/friendly-hotels-behave.md @@ -0,0 +1,11 @@ +--- +"@digdir/designsystemet": minor +--- + +Add JSON schema for CLI config file, which enables editor hints. To use it, do something like this: +```jsonc +{ + "$schema": "node_modules/@digdir/designsystemet/dist/config.schema.json" + // ...config options here... +} +``` diff --git a/packages/cli/bin/config.ts b/packages/cli/bin/config.ts index 67d75e572c..2df01e323f 100644 --- a/packages/cli/bin/config.ts +++ b/packages/cli/bin/config.ts @@ -13,24 +13,52 @@ export function mapPathToOptionName(path: (string | number)[]) { return option; } -const themeSchema = z.object({ - colors: z.object({ - main: z.record(z.string().transform(convertToHex)), - support: z.record(z.string().transform(convertToHex)), - neutral: z.string().transform(convertToHex), - }), - typography: z.object({ - fontFamily: z.string(), - }), - borderRadius: z.number(), -}); +const hexPatterns = [ + // Hex colors: #000, #0000, #000000, #00000000 + `#[0-9a-fA-F]{3}`, + `#[0-9a-fA-F]{4}`, + `#[0-9a-fA-F]{6}`, + `#[0-9a-fA-F]{8}`, +]; + +export const colorRegex = new RegExp(`^${hexPatterns.join('|')}$`); + +const colorSchema = z + .string({ description: 'A hex color, which is used for creating a color scale' }) + .regex(colorRegex) + .transform(convertToHex); +const colorCategorySchema = z.record(colorSchema, { description: 'One or more color definitions' }); + +const themeSchema = z.object( + { + colors: z.object( + { + main: colorCategorySchema, + support: colorCategorySchema, + neutral: colorSchema, + }, + { description: 'Defines the colors for this theme' }, + ), + typography: z.object( + { + fontFamily: z.string({ description: 'Sets the font-family for this theme' }), + }, + { description: 'Defines the typography for a given theme' }, + ), + borderRadius: z.number({ description: 'Defines the border-radius for this theme' }), + }, + { description: 'An object defining a theme. The property name holding the object becomes the theme name.' }, +); /** * This defines the structure of the JSON config file */ export const configFileSchema = z.object({ - outDir: z.string().optional(), - themes: z.record(themeSchema), + outDir: z.string({ description: 'Path to the output directory for the created design tokens' }).optional(), + themes: z.record(themeSchema, { + description: + 'An object with one or more themes. Each property defines a theme, and the property name is used as the theme name.', + }), }); /** diff --git a/packages/cli/package.json b/packages/cli/package.json index 51645feb5a..622bfa67ec 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -33,8 +33,9 @@ "designsystemet": "tsx ./bin/designsystemet.ts", "build:tokens": "yarn clean:theme && yarn designsystemet tokens build -p -t ../../design-tokens -o ../../packages/theme/brand", "build:tokens:debug": "yarn clean:theme && tsx --inspect-brk ./bin/designsystemet.ts tokens build -p -t ../../design-tokens -o ../../packages/theme/brand", - "build": "tsup && yarn build:types", + "build": "tsup && yarn build:types && yarn build:json-schema", "build:types": "tsc --emitDeclarationOnly --declaration", + "build:json-schema": "tsx ./src/build-scripts/createJsonSchema.ts", "types": "tsc --noEmit", "test:tokens-create-options": "yarn designsystemet tokens create -m dominant:#007682 complimentary:#ff0000 -n #003333 -s support1:#12404f support2:#0054a6 support3:#942977 -b 99 -o ./test-tokens-create", "test:tokens-create-json": "yarn designsystemet tokens create --json ./test-tokens-create-complex.config.json", @@ -85,6 +86,7 @@ "tslib": "^2.6.3", "tsup": "^8.2.4", "tsx": "^4.16.5", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "zod-to-json-schema": "^3.24.1" } } diff --git a/packages/cli/src/build-scripts/createJsonSchema.ts b/packages/cli/src/build-scripts/createJsonSchema.ts new file mode 100644 index 0000000000..3f2a5ea4fd --- /dev/null +++ b/packages/cli/src/build-scripts/createJsonSchema.ts @@ -0,0 +1,19 @@ +import { writeFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import { configFileSchema } from '../../bin/config.js'; + +const schema = z + .object({ + $schema: z.string().optional(), + }) + .extend(configFileSchema.shape); + +writeFile( + resolve(import.meta.dirname, '../../dist/config.schema.json'), + JSON.stringify(zodToJsonSchema(schema), undefined, 2), + { + encoding: 'utf-8', + }, +); diff --git a/packages/cli/test-tokens-create-complex.config.json b/packages/cli/test-tokens-create-complex.config.json index 3b6814354c..ea7a850752 100644 --- a/packages/cli/test-tokens-create-complex.config.json +++ b/packages/cli/test-tokens-create-complex.config.json @@ -1,4 +1,5 @@ { + "$schema": "./dist/config.schema.json", "outDir": "./test-tokens-create", "themes": { "some-org": { diff --git a/packages/cli/test-tokens-create.config.json b/packages/cli/test-tokens-create.config.json index 764f188331..1f58a15d89 100644 --- a/packages/cli/test-tokens-create.config.json +++ b/packages/cli/test-tokens-create.config.json @@ -1,4 +1,5 @@ { + "$schema": "./dist/config.schema.json", "outDir": "./test-tokens-create", "themes": { "digdir": { diff --git a/yarn.lock b/yarn.lock index 8a9b12d13b..5d2baf7a61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1785,6 +1785,7 @@ __metadata: tsx: "npm:^4.16.5" typescript: "npm:^5.5.4" zod: "npm:^3.23.8" + zod-to-json-schema: "npm:^3.24.1" zod-validation-error: "npm:^3.4.0" bin: designsystemet: dist/bin/designsystemet.js @@ -18526,6 +18527,15 @@ __metadata: languageName: node linkType: hard +"zod-to-json-schema@npm:^3.24.1": + version: 3.24.1 + resolution: "zod-to-json-schema@npm:3.24.1" + peerDependencies: + zod: ^3.24.1 + checksum: 10/d31fd05b67b428d8e0d5ecad2c3e80a1c2fc370e4c22f9111ffd11cbe05cfcab00f3228f84295830952649d15ea4494ef42c2ee1cbe723c865b13f4cf2b80c09 + languageName: node + linkType: hard + "zod-validation-error@npm:^3.4.0": version: 3.4.0 resolution: "zod-validation-error@npm:3.4.0"