generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy paththeme-json-schema.ts
More file actions
125 lines (116 loc) · 4.25 KB
/
theme-json-schema.ts
File metadata and controls
125 lines (116 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { validate } from 'jsonschema';
import { Theme } from '../../shared/theme';
import { ThemeJson } from './theme-json';
interface ThemeJsonSchema extends GenericSchema {
$schema: string;
}
interface GenericSchema {
type: string;
pattern?: string;
patternProperties?: Record<string, GenericSchema>;
properties?: Record<string, GenericSchema>;
additionalProperties?: boolean;
required?: Array<string>;
}
const stringValueSchema: GenericSchema = { type: 'string' };
const colorValueSchema: GenericSchema = {
type: 'string',
pattern: '#[0-9a-f]{6}|rgba\\(\\d{1,3}%?(,\\s?\\d{1,3}%?){2},\\s?(1|0|0?\\.\\d+)\\)|transparent',
};
const spaceValueSchema: GenericSchema = {
type: 'string',
pattern: '^\\d+(\\.\\d+)?(px|rem|%)$',
};
const borderWidthValueSchema: GenericSchema = {
type: 'string',
pattern: '^\\d+(\\.\\d+)?(px|rem|em)$',
};
const textSizeValueSchema: GenericSchema = {
type: 'string',
pattern: '^\\d+(\\.\\d+)?(px|rem|em)$',
};
const textWeightValueSchema: GenericSchema = {
type: 'string',
pattern: '300|400|700|900|normal|bold|light|heavy',
};
const letterSpacingValueSchema: GenericSchema = {
type: 'string',
pattern: '^(normal|inherit|initial|revert|revert-layer|unset|-?\\d*\\.?\\d+(px|rem|em))$',
};
const durationValueSchema: GenericSchema = { type: 'string', pattern: '\\d+m?s' };
const visualModes = ['light', 'dark'];
const densityModes = ['comfortable', 'compact'];
const motionModes = ['default', 'disabled'];
const getComplexValueSchema = (valueSchema: GenericSchema, propertiesNames: Array<string>): GenericSchema => ({
type: 'object',
properties: propertiesNames.reduce((acc: Record<string, GenericSchema>, current: string) => {
acc[current] = valueSchema;
return acc;
}, {}),
required: propertiesNames,
additionalProperties: false,
});
const getTokenSchema = (valueSchema: GenericSchema): GenericSchema => ({
type: 'object',
properties: {
$value: valueSchema,
$description: { type: 'string' },
},
required: ['$value'],
additionalProperties: false,
});
const tokensSchema: GenericSchema = {
type: 'object',
patternProperties: {
'^color-': getTokenSchema(getComplexValueSchema(colorValueSchema, visualModes)),
'^font-family-': getTokenSchema(stringValueSchema),
'^border-radius-': getTokenSchema(spaceValueSchema),
'^border-width-': getTokenSchema(borderWidthValueSchema),
'^space-': getTokenSchema(getComplexValueSchema(spaceValueSchema, densityModes)),
'^motion-duration-': getTokenSchema(getComplexValueSchema(durationValueSchema, motionModes)),
'^motion-easing-': getTokenSchema(getComplexValueSchema(stringValueSchema, motionModes)),
'^motion-keyframes-': getTokenSchema(getComplexValueSchema(stringValueSchema, motionModes)),
'^shadow-': getTokenSchema(getComplexValueSchema(stringValueSchema, visualModes)),
'^font-size-': getTokenSchema(textSizeValueSchema),
'^line-height-': getTokenSchema(textSizeValueSchema),
'^font-weight-': getTokenSchema(textWeightValueSchema),
'^letter-spacing-': getTokenSchema(letterSpacingValueSchema),
},
additionalProperties: false,
};
export function getThemeJSONSchema(theme: Theme): ThemeJsonSchema {
const contextsNames = Object.keys(theme.contexts || {});
return {
$schema: 'https://json-schema.org/draft/2020-12/schema',
type: 'object',
properties: {
tokens: tokensSchema,
contexts: {
type: 'object',
properties: contextsNames.reduce((acc: Record<string, GenericSchema>, current) => {
acc[current] = {
type: 'object',
properties: { tokens: tokensSchema },
required: ['tokens'],
additionalProperties: false,
};
return acc;
}, {}),
required: contextsNames,
additionalProperties: false,
},
},
required: ['tokens', 'contexts'],
additionalProperties: false,
};
}
export function validateJson(themeJson: ThemeJson, themeJsonSchema: ThemeJsonSchema): boolean {
const validationResult = validate(themeJson, themeJsonSchema);
if (validationResult.valid) {
return true;
} else {
throw new Error(`Tokens validation error: ${validationResult.errors[0].stack}`);
}
}