From d951dfbf3429f1ec20e1e2077a1a4bf5107b316b Mon Sep 17 00:00:00 2001 From: nclsndr Date: Wed, 21 Aug 2024 16:16:56 +0200 Subject: [PATCH] Describe JSON Schemas --- generated/README.md | 3 + generated/tokens/border.json | 151 +++ generated/tokens/border/value.json | 116 ++ generated/tokens/color.json | 58 + generated/tokens/color/value.json | 23 + generated/tokens/cubicBezier.json | 62 + generated/tokens/cubicBezier/value.json | 27 + generated/tokens/dimension.json | 58 + generated/tokens/dimension/value.json | 23 + generated/tokens/duration.json | 58 + generated/tokens/duration/value.json | 23 + generated/tokens/fontFamily.json | 67 + generated/tokens/fontFamily/value.json | 32 + generated/tokens/fontWeight.json | 84 ++ generated/tokens/fontWeight/value.json | 49 + generated/tokens/gradient.json | 88 ++ generated/tokens/gradient/value.json | 53 + generated/tokens/number.json | 57 + generated/tokens/number/value.json | 22 + generated/tokens/shadow.json | 109 ++ generated/tokens/shadow/value.json | 74 ++ generated/tokens/strokeStyle.json | 108 ++ generated/tokens/strokeStyle/value.json | 73 + generated/tokens/transition.json | 105 ++ generated/tokens/transition/value.json | 70 + generated/tokens/typography.json | 171 +++ generated/tokens/typography/value.json | 136 ++ package.json | 2 + src/bin/generateJSONSchemas.ts | 67 + src/definitions/JSONSignatures.ts | 2 + src/definitions/tokenTypes.ts | 26 +- src/playground.ts | 21 + src/schemas/alias.ts | 11 + src/schemas/all.ts | 20 + src/schemas/constants.ts | 1 + src/schemas/generate.ts | 45 + src/schemas/group.ts | 14 + src/schemas/internals/makeTokenJSONSchema.ts | 26 + .../internals/makeTokenValueJSONSchema.ts | 31 + src/schemas/internals/withBaseURI.ts | 10 + src/schemas/tokenTree.ts | 16 + src/schemas/tokens.ts | 355 +++++ src/schemas/treeNode.ts | 21 + src/utils/capitalize.ts | 3 + src/utils/traverseJSONValue.ts | 22 + .../generateStandaloneSchema.spec.ts.snap | 1182 +++++++++++++++++ .../schemas/generateStandaloneSchema.spec.ts | 14 + tests/schemas/tokenTree.spec.ts | 49 + tests/utils/traverseJSONValue.spec.ts | 156 +++ 49 files changed, 3981 insertions(+), 13 deletions(-) create mode 100644 generated/README.md create mode 100644 generated/tokens/border.json create mode 100644 generated/tokens/border/value.json create mode 100644 generated/tokens/color.json create mode 100644 generated/tokens/color/value.json create mode 100644 generated/tokens/cubicBezier.json create mode 100644 generated/tokens/cubicBezier/value.json create mode 100644 generated/tokens/dimension.json create mode 100644 generated/tokens/dimension/value.json create mode 100644 generated/tokens/duration.json create mode 100644 generated/tokens/duration/value.json create mode 100644 generated/tokens/fontFamily.json create mode 100644 generated/tokens/fontFamily/value.json create mode 100644 generated/tokens/fontWeight.json create mode 100644 generated/tokens/fontWeight/value.json create mode 100644 generated/tokens/gradient.json create mode 100644 generated/tokens/gradient/value.json create mode 100644 generated/tokens/number.json create mode 100644 generated/tokens/number/value.json create mode 100644 generated/tokens/shadow.json create mode 100644 generated/tokens/shadow/value.json create mode 100644 generated/tokens/strokeStyle.json create mode 100644 generated/tokens/strokeStyle/value.json create mode 100644 generated/tokens/transition.json create mode 100644 generated/tokens/transition/value.json create mode 100644 generated/tokens/typography.json create mode 100644 generated/tokens/typography/value.json create mode 100644 src/bin/generateJSONSchemas.ts create mode 100644 src/playground.ts create mode 100644 src/schemas/alias.ts create mode 100644 src/schemas/all.ts create mode 100644 src/schemas/constants.ts create mode 100644 src/schemas/generate.ts create mode 100644 src/schemas/group.ts create mode 100644 src/schemas/internals/makeTokenJSONSchema.ts create mode 100644 src/schemas/internals/makeTokenValueJSONSchema.ts create mode 100644 src/schemas/internals/withBaseURI.ts create mode 100644 src/schemas/tokenTree.ts create mode 100644 src/schemas/tokens.ts create mode 100644 src/schemas/treeNode.ts create mode 100644 src/utils/capitalize.ts create mode 100644 src/utils/traverseJSONValue.ts create mode 100644 tests/schemas/__snapshots__/generateStandaloneSchema.spec.ts.snap create mode 100644 tests/schemas/generateStandaloneSchema.spec.ts create mode 100644 tests/schemas/tokenTree.spec.ts create mode 100644 tests/utils/traverseJSONValue.spec.ts diff --git a/generated/README.md b/generated/README.md new file mode 100644 index 0000000..9c10611 --- /dev/null +++ b/generated/README.md @@ -0,0 +1,3 @@ +## ⚠️ + +### The content of this folder is generated and should not be modified directly. diff --git a/generated/tokens/border.json b/generated/tokens/border.json new file mode 100644 index 0000000..a24edfa --- /dev/null +++ b/generated/tokens/border.json @@ -0,0 +1,151 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/border", + "title": "Border token", + "description": "The border token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^border$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/border/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/strokeStyle/value", + "title": "StrokeStyle value", + "description": "The stroke style of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "solid", + "dashed", + "dotted", + "double", + "groove", + "ridge", + "outset", + "inset" + ] + }, + { + "type": "object", + "properties": { + "dashArray": { + "type": "array", + "items": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + } + }, + "lineCap": { + "type": "string", + "enum": [ + "round", + "butt", + "square" + ] + } + }, + "required": [ + "dashArray", + "lineCap" + ] + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/border/value", + "title": "Border value", + "description": "The border of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "width": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "style": { + "$ref": "https://designtokens.org/schemas/tokens/strokeStyle/value" + } + }, + "required": [ + "color", + "width", + "style" + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/border/value.json b/generated/tokens/border/value.json new file mode 100644 index 0000000..e86f7c3 --- /dev/null +++ b/generated/tokens/border/value.json @@ -0,0 +1,116 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/border/value", + "title": "Border value", + "description": "The border of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "width": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "style": { + "$ref": "https://designtokens.org/schemas/tokens/strokeStyle/value" + } + }, + "required": [ + "color", + "width", + "style" + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/strokeStyle/value", + "title": "StrokeStyle value", + "description": "The stroke style of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "solid", + "dashed", + "dotted", + "double", + "groove", + "ridge", + "outset", + "inset" + ] + }, + { + "type": "object", + "properties": { + "dashArray": { + "type": "array", + "items": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + } + }, + "lineCap": { + "type": "string", + "enum": [ + "round", + "butt", + "square" + ] + } + }, + "required": [ + "dashArray", + "lineCap" + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/generated/tokens/color.json b/generated/tokens/color.json new file mode 100644 index 0000000..0c9d717 --- /dev/null +++ b/generated/tokens/color.json @@ -0,0 +1,58 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/color", + "title": "Color token", + "description": "The color token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^color$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/color/value.json b/generated/tokens/color/value.json new file mode 100644 index 0000000..f5d7c2f --- /dev/null +++ b/generated/tokens/color/value.json @@ -0,0 +1,23 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/cubicBezier.json b/generated/tokens/cubicBezier.json new file mode 100644 index 0000000..75823e2 --- /dev/null +++ b/generated/tokens/cubicBezier.json @@ -0,0 +1,62 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/cubicBezier", + "title": "CubicBezier token", + "description": "The cubic bezier token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^cubicBezier$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/cubicBezier/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/cubicBezier/value", + "title": "CubicBezier value", + "description": "The cubic bezier of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 4, + "maxItems": 4 + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/cubicBezier/value.json b/generated/tokens/cubicBezier/value.json new file mode 100644 index 0000000..fe7358c --- /dev/null +++ b/generated/tokens/cubicBezier/value.json @@ -0,0 +1,27 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/cubicBezier/value", + "title": "CubicBezier value", + "description": "The cubic bezier of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 4, + "maxItems": 4 + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/dimension.json b/generated/tokens/dimension.json new file mode 100644 index 0000000..2cbeedf --- /dev/null +++ b/generated/tokens/dimension.json @@ -0,0 +1,58 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/dimension", + "title": "Dimension token", + "description": "The dimension token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^dimension$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/dimension/value.json b/generated/tokens/dimension/value.json new file mode 100644 index 0000000..1ee5299 --- /dev/null +++ b/generated/tokens/dimension/value.json @@ -0,0 +1,23 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/duration.json b/generated/tokens/duration.json new file mode 100644 index 0000000..bebbc16 --- /dev/null +++ b/generated/tokens/duration.json @@ -0,0 +1,58 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/duration", + "title": "Duration token", + "description": "The duration token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^duration$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/duration/value", + "title": "Duration value", + "description": "The duration of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/duration/value.json b/generated/tokens/duration/value.json new file mode 100644 index 0000000..efafddc --- /dev/null +++ b/generated/tokens/duration/value.json @@ -0,0 +1,23 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/duration/value", + "title": "Duration value", + "description": "The duration of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$" + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/fontFamily.json b/generated/tokens/fontFamily.json new file mode 100644 index 0000000..1f2126b --- /dev/null +++ b/generated/tokens/fontFamily.json @@ -0,0 +1,67 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/fontFamily", + "title": "FontFamily token", + "description": "The font family token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^fontFamily$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/fontFamily/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontFamily/value", + "title": "FontFamily value", + "description": "The font family of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/fontFamily/value.json b/generated/tokens/fontFamily/value.json new file mode 100644 index 0000000..6e14669 --- /dev/null +++ b/generated/tokens/fontFamily/value.json @@ -0,0 +1,32 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/fontFamily/value", + "title": "FontFamily value", + "description": "The font family of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/fontWeight.json b/generated/tokens/fontWeight.json new file mode 100644 index 0000000..496e5d8 --- /dev/null +++ b/generated/tokens/fontWeight.json @@ -0,0 +1,84 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/fontWeight", + "title": "FontWeight token", + "description": "The font weight token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^fontWeight$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/fontWeight/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontWeight/value", + "title": "FontWeight value", + "description": "The font weight of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "thin", + "hairline", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "book", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + "heavy", + "extra-black", + "ultra-black" + ] + }, + { + "type": "number" + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/fontWeight/value.json b/generated/tokens/fontWeight/value.json new file mode 100644 index 0000000..7c190b6 --- /dev/null +++ b/generated/tokens/fontWeight/value.json @@ -0,0 +1,49 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/fontWeight/value", + "title": "FontWeight value", + "description": "The font weight of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "thin", + "hairline", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "book", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + "heavy", + "extra-black", + "ultra-black" + ] + }, + { + "type": "number" + } + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/gradient.json b/generated/tokens/gradient.json new file mode 100644 index 0000000..a8c9e06 --- /dev/null +++ b/generated/tokens/gradient.json @@ -0,0 +1,88 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/gradient", + "title": "Gradient token", + "description": "The gradient token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^gradient$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/gradient/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/gradient/value", + "title": "Gradient value", + "description": "The gradient of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "position": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "required": [ + "color", + "position" + ] + } + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/gradient/value.json b/generated/tokens/gradient/value.json new file mode 100644 index 0000000..d4030a9 --- /dev/null +++ b/generated/tokens/gradient/value.json @@ -0,0 +1,53 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/gradient/value", + "title": "Gradient value", + "description": "The gradient of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "position": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "required": [ + "color", + "position" + ] + } + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + } + ] +} \ No newline at end of file diff --git a/generated/tokens/number.json b/generated/tokens/number.json new file mode 100644 index 0000000..ac1d7cd --- /dev/null +++ b/generated/tokens/number.json @@ -0,0 +1,57 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/number", + "title": "Number token", + "description": "The number token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^number$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/number/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/number/value", + "title": "Number value", + "description": "The number of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "number" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/number/value.json b/generated/tokens/number/value.json new file mode 100644 index 0000000..4c1cc3d --- /dev/null +++ b/generated/tokens/number/value.json @@ -0,0 +1,22 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/number/value", + "title": "Number value", + "description": "The number of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "number" + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/shadow.json b/generated/tokens/shadow.json new file mode 100644 index 0000000..80a8906 --- /dev/null +++ b/generated/tokens/shadow.json @@ -0,0 +1,109 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/shadow", + "title": "Shadow token", + "description": "The shadow token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^shadow$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/shadow/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/shadow/value", + "title": "Shadow value", + "description": "The shadow of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "offsetX": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "offsetY": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "blur": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "spread": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + } + }, + "required": [ + "color", + "offsetX", + "offsetY", + "blur", + "spread" + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/shadow/value.json b/generated/tokens/shadow/value.json new file mode 100644 index 0000000..bd7e6c4 --- /dev/null +++ b/generated/tokens/shadow/value.json @@ -0,0 +1,74 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/shadow/value", + "title": "Shadow value", + "description": "The shadow of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value" + }, + "offsetX": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "offsetY": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "blur": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "spread": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + } + }, + "required": [ + "color", + "offsetX", + "offsetY", + "blur", + "spread" + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "title": "Color value", + "description": "The hexadecimal representation of a color.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6,8}$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + } + ] +} \ No newline at end of file diff --git a/generated/tokens/strokeStyle.json b/generated/tokens/strokeStyle.json new file mode 100644 index 0000000..b4f3e23 --- /dev/null +++ b/generated/tokens/strokeStyle.json @@ -0,0 +1,108 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/strokeStyle", + "title": "StrokeStyle token", + "description": "The stroke style token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^strokeStyle$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/strokeStyle/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/strokeStyle/value", + "title": "StrokeStyle value", + "description": "The stroke style of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "solid", + "dashed", + "dotted", + "double", + "groove", + "ridge", + "outset", + "inset" + ] + }, + { + "type": "object", + "properties": { + "dashArray": { + "type": "array", + "items": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + } + }, + "lineCap": { + "type": "string", + "enum": [ + "round", + "butt", + "square" + ] + } + }, + "required": [ + "dashArray", + "lineCap" + ] + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/strokeStyle/value.json b/generated/tokens/strokeStyle/value.json new file mode 100644 index 0000000..72de3ba --- /dev/null +++ b/generated/tokens/strokeStyle/value.json @@ -0,0 +1,73 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/strokeStyle/value", + "title": "StrokeStyle value", + "description": "The stroke style of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "solid", + "dashed", + "dotted", + "double", + "groove", + "ridge", + "outset", + "inset" + ] + }, + { + "type": "object", + "properties": { + "dashArray": { + "type": "array", + "items": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + } + }, + "lineCap": { + "type": "string", + "enum": [ + "round", + "butt", + "square" + ] + } + }, + "required": [ + "dashArray", + "lineCap" + ] + } + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + } + ] +} \ No newline at end of file diff --git a/generated/tokens/transition.json b/generated/tokens/transition.json new file mode 100644 index 0000000..145360c --- /dev/null +++ b/generated/tokens/transition.json @@ -0,0 +1,105 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/transition", + "title": "Transition token", + "description": "The transition token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^transition$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/transition/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/duration/value", + "title": "Duration value", + "description": "The duration of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/cubicBezier/value", + "title": "CubicBezier value", + "description": "The cubic bezier of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 4, + "maxItems": 4 + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/transition/value", + "title": "Transition value", + "description": "The transition of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "duration": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value" + }, + "delay": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value" + }, + "timingFunction": { + "$ref": "https://designtokens.org/schemas/tokens/cubicBezier/value" + } + }, + "required": [ + "duration", + "delay", + "timingFunction" + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/transition/value.json b/generated/tokens/transition/value.json new file mode 100644 index 0000000..def23b8 --- /dev/null +++ b/generated/tokens/transition/value.json @@ -0,0 +1,70 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/transition/value", + "title": "Transition value", + "description": "The transition of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "duration": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value" + }, + "delay": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value" + }, + "timingFunction": { + "$ref": "https://designtokens.org/schemas/tokens/cubicBezier/value" + } + }, + "required": [ + "duration", + "delay", + "timingFunction" + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/duration/value", + "title": "Duration value", + "description": "The duration of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/cubicBezier/value", + "title": "CubicBezier value", + "description": "The cubic bezier of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 4, + "maxItems": 4 + } + ] + } + ] +} \ No newline at end of file diff --git a/generated/tokens/typography.json b/generated/tokens/typography.json new file mode 100644 index 0000000..8a360cf --- /dev/null +++ b/generated/tokens/typography.json @@ -0,0 +1,171 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/typography", + "title": "Typography token", + "description": "The typography token.", + "type": "object", + "properties": { + "$type": { + "type": "string", + "pattern": "^typography$" + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/typography/value" + }, + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description" + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions" + } + }, + "required": [ + "$value" + ], + "additionalProperties": false, + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontFamily/value", + "title": "FontFamily value", + "description": "The font family of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontWeight/value", + "title": "FontWeight value", + "description": "The font weight of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "thin", + "hairline", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "book", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + "heavy", + "extra-black", + "ultra-black" + ] + }, + { + "type": "number" + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/number/value", + "title": "Number value", + "description": "The number of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "number" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/typography/value", + "title": "Typography value", + "description": "The typography of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "fontFamily": { + "$ref": "https://designtokens.org/schemas/tokens/fontFamily/value" + }, + "fontSize": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "fontWeight": { + "$ref": "https://designtokens.org/schemas/tokens/fontWeight/value" + }, + "letterSpacing": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "lineHeight": { + "$ref": "https://designtokens.org/schemas/tokens/number/value" + } + }, + "required": [ + "fontFamily", + "fontSize", + "fontWeight", + "letterSpacing", + "lineHeight" + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string" + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/generated/tokens/typography/value.json b/generated/tokens/typography/value.json new file mode 100644 index 0000000..cc39097 --- /dev/null +++ b/generated/tokens/typography/value.json @@ -0,0 +1,136 @@ +{ + "$id": "https://designtokens.org/schemas/tokens/typography/value", + "title": "Typography value", + "description": "The typography of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "object", + "properties": { + "fontFamily": { + "$ref": "https://designtokens.org/schemas/tokens/fontFamily/value" + }, + "fontSize": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "fontWeight": { + "$ref": "https://designtokens.org/schemas/tokens/fontWeight/value" + }, + "letterSpacing": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value" + }, + "lineHeight": { + "$ref": "https://designtokens.org/schemas/tokens/number/value" + } + }, + "required": [ + "fontFamily", + "fontSize", + "fontWeight", + "letterSpacing", + "lineHeight" + ] + } + ], + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "title": "Alias value", + "description": "A path to a value in the design token tree. Example: \"{colors.primary}\".", + "type": "string", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$" + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontFamily/value", + "title": "FontFamily value", + "description": "The font family of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "title": "Dimension value", + "description": "The dimension of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "string", + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$" + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontWeight/value", + "title": "FontWeight value", + "description": "The font weight of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "oneOf": [ + { + "type": "string", + "enum": [ + "thin", + "hairline", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "book", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + "heavy", + "extra-black", + "ultra-black" + ] + }, + { + "type": "number" + } + ] + } + ] + }, + { + "$id": "https://designtokens.org/schemas/tokens/number/value", + "title": "Number value", + "description": "The number of a property.", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value" + }, + { + "type": "number" + } + ] + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index fa6f7bb..6c01ad7 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "scripts": { "test": "vitest", "build": "tsc --build", + "generateSchemas": "tsc --build && node ./dist/bin/generateJSONSchemas.js", "tsc": "tsc" }, "main": "./dist/index.js", @@ -24,6 +25,7 @@ "devDependencies": { "@types/node": "^20.14.10", "@vitest/coverage-v8": "^1.6.0", + "ajv": "^8.17.1", "prettier": "^3.3.3", "typescript": "^5.5.4", "vitest": "^1.6.0" diff --git a/src/bin/generateJSONSchemas.ts b/src/bin/generateJSONSchemas.ts new file mode 100644 index 0000000..eec5355 --- /dev/null +++ b/src/bin/generateJSONSchemas.ts @@ -0,0 +1,67 @@ +import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { URL } from 'node:url'; + +import { generateStandaloneSchema } from '../schemas/generate.js'; +import { + allTokenJSONSchemas, + allTokenValueJSONSchemas, +} from '../schemas/tokens.js'; +import { JSON_SCHEMA_BASE_URI } from '../schemas/constants.js'; + +const moduleRoot = resolve(new URL('.', import.meta.url).pathname, '..', '..'); + +const generatedDirPath = resolve(moduleRoot, 'generated'); +if (!existsSync(generatedDirPath)) { + mkdirSync(generatedDirPath, { recursive: true }); +} + +/* ------------------------------------------ + Tokens +--------------------------------------------- */ +console.log('Generate JSON schemas for tokens'); +allTokenJSONSchemas + .map((schema) => generateStandaloneSchema(schema)) + .forEach((schema) => { + console.log('Generate schema for:', schema.$id); + + // assuming the $id is like: https://designtokens.org/schemas/tokens/color + const pathItems = schema.$id + .replaceAll(JSON_SCHEMA_BASE_URI, '') + .split('/'); + const tail = pathItems.pop(); + + const path = resolve(generatedDirPath, ...pathItems); + if (!existsSync(path)) { + mkdirSync(path, { recursive: true }); + } + writeFileSync( + resolve(path, `${tail}.json`), + JSON.stringify(schema, null, 2), + ); + }); + +/* ------------------------------------------ + Token values +--------------------------------------------- */ +console.log('Generate JSON schemas for token values'); +allTokenValueJSONSchemas + .map((schema) => generateStandaloneSchema(schema)) + .forEach((schema) => { + console.log('Generate schema for:', schema.$id); + + // assuming the $id is like: https://designtokens.org/schemas/tokens/color + const pathItems = schema.$id + .replaceAll(JSON_SCHEMA_BASE_URI, '') + .split('/'); + const tail = pathItems.pop(); + + const path = resolve(generatedDirPath, ...pathItems); + if (!existsSync(path)) { + mkdirSync(path, { recursive: true }); + } + writeFileSync( + resolve(path, `${tail}.json`), + JSON.stringify(schema, null, 2), + ); + }); diff --git a/src/definitions/JSONSignatures.ts b/src/definitions/JSONSignatures.ts index 491e954..a3f1ab1 100644 --- a/src/definitions/JSONSignatures.ts +++ b/src/definitions/JSONSignatures.ts @@ -11,3 +11,5 @@ export namespace JSON { export type Array = JSONArray; export type Primitive = string | number | boolean | null; } + +export type JSONValuePath = (string | number)[]; diff --git a/src/definitions/tokenTypes.ts b/src/definitions/tokenTypes.ts index 44a79a4..4f549f9 100644 --- a/src/definitions/tokenTypes.ts +++ b/src/definitions/tokenTypes.ts @@ -4,7 +4,7 @@ import type { TokenSignature } from './TokenSignature.js'; // Type declaration following the https://tr.designtokens.org/format specification // 8.1 Color -const colorTypeName = 'color'; +export const colorTypeName = 'color'; type ColorTypeName = typeof colorTypeName; type ColorValue = WithAliasValue<`#${string}`>; type ColorToken = TokenSignature; @@ -15,7 +15,7 @@ export namespace Color { } // 8.2 Dimension -const dimensionTypeName = 'dimension'; +export const dimensionTypeName = 'dimension'; type DimensionTypeName = typeof dimensionTypeName; type DimensionValue = WithAliasValue<`${number}px` | `${number}rem`>; type DimensionToken = TokenSignature; @@ -26,7 +26,7 @@ export namespace Dimension { } // 8.3 Font Family -const fontFamilyTypeName = 'fontFamily'; +export const fontFamilyTypeName = 'fontFamily'; type FontFamilyTypeName = typeof fontFamilyTypeName; type FontFamilyValue = WithAliasValue>; type FontFamilyToken = TokenSignature; @@ -37,7 +37,7 @@ export namespace FontFamily { } // 8.4 Font Weight -const fontWeightTypeName = 'fontWeight'; +export const fontWeightTypeName = 'fontWeight'; type FontWeightTypeName = typeof fontWeightTypeName; export const fontWeightValues = [ 'thin', @@ -70,7 +70,7 @@ export namespace FontWeight { } // 8.5 Duration -const durationTypeName = 'duration'; +export const durationTypeName = 'duration'; type DurationTypeName = typeof durationTypeName; type DurationValue = WithAliasValue<`${number}ms` | `${number}s`>; type DurationToken = TokenSignature; @@ -81,7 +81,7 @@ export namespace Duration { } // 8.6 Cubic Bezier -const cubicBezierTypeName = 'cubicBezier'; +export const cubicBezierTypeName = 'cubicBezier'; type CubicBezierTypeName = typeof cubicBezierTypeName; type CubicBezierValue = WithAliasValue<[number, number, number, number]>; type CubicBezierToken = TokenSignature; @@ -92,7 +92,7 @@ export namespace CubicBezier { } // 8.7 Number -const numberTypeName = 'number'; +export const numberTypeName = 'number'; type NumberTypeName = typeof numberTypeName; type NumberValue = WithAliasValue; type NumberToken = TokenSignature; @@ -107,7 +107,7 @@ export namespace Number { https://tr.designtokens.org/format/#composite-types */ // 9.2 Stroke Style -const strokeStyleTypeName = 'strokeStyle'; +export const strokeStyleTypeName = 'strokeStyle'; type StrokeStyleTypeName = typeof strokeStyleTypeName; export const strokeStyleStringValues = [ 'solid', @@ -135,7 +135,7 @@ export namespace StrokeStyle { } // 9.3 Border -const borderTypeName = 'border'; +export const borderTypeName = 'border'; type BorderTypeName = typeof borderTypeName; type BorderValue = WithAliasValue<{ color: ColorValue; @@ -150,7 +150,7 @@ export namespace Border { } // 9.4 Transition -const transitionTypeName = 'transition'; +export const transitionTypeName = 'transition'; type TransitionTypeName = typeof transitionTypeName; type TransitionValue = WithAliasValue<{ duration: DurationValue; @@ -165,7 +165,7 @@ export namespace Transition { } // 9.5 Shadow -const shadowTypeName = 'shadow'; +export const shadowTypeName = 'shadow'; type ShadowTypeName = typeof shadowTypeName; type ShadowValue = WithAliasValue<{ color: ColorValue; @@ -182,7 +182,7 @@ export namespace Shadow { } // 9.6 Gradient -const gradientTypeName = 'gradient'; +export const gradientTypeName = 'gradient'; type GradientTypeName = typeof gradientTypeName; type GradientValue = WithAliasValue< Array<{ @@ -198,7 +198,7 @@ export namespace Gradient { } // 9.7 Typography -const typographyTypeName = 'typography'; +export const typographyTypeName = 'typography'; type TypographyTypeName = typeof typographyTypeName; type TypographyValue = WithAliasValue<{ fontFamily: FontFamilyValue; diff --git a/src/playground.ts b/src/playground.ts new file mode 100644 index 0000000..cdabfa6 --- /dev/null +++ b/src/playground.ts @@ -0,0 +1,21 @@ +const schemaBluePrint = { + $schema: 'https://json-schema.org/draft/2020-12/schema', +}; + +export function makeSchema( + schema: any, + { + dependencies = [], + }: { + dependencies?: any[]; + } = {}, +) { + const finalSchema = { + ...schemaBluePrint, + ...schema, + }; + if (dependencies.length > 0) { + finalSchema.$defs = dependencies[0]; + } + return finalSchema; +} diff --git a/src/schemas/alias.ts b/src/schemas/alias.ts new file mode 100644 index 0000000..0126afd --- /dev/null +++ b/src/schemas/alias.ts @@ -0,0 +1,11 @@ +import { withBaseURI } from './internals/withBaseURI.js'; + +export const aliasValuePattern = '^\\{[a-zA-Z0-9_\\-\\.]+\\}$'; +export const aliasValueJSONSchema = { + $id: withBaseURI('/alias/value'), + title: 'Alias value', + description: + 'A path to a value in the design token tree. Example: "{colors.primary}".', + type: 'string', + pattern: aliasValuePattern, +}; diff --git a/src/schemas/all.ts b/src/schemas/all.ts new file mode 100644 index 0000000..85f00c3 --- /dev/null +++ b/src/schemas/all.ts @@ -0,0 +1,20 @@ +import { groupJSONSchema } from './group.js'; +import { aliasValueJSONSchema } from './alias.js'; +import { + descriptionJSONSchema, + extensionsJSONSchema, + tokenTypeNameJSONSchema, +} from './treeNode.js'; +import { tokenTreeJSONSchema } from './tokenTree.js'; +import { allTokenJSONSchemas, allTokenValueJSONSchemas } from './tokens.js'; + +export const allJSONSchemas = [ + tokenTypeNameJSONSchema, + descriptionJSONSchema, + extensionsJSONSchema, + aliasValueJSONSchema, + tokenTreeJSONSchema, + groupJSONSchema, + ...allTokenJSONSchemas, + ...allTokenValueJSONSchemas, +]; diff --git a/src/schemas/constants.ts b/src/schemas/constants.ts new file mode 100644 index 0000000..0f5cba4 --- /dev/null +++ b/src/schemas/constants.ts @@ -0,0 +1 @@ +export const JSON_SCHEMA_BASE_URI = 'https://designtokens.org/schemas'; diff --git a/src/schemas/generate.ts b/src/schemas/generate.ts new file mode 100644 index 0000000..2afc919 --- /dev/null +++ b/src/schemas/generate.ts @@ -0,0 +1,45 @@ +import { traverseJSONValue } from '../utils/traverseJSONValue.js'; +import { allJSONSchemas } from './all.js'; + +const allJSONSchemasMap = new Map( + allJSONSchemas.map((schema) => [schema.$id, schema]), +); + +function resolveRef(ref: string) { + const [base] = ref.split('#/'); + const foundSchema = allJSONSchemasMap.get(base); + if (!foundSchema) { + throw new Error(`Schema with $id ${ref} not found`); + } + return foundSchema; +} + +function collectRefs(schema: any, initialRefIds: Set = new Set()) { + traverseJSONValue(schema, (value, path) => { + if ( + typeof value === 'object' && + value !== null && + !Array.isArray(value) && + '$ref' in value && + typeof value.$ref === 'string' + ) { + collectRefs(resolveRef(value.$ref), initialRefIds).forEach((ref) => { + initialRefIds.add(ref); + }); + initialRefIds.add(value.$ref); + return false; + } + return true; + }); + + return initialRefIds; +} + +export function generateStandaloneSchema(schema: any) { + const $defs = Array.from(collectRefs(schema)).map(($id) => resolveRef($id)); + + return { + ...schema, + $defs, + }; +} diff --git a/src/schemas/group.ts b/src/schemas/group.ts new file mode 100644 index 0000000..a3f0e3c --- /dev/null +++ b/src/schemas/group.ts @@ -0,0 +1,14 @@ +import { withBaseURI } from './internals/withBaseURI.js'; + +export const groupJSONSchema = { + $id: withBaseURI('/group'), + type: 'object', + properties: { + $type: { $ref: withBaseURI('/treeNode/tokenTypeName') }, + $description: { $ref: withBaseURI('/treeNode/description') }, + $extensions: { $ref: withBaseURI('/treeNode/extensions') }, + }, + additionalProperties: { + $ref: withBaseURI('/tokenTree#/additionalProperties'), + }, +}; diff --git a/src/schemas/internals/makeTokenJSONSchema.ts b/src/schemas/internals/makeTokenJSONSchema.ts new file mode 100644 index 0000000..231e138 --- /dev/null +++ b/src/schemas/internals/makeTokenJSONSchema.ts @@ -0,0 +1,26 @@ +import type { TokenTypeName } from '../../definitions/tokenTypes.js'; +import { withBaseURI } from './withBaseURI.js'; +import { capitalize } from '../../utils/capitalize.js'; + +export function makeTokenJSONSchema({ + tokenType, + description, +}: { + tokenType: TokenTypeName; + description: string; +}) { + return { + $id: withBaseURI(`/tokens/${tokenType}`), + title: `${capitalize(tokenType)} token`, + description, + type: 'object', + properties: { + $type: { type: 'string', pattern: `^${tokenType}$` }, + $value: { $ref: withBaseURI(`/tokens/${tokenType}/value`) }, + $description: { $ref: withBaseURI('/treeNode/description') }, + $extensions: { $ref: withBaseURI('/treeNode/extensions') }, + }, + required: ['$value'], + additionalProperties: false, + }; +} diff --git a/src/schemas/internals/makeTokenValueJSONSchema.ts b/src/schemas/internals/makeTokenValueJSONSchema.ts new file mode 100644 index 0000000..eb5d4be --- /dev/null +++ b/src/schemas/internals/makeTokenValueJSONSchema.ts @@ -0,0 +1,31 @@ +import { type TokenTypeName } from '../../definitions/tokenTypes.js'; +import { capitalize } from '../../utils/capitalize.js'; +import { withBaseURI } from './withBaseURI.js'; + +export function makeTokenValueJSONSchema({ + tokenType, + description, + rawValueSchema, +}: { + tokenType: TokenTypeName; + description: string; + rawValueSchema: { [k: string]: any }; +}) { + const anyOf: any[] = [ + { + $ref: withBaseURI('/alias/value'), + }, + ]; + if ('anyOf' in rawValueSchema) { + anyOf.push(...rawValueSchema.anyOf); + } else { + anyOf.push(rawValueSchema); + } + + return { + $id: withBaseURI(`/tokens/${tokenType}/value`), + title: `${capitalize(tokenType)} value`, + description: description, + anyOf, + }; +} diff --git a/src/schemas/internals/withBaseURI.ts b/src/schemas/internals/withBaseURI.ts new file mode 100644 index 0000000..600e6ab --- /dev/null +++ b/src/schemas/internals/withBaseURI.ts @@ -0,0 +1,10 @@ +import { JSON_SCHEMA_BASE_URI } from '../constants.js'; + +export function withBaseURI(path: string) { + if (path.startsWith('/') === false) { + throw new Error( + 'Path must be absolute, thus starts with a forward slash (/).', + ); + } + return JSON_SCHEMA_BASE_URI + path; +} diff --git a/src/schemas/tokenTree.ts b/src/schemas/tokenTree.ts new file mode 100644 index 0000000..465e6e0 --- /dev/null +++ b/src/schemas/tokenTree.ts @@ -0,0 +1,16 @@ +import { withBaseURI } from './internals/withBaseURI.js'; +import { allTokenJSONSchemas } from './tokens.js'; + +export const tokenTreeJSONSchema = { + $id: withBaseURI('/tokenTree'), + title: 'Token tree', + type: 'object', + additionalProperties: { + anyOf: [ + ...allTokenJSONSchemas.map((s) => ({ $ref: s.$id })), + { + $ref: withBaseURI('/group'), + }, + ], + }, +}; diff --git a/src/schemas/tokens.ts b/src/schemas/tokens.ts new file mode 100644 index 0000000..2fad363 --- /dev/null +++ b/src/schemas/tokens.ts @@ -0,0 +1,355 @@ +import { makeTokenJSONSchema } from './internals/makeTokenJSONSchema.js'; +import { makeTokenValueJSONSchema } from './internals/makeTokenValueJSONSchema.js'; +import { withBaseURI } from './internals/withBaseURI.js'; +import { + borderTypeName, + colorTypeName, + cubicBezierTypeName, + dimensionTypeName, + durationTypeName, + fontFamilyTypeName, + fontWeightTypeName, + fontWeightValues, + gradientTypeName, + numberTypeName, + shadowTypeName, + strokeStyleLineCapValues, + strokeStyleStringValues, + strokeStyleTypeName, + transitionTypeName, + typographyTypeName, +} from '../definitions/tokenTypes.js'; + +// 8.1 Color +export const colorValuePattern = '^#[0-9a-fA-F]{6,8}$'; +export const colorValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: colorTypeName, + description: 'The hexadecimal representation of a color.', + rawValueSchema: { + type: 'string', + pattern: colorValuePattern, + }, +}); +export const colorJSONSchema = makeTokenJSONSchema({ + tokenType: colorTypeName, + description: 'The color token.', +}); + +// 8.2 Dimension +export const dimensionValuePattern = '^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$'; +export const dimensionValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: dimensionTypeName, + description: 'The dimension of a property.', + rawValueSchema: { + type: 'string', + pattern: dimensionValuePattern, + }, +}); +export const dimensionJSONSchema = makeTokenJSONSchema({ + tokenType: dimensionTypeName, + description: 'The dimension token.', +}); + +// 8.3 Font Family +export const fontFamilyValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: fontFamilyTypeName, + description: 'The font family of a property.', + rawValueSchema: { + oneOf: [ + { + type: 'string', + }, + { + type: 'array', + items: { + type: 'string', + }, + }, + ], + }, +}); +export const fontFamilyJSONSchema = makeTokenJSONSchema({ + tokenType: fontFamilyTypeName, + description: 'The font family token.', +}); + +// 8.4 Font Weight +export const fontWeightValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: fontWeightTypeName, + description: 'The font weight of a property.', + rawValueSchema: { + oneOf: [ + { + type: 'string', + enum: fontWeightValues, + }, + { + type: 'number', + }, + ], + }, +}); +export const fontWeightJSONSchema = makeTokenJSONSchema({ + tokenType: fontWeightTypeName, + description: 'The font weight token.', +}); + +// 8.5 Duration +export const durationValuePattern = '^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$'; +export const durationValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: durationTypeName, + description: 'The duration of a property.', + rawValueSchema: { + type: 'string', + pattern: durationValuePattern, + }, +}); +export const durationJSONSchema = makeTokenJSONSchema({ + tokenType: durationTypeName, + description: 'The duration token.', +}); + +// 8.6 Cubic Bezier +export const cubicBezierValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: cubicBezierTypeName, + description: 'The cubic bezier of a property.', + rawValueSchema: { + type: 'array', + items: { + // TODO @Nico: missing 0-1 boundaries - how to tuple? + type: 'number', + }, + minItems: 4, + maxItems: 4, + }, +}); +export const cubicBezierJSONSchema = makeTokenJSONSchema({ + tokenType: cubicBezierTypeName, + description: 'The cubic bezier token.', +}); + +// 8.7 Number +export const numberValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: numberTypeName, + description: 'The number of a property.', + rawValueSchema: { + type: 'number', + }, +}); +export const numberJSONSchema = makeTokenJSONSchema({ + tokenType: numberTypeName, + description: 'The number token.', +}); + +// 9.2 Stroke Style +export const strokeStyleValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: strokeStyleTypeName, + description: 'The stroke style of a property.', + rawValueSchema: { + oneOf: [ + { + type: 'string', + enum: strokeStyleStringValues, + }, + { + type: 'object', + properties: { + dashArray: { + type: 'array', + items: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + }, + lineCap: { + type: 'string', + enum: strokeStyleLineCapValues, + }, + }, + required: ['dashArray', 'lineCap'], + }, + ], + }, +}); +export const strokeStyleJSONSchema = makeTokenJSONSchema({ + tokenType: strokeStyleTypeName, + description: 'The stroke style token.', +}); + +// 9.3 Border +export const borderValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: borderTypeName, + description: 'The border of a property.', + rawValueSchema: { + type: 'object', + properties: { + color: { + $ref: withBaseURI('/tokens/color/value'), + }, + width: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + style: { + $ref: withBaseURI('/tokens/strokeStyle/value'), + }, + }, + required: ['color', 'width', 'style'], + }, +}); +export const borderJSONSchema = makeTokenJSONSchema({ + tokenType: borderTypeName, + description: 'The border token.', +}); + +// 9.4 Transition +export const transitionValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: transitionTypeName, + description: 'The transition of a property.', + rawValueSchema: { + type: 'object', + properties: { + duration: { + $ref: withBaseURI('/tokens/duration/value'), + }, + delay: { + $ref: withBaseURI('/tokens/duration/value'), + }, + timingFunction: { + $ref: withBaseURI('/tokens/cubicBezier/value'), + }, + }, + required: ['duration', 'delay', 'timingFunction'], + }, +}); +export const transitionJSONSchema = makeTokenJSONSchema({ + tokenType: transitionTypeName, + description: 'The transition token.', +}); + +// 9.5 Shadow +export const shadowValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: shadowTypeName, + description: 'The shadow of a property.', + rawValueSchema: { + type: 'object', + properties: { + color: { + $ref: withBaseURI('/tokens/color/value'), + }, + offsetX: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + offsetY: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + blur: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + spread: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + }, + required: ['color', 'offsetX', 'offsetY', 'blur', 'spread'], + }, +}); +export const shadowJSONSchema = makeTokenJSONSchema({ + tokenType: shadowTypeName, + description: 'The shadow token.', +}); + +// 9.6 Gradient +export const gradientValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: gradientTypeName, + description: 'The gradient of a property.', + rawValueSchema: { + type: 'array', + items: { + type: 'object', + properties: { + color: { + $ref: withBaseURI('/tokens/color/value'), + }, + position: { + type: 'number', + minimum: 0, + maximum: 1, + }, + }, + required: ['color', 'position'], + }, + }, +}); +export const gradientJSONSchema = makeTokenJSONSchema({ + tokenType: gradientTypeName, + description: 'The gradient token.', +}); + +// 9.7 Typography +export const typographyValueJSONSchema = makeTokenValueJSONSchema({ + tokenType: typographyTypeName, + description: 'The typography of a property.', + rawValueSchema: { + type: 'object', + properties: { + fontFamily: { + $ref: withBaseURI('/tokens/fontFamily/value'), + }, + fontSize: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + fontWeight: { + $ref: withBaseURI('/tokens/fontWeight/value'), + }, + letterSpacing: { + $ref: withBaseURI('/tokens/dimension/value'), + }, + lineHeight: { + $ref: withBaseURI('/tokens/number/value'), + }, + }, + required: [ + 'fontFamily', + 'fontSize', + 'fontWeight', + 'letterSpacing', + 'lineHeight', + ], + }, +}); +export const typographyJSONSchema = makeTokenJSONSchema({ + tokenType: typographyTypeName, + description: 'The typography token.', +}); + +/* ------------------------------------------ + Mapping Exports +--------------------------------------------- */ +export const allTokenValueJSONSchemas = [ + colorValueJSONSchema, + dimensionValueJSONSchema, + fontFamilyValueJSONSchema, + fontWeightValueJSONSchema, + durationValueJSONSchema, + cubicBezierValueJSONSchema, + numberValueJSONSchema, + strokeStyleValueJSONSchema, + borderValueJSONSchema, + transitionValueJSONSchema, + shadowValueJSONSchema, + gradientValueJSONSchema, + typographyValueJSONSchema, +] as const; +export const allTokenJSONSchemas = [ + colorJSONSchema, + dimensionJSONSchema, + fontFamilyJSONSchema, + fontWeightJSONSchema, + durationJSONSchema, + cubicBezierJSONSchema, + numberJSONSchema, + strokeStyleJSONSchema, + borderJSONSchema, + transitionJSONSchema, + shadowJSONSchema, + gradientJSONSchema, + typographyJSONSchema, +] as const; diff --git a/src/schemas/treeNode.ts b/src/schemas/treeNode.ts new file mode 100644 index 0000000..36979ef --- /dev/null +++ b/src/schemas/treeNode.ts @@ -0,0 +1,21 @@ +import { withBaseURI } from './internals/withBaseURI.js'; +import { tokenTypeNames } from '../definitions/tokenTypes.js'; + +export const tokenTypeNameJSONSchema = { + $id: withBaseURI('/treeNode/tokenTypeName'), + title: 'Token type', + type: 'string', + enum: tokenTypeNames, +}; + +export const descriptionJSONSchema = { + $id: withBaseURI('/treeNode/description'), + title: 'Description', + type: 'string', +}; + +export const extensionsJSONSchema = { + $id: withBaseURI('/treeNode/extensions'), + title: 'Extensions', + type: 'object', +}; diff --git a/src/utils/capitalize.ts b/src/utils/capitalize.ts new file mode 100644 index 0000000..7519095 --- /dev/null +++ b/src/utils/capitalize.ts @@ -0,0 +1,3 @@ +export function capitalize(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); +} diff --git a/src/utils/traverseJSONValue.ts b/src/utils/traverseJSONValue.ts new file mode 100644 index 0000000..6b0feb1 --- /dev/null +++ b/src/utils/traverseJSONValue.ts @@ -0,0 +1,22 @@ +import { JSONValue, JSONValuePath } from '../definitions/JSONSignatures.js'; + +export function traverseJSONValue( + JSONValue: JSONValue, + callback: (data: JSONValue, path: JSONValuePath) => boolean | void, + path: JSONValuePath = [], +) { + if (JSONValue === undefined) throw new Error('JSONValue is undefined'); + const shouldDive = callback(JSONValue, path) ?? true; + if (!shouldDive) return; + if (JSONValue !== null && typeof JSONValue === 'object') { + if (Array.isArray(JSONValue)) { + JSONValue.forEach((item, i) => { + traverseJSONValue(item, callback, [...path, i]); + }); + } else { + Object.keys(JSONValue).forEach((key) => { + traverseJSONValue(JSONValue[key], callback, [...path, key]); + }); + } + } +} diff --git a/tests/schemas/__snapshots__/generateStandaloneSchema.spec.ts.snap b/tests/schemas/__snapshots__/generateStandaloneSchema.spec.ts.snap new file mode 100644 index 0000000..9b33136 --- /dev/null +++ b/tests/schemas/__snapshots__/generateStandaloneSchema.spec.ts.snap @@ -0,0 +1,1182 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`generateStandaloneSchema > Should generate standalone schemas for token types 1`] = ` +[ + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^#[0-9a-fA-F]{6,8}$", + "type": "string", + }, + ], + "description": "The hexadecimal representation of a color.", + "title": "Color value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/color", + "additionalProperties": false, + "description": "The color token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^color$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/color/value", + }, + }, + "required": [ + "$value", + ], + "title": "Color token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$", + "type": "string", + }, + ], + "description": "The dimension of a property.", + "title": "Dimension value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/dimension", + "additionalProperties": false, + "description": "The dimension token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^dimension$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + }, + "required": [ + "$value", + ], + "title": "Dimension token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontFamily/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "oneOf": [ + { + "type": "string", + }, + { + "items": { + "type": "string", + }, + "type": "array", + }, + ], + }, + ], + "description": "The font family of a property.", + "title": "FontFamily value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/fontFamily", + "additionalProperties": false, + "description": "The font family token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^fontFamily$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/fontFamily/value", + }, + }, + "required": [ + "$value", + ], + "title": "FontFamily token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontWeight/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "oneOf": [ + { + "enum": [ + "thin", + "hairline", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "book", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + "heavy", + "extra-black", + "ultra-black", + ], + "type": "string", + }, + { + "type": "number", + }, + ], + }, + ], + "description": "The font weight of a property.", + "title": "FontWeight value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/fontWeight", + "additionalProperties": false, + "description": "The font weight token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^fontWeight$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/fontWeight/value", + }, + }, + "required": [ + "$value", + ], + "title": "FontWeight token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/duration/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$", + "type": "string", + }, + ], + "description": "The duration of a property.", + "title": "Duration value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/duration", + "additionalProperties": false, + "description": "The duration token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^duration$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value", + }, + }, + "required": [ + "$value", + ], + "title": "Duration token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/cubicBezier/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "items": { + "type": "number", + }, + "maxItems": 4, + "minItems": 4, + "type": "array", + }, + ], + "description": "The cubic bezier of a property.", + "title": "CubicBezier value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/cubicBezier", + "additionalProperties": false, + "description": "The cubic bezier token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^cubicBezier$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/cubicBezier/value", + }, + }, + "required": [ + "$value", + ], + "title": "CubicBezier token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/number/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "type": "number", + }, + ], + "description": "The number of a property.", + "title": "Number value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/number", + "additionalProperties": false, + "description": "The number token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^number$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/number/value", + }, + }, + "required": [ + "$value", + ], + "title": "Number token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$", + "type": "string", + }, + ], + "description": "The dimension of a property.", + "title": "Dimension value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/strokeStyle/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "oneOf": [ + { + "enum": [ + "solid", + "dashed", + "dotted", + "double", + "groove", + "ridge", + "outset", + "inset", + ], + "type": "string", + }, + { + "properties": { + "dashArray": { + "items": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "type": "array", + }, + "lineCap": { + "enum": [ + "round", + "butt", + "square", + ], + "type": "string", + }, + }, + "required": [ + "dashArray", + "lineCap", + ], + "type": "object", + }, + ], + }, + ], + "description": "The stroke style of a property.", + "title": "StrokeStyle value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/strokeStyle", + "additionalProperties": false, + "description": "The stroke style token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^strokeStyle$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/strokeStyle/value", + }, + }, + "required": [ + "$value", + ], + "title": "StrokeStyle token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^#[0-9a-fA-F]{6,8}$", + "type": "string", + }, + ], + "description": "The hexadecimal representation of a color.", + "title": "Color value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$", + "type": "string", + }, + ], + "description": "The dimension of a property.", + "title": "Dimension value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/strokeStyle/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "oneOf": [ + { + "enum": [ + "solid", + "dashed", + "dotted", + "double", + "groove", + "ridge", + "outset", + "inset", + ], + "type": "string", + }, + { + "properties": { + "dashArray": { + "items": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "type": "array", + }, + "lineCap": { + "enum": [ + "round", + "butt", + "square", + ], + "type": "string", + }, + }, + "required": [ + "dashArray", + "lineCap", + ], + "type": "object", + }, + ], + }, + ], + "description": "The stroke style of a property.", + "title": "StrokeStyle value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/border/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value", + }, + "style": { + "$ref": "https://designtokens.org/schemas/tokens/strokeStyle/value", + }, + "width": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + }, + "required": [ + "color", + "width", + "style", + ], + "type": "object", + }, + ], + "description": "The border of a property.", + "title": "Border value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/border", + "additionalProperties": false, + "description": "The border token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^border$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/border/value", + }, + }, + "required": [ + "$value", + ], + "title": "Border token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/duration/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:ms|s)$", + "type": "string", + }, + ], + "description": "The duration of a property.", + "title": "Duration value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/cubicBezier/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "items": { + "type": "number", + }, + "maxItems": 4, + "minItems": 4, + "type": "array", + }, + ], + "description": "The cubic bezier of a property.", + "title": "CubicBezier value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/transition/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "properties": { + "delay": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value", + }, + "duration": { + "$ref": "https://designtokens.org/schemas/tokens/duration/value", + }, + "timingFunction": { + "$ref": "https://designtokens.org/schemas/tokens/cubicBezier/value", + }, + }, + "required": [ + "duration", + "delay", + "timingFunction", + ], + "type": "object", + }, + ], + "description": "The transition of a property.", + "title": "Transition value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/transition", + "additionalProperties": false, + "description": "The transition token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^transition$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/transition/value", + }, + }, + "required": [ + "$value", + ], + "title": "Transition token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^#[0-9a-fA-F]{6,8}$", + "type": "string", + }, + ], + "description": "The hexadecimal representation of a color.", + "title": "Color value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$", + "type": "string", + }, + ], + "description": "The dimension of a property.", + "title": "Dimension value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/shadow/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "properties": { + "blur": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value", + }, + "offsetX": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "offsetY": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "spread": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + }, + "required": [ + "color", + "offsetX", + "offsetY", + "blur", + "spread", + ], + "type": "object", + }, + ], + "description": "The shadow of a property.", + "title": "Shadow value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/shadow", + "additionalProperties": false, + "description": "The shadow token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^shadow$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/shadow/value", + }, + }, + "required": [ + "$value", + ], + "title": "Shadow token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/color/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^#[0-9a-fA-F]{6,8}$", + "type": "string", + }, + ], + "description": "The hexadecimal representation of a color.", + "title": "Color value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/gradient/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "items": { + "properties": { + "color": { + "$ref": "https://designtokens.org/schemas/tokens/color/value", + }, + "position": { + "maximum": 1, + "minimum": 0, + "type": "number", + }, + }, + "required": [ + "color", + "position", + ], + "type": "object", + }, + "type": "array", + }, + ], + "description": "The gradient of a property.", + "title": "Gradient value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/gradient", + "additionalProperties": false, + "description": "The gradient token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^gradient$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/gradient/value", + }, + }, + "required": [ + "$value", + ], + "title": "Gradient token", + "type": "object", + }, + { + "$defs": [ + { + "$id": "https://designtokens.org/schemas/alias/value", + "description": "A path to a value in the design token tree. Example: "{colors.primary}".", + "pattern": "^\\{[a-zA-Z0-9_\\-\\.]+\\}$", + "title": "Alias value", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontFamily/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "oneOf": [ + { + "type": "string", + }, + { + "items": { + "type": "string", + }, + "type": "array", + }, + ], + }, + ], + "description": "The font family of a property.", + "title": "FontFamily value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/dimension/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "pattern": "^(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:px|rem)$", + "type": "string", + }, + ], + "description": "The dimension of a property.", + "title": "Dimension value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/fontWeight/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "oneOf": [ + { + "enum": [ + "thin", + "hairline", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "book", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + "heavy", + "extra-black", + "ultra-black", + ], + "type": "string", + }, + { + "type": "number", + }, + ], + }, + ], + "description": "The font weight of a property.", + "title": "FontWeight value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/number/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "type": "number", + }, + ], + "description": "The number of a property.", + "title": "Number value", + }, + { + "$id": "https://designtokens.org/schemas/tokens/typography/value", + "anyOf": [ + { + "$ref": "https://designtokens.org/schemas/alias/value", + }, + { + "properties": { + "fontFamily": { + "$ref": "https://designtokens.org/schemas/tokens/fontFamily/value", + }, + "fontSize": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "fontWeight": { + "$ref": "https://designtokens.org/schemas/tokens/fontWeight/value", + }, + "letterSpacing": { + "$ref": "https://designtokens.org/schemas/tokens/dimension/value", + }, + "lineHeight": { + "$ref": "https://designtokens.org/schemas/tokens/number/value", + }, + }, + "required": [ + "fontFamily", + "fontSize", + "fontWeight", + "letterSpacing", + "lineHeight", + ], + "type": "object", + }, + ], + "description": "The typography of a property.", + "title": "Typography value", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/description", + "title": "Description", + "type": "string", + }, + { + "$id": "https://designtokens.org/schemas/treeNode/extensions", + "title": "Extensions", + "type": "object", + }, + ], + "$id": "https://designtokens.org/schemas/tokens/typography", + "additionalProperties": false, + "description": "The typography token.", + "properties": { + "$description": { + "$ref": "https://designtokens.org/schemas/treeNode/description", + }, + "$extensions": { + "$ref": "https://designtokens.org/schemas/treeNode/extensions", + }, + "$type": { + "pattern": "^typography$", + "type": "string", + }, + "$value": { + "$ref": "https://designtokens.org/schemas/tokens/typography/value", + }, + }, + "required": [ + "$value", + ], + "title": "Typography token", + "type": "object", + }, +] +`; diff --git a/tests/schemas/generateStandaloneSchema.spec.ts b/tests/schemas/generateStandaloneSchema.spec.ts new file mode 100644 index 0000000..f843ec3 --- /dev/null +++ b/tests/schemas/generateStandaloneSchema.spec.ts @@ -0,0 +1,14 @@ +import { describe, it, expect } from 'vitest'; + +import { allTokenJSONSchemas } from '../../src/schemas/tokens'; + +import { generateStandaloneSchema } from '../../src/schemas/generate'; + +describe('generateStandaloneSchema', () => { + it('Should generate standalone schemas for token types', () => { + const all = allTokenJSONSchemas.map((schema) => + generateStandaloneSchema(schema), + ); + expect(all).toMatchSnapshot(); + }); +}); diff --git a/tests/schemas/tokenTree.spec.ts b/tests/schemas/tokenTree.spec.ts new file mode 100644 index 0000000..d3993d7 --- /dev/null +++ b/tests/schemas/tokenTree.spec.ts @@ -0,0 +1,49 @@ +import { describe, it, expect } from 'vitest'; +import Ajv from 'ajv/dist/2020'; + +import { allJSONSchemas } from '../../src/schemas/all'; +import { withBaseURI } from '../../src/schemas/internals/withBaseURI'; + +describe('group schema', () => { + it('should execute', () => { + const ajv = new Ajv({ + schemas: allJSONSchemas, + }); + + const validate = ajv.getSchema(withBaseURI('/tokenTree')); + if (!validate) { + throw new Error('Schema not found'); + } + + const data = { + colors: { + $type: 'color', + // TODO: This should fail the test + anInvalidColor: { + $value: 'invalid', + }, + blue: { + $type: 'color', + $value: '#0000ff', + }, + }, + dimensions: { + small: { + $type: 'dimension', + $value: '4px', + }, + }, + fontFamilies: { + $type: 'fontFamily', + inter: { + $value: 'Inter', + }, + }, + }; + + const valid = validate(data); + if (!valid) console.log(validate.errors); + + expect(valid).toBe(true); + }); +}); diff --git a/tests/utils/traverseJSONValue.spec.ts b/tests/utils/traverseJSONValue.spec.ts new file mode 100644 index 0000000..07912bb --- /dev/null +++ b/tests/utils/traverseJSONValue.spec.ts @@ -0,0 +1,156 @@ +import { describe, it, expect, vi } from 'vitest'; + +import { traverseJSONValue } from '../../src/utils/traverseJSONValue.js'; + +describe('traverseJSONValue', () => { + it('should traverse a string', () => { + const callback = vi.fn(); + traverseJSONValue('hello', callback); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith('hello', []); + }); + it('should traverse a number', () => { + const callback = vi.fn(); + traverseJSONValue(12, callback); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith(12, []); + }); + it('should traverse a boolean', () => { + const callback = vi.fn(); + traverseJSONValue(true, callback); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith(true, []); + }); + it('should traverse an null', () => { + const callback = vi.fn(); + traverseJSONValue(null, callback); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith(null, []); + }); + it('should deeply traverse an array of primitives', () => { + const shouldDive = vi.fn(() => true); + const callback = shouldDive; + + traverseJSONValue([1, 'two', true, null], callback); + + expect(callback).toHaveBeenCalledTimes(5); + expect(callback).toHaveBeenCalledWith([1, 'two', true, null], []); + expect(callback).toHaveBeenCalledWith(1, [0]); + expect(callback).toHaveBeenCalledWith('two', [1]); + expect(callback).toHaveBeenCalledWith(true, [2]); + expect(callback).toHaveBeenCalledWith(null, [3]); + }); + it('should deeply traverse an array of arrays and objects', () => { + const shouldDive = vi.fn(() => true); + const callback = shouldDive; + + traverseJSONValue([1, 'two', true, null, [1, 2], { a: true, 100: true }], callback); + + expect(callback).toHaveBeenCalledTimes(11); + expect(callback).toHaveBeenCalledWith( + [1, 'two', true, null, [1, 2], { a: true, 100: true }], + [], + ); + expect(callback).toHaveBeenCalledWith(1, [0]); + expect(callback).toHaveBeenCalledWith('two', [1]); + expect(callback).toHaveBeenCalledWith(true, [2]); + expect(callback).toHaveBeenCalledWith(null, [3]); + expect(callback).toHaveBeenCalledWith([1, 2], [4]); + expect(callback).toHaveBeenCalledWith({ a: true, 100: true }, [5]); + expect(callback).toHaveBeenCalledWith(1, [4, 0]); + expect(callback).toHaveBeenCalledWith(2, [4, 1]); + expect(callback).toHaveBeenCalledWith(true, [5, 'a']); + expect(callback).toHaveBeenCalledWith(true, [5, '100']); + }); + + it('should deeply traverse an object of primitives if the callback returns void', () => { + const shouldDive = vi.fn(() => {}); + const callback = shouldDive; + + traverseJSONValue({ a: 1, b: 'two', c: true, 100: null }, callback); + + expect(callback).toHaveBeenCalledTimes(5); + expect(callback).toHaveBeenCalledWith({ a: 1, b: 'two', c: true, 100: null }, []); + expect(callback).toHaveBeenCalledWith(1, ['a']); + expect(callback).toHaveBeenCalledWith('two', ['b']); + expect(callback).toHaveBeenCalledWith(true, ['c']); + expect(callback).toHaveBeenCalledWith(null, ['100']); + }); + it('should deeply traverse an object of primitives if the callback returns true', () => { + const shouldDive = vi.fn(() => true); + const callback = shouldDive; + + traverseJSONValue({ a: 1, b: 'two', c: true, d: null }, callback); + + expect(callback).toHaveBeenCalledTimes(5); + expect(callback).toHaveBeenCalledWith({ a: 1, b: 'two', c: true, d: null }, []); + expect(callback).toHaveBeenCalledWith(1, ['a']); + expect(callback).toHaveBeenCalledWith('two', ['b']); + expect(callback).toHaveBeenCalledWith(true, ['c']); + expect(callback).toHaveBeenCalledWith(null, ['d']); + }); + it('should shallow traverse an object of primitives if the callback returns false', () => { + const shouldDiveAtOneLevelOfDepth = vi.fn((value, path) => { + const depth = path.length; + return depth < 1; + }); + const callback = shouldDiveAtOneLevelOfDepth; + + traverseJSONValue({ a: { nested: { object: 'value' } } }, callback); + + expect(callback).toHaveBeenCalledTimes(2); + expect(callback).toHaveBeenCalledWith({ a: { nested: { object: 'value' } } }, []); + expect(callback).toHaveBeenCalledWith({ nested: { object: 'value' } }, ['a']); + }); + it('should traverse an object based on the callback return value', () => { + const given = { + a: { + isValid: true, + value: { + a1: { + isValid: true, + }, + a2: { + isValid: false, + }, + }, + }, + b: { + isValid: false, + value: { + b1: { + isValid: true, + }, + }, + }, + }; + + const spied = vi.fn((value, path) => { + if (path.length === 0) return true; + if (typeof value === 'object' && value !== null && 'isValid' in value) { + return value.isValid as boolean; + } + return false; + }); + + traverseJSONValue(given, spied); + + expect(spied).toHaveBeenCalledTimes(5); + expect(spied).toHaveBeenCalledWith(given, []); + expect(spied).toHaveBeenCalledWith(given.a, ['a']); + expect(spied).toHaveBeenCalledWith(given.a.isValid, ['a', 'isValid']); + expect(spied).toHaveBeenCalledWith(given.a.value, ['a', 'value']); + expect(spied).toHaveBeenCalledWith(given.b, ['b']); + }); + + it('should fail trying to traverse an undefined', () => { + const callback = vi.fn(); + expect(() => + traverseJSONValue( + // @ts-expect-error + undefined, + callback, + ), + ).toThrow('JSONValue is undefined'); + }); +});