|
|
|
|
@ -1,14 +1,17 @@
|
|
|
|
|
import {
|
|
|
|
|
ASPECT_RATIO_KEYS,
|
|
|
|
|
BORDER_COLOR_KEYS,
|
|
|
|
|
BORDER_STYLE_KEYS,
|
|
|
|
|
BORDER_WIDTH_KEYS,
|
|
|
|
|
COLOR_ROLES,
|
|
|
|
|
COLOR_SCALE_STEPS,
|
|
|
|
|
CONTAINER_WIDTH_KEYS,
|
|
|
|
|
CONTENT_COLOR_KEYS,
|
|
|
|
|
CONTENT_WIDTH_KEYS,
|
|
|
|
|
DENSITY_KEYS,
|
|
|
|
|
DURATION_KEYS,
|
|
|
|
|
EASE_KEYS,
|
|
|
|
|
FOCUS_COLOR_KEYS,
|
|
|
|
|
ICON_STROKE_WIDTH_KEYS,
|
|
|
|
|
MOTION_DISTANCE_KEYS,
|
|
|
|
|
MOTION_SCALE_KEYS,
|
|
|
|
|
@ -16,9 +19,11 @@ import {
|
|
|
|
|
RADIUS_KEYS,
|
|
|
|
|
SHADOW_KEYS,
|
|
|
|
|
SIZE_PRIMITIVE_KEYS,
|
|
|
|
|
SURFACE_COLOR_KEYS,
|
|
|
|
|
TEXT_SIZES,
|
|
|
|
|
Z_INDEX_KEYS,
|
|
|
|
|
type BorderPrimitiveSet,
|
|
|
|
|
type ColorSemanticSet,
|
|
|
|
|
type ColorRole,
|
|
|
|
|
type ColorRoleDefinition,
|
|
|
|
|
type ColorScale,
|
|
|
|
|
@ -48,11 +53,14 @@ const COLOR_ROLE_SET = new Set<string>(COLOR_ROLES)
|
|
|
|
|
const ASPECT_RATIO_KEY_SET = new Set<string>(ASPECT_RATIO_KEYS)
|
|
|
|
|
const BORDER_WIDTH_KEY_SET = new Set<string>(BORDER_WIDTH_KEYS)
|
|
|
|
|
const BORDER_STYLE_KEY_SET = new Set<string>(BORDER_STYLE_KEYS)
|
|
|
|
|
const BORDER_COLOR_KEY_SET = new Set<string>(BORDER_COLOR_KEYS)
|
|
|
|
|
const CONTENT_COLOR_KEY_SET = new Set<string>(CONTENT_COLOR_KEYS)
|
|
|
|
|
const CONTAINER_WIDTH_KEY_SET = new Set<string>(CONTAINER_WIDTH_KEYS)
|
|
|
|
|
const CONTENT_WIDTH_KEY_SET = new Set<string>(CONTENT_WIDTH_KEYS)
|
|
|
|
|
const DENSITY_KEY_SET = new Set<string>(DENSITY_KEYS)
|
|
|
|
|
const DURATION_KEY_SET = new Set<string>(DURATION_KEYS)
|
|
|
|
|
const EASE_KEY_SET = new Set<string>(EASE_KEYS)
|
|
|
|
|
const FOCUS_COLOR_KEY_SET = new Set<string>(FOCUS_COLOR_KEYS)
|
|
|
|
|
const ICON_STROKE_WIDTH_KEY_SET = new Set<string>(ICON_STROKE_WIDTH_KEYS)
|
|
|
|
|
const MOTION_DISTANCE_KEY_SET = new Set<string>(MOTION_DISTANCE_KEYS)
|
|
|
|
|
const MOTION_SCALE_KEY_SET = new Set<string>(MOTION_SCALE_KEYS)
|
|
|
|
|
@ -60,6 +68,7 @@ const OPACITY_KEY_SET = new Set<string>(OPACITY_KEYS)
|
|
|
|
|
const RADIUS_KEY_SET = new Set<string>(RADIUS_KEYS)
|
|
|
|
|
const SHADOW_KEY_SET = new Set<string>(SHADOW_KEYS)
|
|
|
|
|
const SIZE_PRIMITIVE_KEY_SET = new Set<string>(SIZE_PRIMITIVE_KEYS)
|
|
|
|
|
const SURFACE_COLOR_KEY_SET = new Set<string>(SURFACE_COLOR_KEYS)
|
|
|
|
|
const TEXT_SIZE_SET = new Set<string>(TEXT_SIZES)
|
|
|
|
|
const Z_INDEX_KEY_SET = new Set<string>(Z_INDEX_KEYS)
|
|
|
|
|
const RESPONSIVE_KEY_SET = new Set(['base', 'sm', 'md', 'lg', 'xl', 'xxl'])
|
|
|
|
|
@ -103,6 +112,7 @@ export function validateEidosConfig(options: EidosConfig): EidosValidationReport
|
|
|
|
|
validateThemeKeys(options, issues)
|
|
|
|
|
validateColorScales(options, issues)
|
|
|
|
|
validateColorRoles(options, issues)
|
|
|
|
|
validateColorSemanticGroups(options, issues)
|
|
|
|
|
validateTypography(options, issues)
|
|
|
|
|
validateSizePrimitives(options, issues)
|
|
|
|
|
validateStaticPrimitives(options, issues)
|
|
|
|
|
@ -323,6 +333,95 @@ function validateColorRoles(options: EidosConfig, issues: EidosValidationIssue[]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validateColorSemanticGroups(options: EidosConfig, issues: EidosValidationIssue[]): void {
|
|
|
|
|
validateColorSemanticSet('semantics.color', options.semantics.color, issues)
|
|
|
|
|
|
|
|
|
|
for (const [themeId, theme] of Object.entries(options.themes ?? {})) {
|
|
|
|
|
if (!theme.color) continue
|
|
|
|
|
validateColorSemanticSet(`themes.${themeId}.color`, theme.color, issues)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validateColorSemanticSet(
|
|
|
|
|
path: string,
|
|
|
|
|
color: Partial<
|
|
|
|
|
Pick<ColorSemanticSet, 'surface' | 'content' | 'border' | 'focus'>
|
|
|
|
|
>,
|
|
|
|
|
issues: EidosValidationIssue[]
|
|
|
|
|
): void {
|
|
|
|
|
validateColorSemanticGroup(
|
|
|
|
|
`${path}.surface`,
|
|
|
|
|
color.surface,
|
|
|
|
|
SURFACE_COLOR_KEYS,
|
|
|
|
|
SURFACE_COLOR_KEY_SET,
|
|
|
|
|
issues
|
|
|
|
|
)
|
|
|
|
|
validateColorSemanticGroup(
|
|
|
|
|
`${path}.content`,
|
|
|
|
|
color.content,
|
|
|
|
|
CONTENT_COLOR_KEYS,
|
|
|
|
|
CONTENT_COLOR_KEY_SET,
|
|
|
|
|
issues
|
|
|
|
|
)
|
|
|
|
|
validateColorSemanticGroup(
|
|
|
|
|
`${path}.border`,
|
|
|
|
|
color.border,
|
|
|
|
|
BORDER_COLOR_KEYS,
|
|
|
|
|
BORDER_COLOR_KEY_SET,
|
|
|
|
|
issues
|
|
|
|
|
)
|
|
|
|
|
validateColorSemanticGroup(
|
|
|
|
|
`${path}.focus`,
|
|
|
|
|
color.focus,
|
|
|
|
|
FOCUS_COLOR_KEYS,
|
|
|
|
|
FOCUS_COLOR_KEY_SET,
|
|
|
|
|
issues
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validateColorSemanticGroup(
|
|
|
|
|
path: string,
|
|
|
|
|
group: unknown,
|
|
|
|
|
keys: readonly string[],
|
|
|
|
|
keySet: Set<string>,
|
|
|
|
|
issues: EidosValidationIssue[]
|
|
|
|
|
): void {
|
|
|
|
|
if (group === undefined) return
|
|
|
|
|
if (!isPlainRecord(group)) {
|
|
|
|
|
issues.push({
|
|
|
|
|
path,
|
|
|
|
|
message: 'color semantic group must be a plain object'
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const key of keys) {
|
|
|
|
|
if (!hasOwn(group, key)) {
|
|
|
|
|
issues.push({
|
|
|
|
|
path: `${path}.${key}`,
|
|
|
|
|
message: 'color semantic groups must define every canonical key'
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const value = group[key]
|
|
|
|
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
|
|
|
issues.push({
|
|
|
|
|
path: `${path}.${key}`,
|
|
|
|
|
message: 'color semantic CSS value cannot be empty'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const key of Object.keys(group)) {
|
|
|
|
|
if (keySet.has(key)) continue
|
|
|
|
|
issues.push({
|
|
|
|
|
path: `${path}.${key}`,
|
|
|
|
|
message: 'unknown color semantic key'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validateColorScale(
|
|
|
|
|
path: string,
|
|
|
|
|
name: string,
|
|
|
|
|
|