From 0f8136705e2f05d578fd7caf8e359aa997784957 Mon Sep 17 00:00:00 2001 From: fullex <0xfullex@gmail.com> Date: Wed, 26 Nov 2025 12:50:38 +0800 Subject: [PATCH] feat: add ESLint rule for schema key naming convention in cache and preference schemas - Introduced a new ESLint rule to enforce a specific naming convention for schema keys: `namespace.sub.key_name`. - Updated cache and preference schema files to include documentation on the naming convention and examples of valid/invalid keys. - Modified existing keys in cache schemas to comply with the new convention. --- eslint.config.mjs | 56 +++++++++++++++++++ packages/shared/data/cache/cacheSchemas.ts | 30 ++++++++-- .../data/preference/preferenceSchemas.ts | 17 ++++++ 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index e72484a1d9..3655fbe7cc 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -157,4 +157,60 @@ export default defineConfig([ // ] } }, + // Schema key naming convention (cache & preferences) + { + files: ['packages/shared/data/cache/cacheSchemas.ts', 'packages/shared/data/preference/preferenceSchemas.ts'], + plugins: { + 'data-schema-key': { + rules: { + 'valid-key': { + meta: { + type: 'problem', + docs: { + description: 'Enforce schema key naming convention: namespace.sub.key_name', + recommended: true + }, + messages: { + invalidKey: + 'Schema key "{{key}}" must follow format: namespace.sub.key_name (e.g., app.user.avatar).' + } + }, + create(context) { + const VALID_KEY_PATTERN = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/ + + return { + TSPropertySignature(node) { + if (node.key.type === 'Literal' && typeof node.key.value === 'string') { + const key = node.key.value + if (!VALID_KEY_PATTERN.test(key)) { + context.report({ + node: node.key, + messageId: 'invalidKey', + data: { key } + }) + } + } + }, + Property(node) { + if (node.key.type === 'Literal' && typeof node.key.value === 'string') { + const key = node.key.value + if (!VALID_KEY_PATTERN.test(key)) { + context.report({ + node: node.key, + messageId: 'invalidKey', + data: { key } + }) + } + } + } + } + } + } + } + } + }, + rules: { + 'data-schema-key/valid-key': 'error' + } + } ]) diff --git a/packages/shared/data/cache/cacheSchemas.ts b/packages/shared/data/cache/cacheSchemas.ts index f75fd4f4f3..c77f890f8e 100644 --- a/packages/shared/data/cache/cacheSchemas.ts +++ b/packages/shared/data/cache/cacheSchemas.ts @@ -1,5 +1,27 @@ import type * as CacheValueTypes from './cacheValueTypes' +/** + * Cache Schema Definitions + * + * ## Key Naming Convention + * + * All cache keys MUST follow the format: `namespace.sub.key_name` + * + * Rules: + * - At least 2 segments separated by dots (.) + * - Each segment uses lowercase letters, numbers, and underscores only + * - Pattern: /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/ + * + * Examples: + * - 'app.user.avatar' (valid) + * - 'chat.multi_select_mode' (valid) + * - 'minapp.opened_keep_alive' (valid) + * - 'userAvatar' (invalid - missing dot separator) + * - 'App.user' (invalid - uppercase not allowed) + * + * This convention is enforced by ESLint rule: data-schema-key/valid-key + */ + /** * Use cache schema for renderer hook */ @@ -63,11 +85,11 @@ export const DefaultUseCache: UseCacheSchema = { * Use shared cache schema for renderer hook */ export type UseSharedCacheSchema = { - 'example-key': string + 'example_scope.example_key': string } export const DefaultUseSharedCache: UseSharedCacheSchema = { - 'example-key': 'example default value' + 'example_scope.example_key': 'example default value' } /** @@ -75,11 +97,11 @@ export const DefaultUseSharedCache: UseSharedCacheSchema = { * This ensures type safety and prevents key conflicts */ export type RendererPersistCacheSchema = { - 'example-key': string + 'example_scope.example_key': string } export const DefaultRendererPersistCache: RendererPersistCacheSchema = { - 'example-key': 'example default value' + 'example_scope.example_key': 'example default value' } /** diff --git a/packages/shared/data/preference/preferenceSchemas.ts b/packages/shared/data/preference/preferenceSchemas.ts index 6b758c0ff5..9438c4c1e1 100644 --- a/packages/shared/data/preference/preferenceSchemas.ts +++ b/packages/shared/data/preference/preferenceSchemas.ts @@ -6,6 +6,23 @@ * To update this file, modify classification.json and run: * node .claude/data-classify/scripts/generate-preferences.js * + * ## Key Naming Convention + * + * All preference keys MUST follow the format: `namespace.sub.key_name` + * + * Rules: + * - At least 2 segments separated by dots (.) + * - Each segment uses lowercase letters, numbers, and underscores only + * - Pattern: /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/ + * + * Examples: + * - 'app.user.avatar' (valid) + * - 'chat.multi_select_mode' (valid) + * - 'userAvatar' (invalid - missing dot separator) + * - 'App.user' (invalid - uppercase not allowed) + * + * This convention is enforced by ESLint rule: data-schema-key/valid-key + * * === AUTO-GENERATED CONTENT START === */