[READ-ONLY] a fast, modern browser for the npm registry
at main 77 lines 2.5 kB view raw
1/* oxlint-disable no-console */ 2import { readFile, writeFile } from 'node:fs/promises' 3import { join } from 'node:path' 4import { fileURLToPath } from 'node:url' 5import { colors } from './utils/colors.ts' 6 7const I18N_DIRECTORY = fileURLToPath(new URL('../i18n', import.meta.url)) 8const LOCALES_DIRECTORY = join(I18N_DIRECTORY, 'locales') 9const REFERENCE_FILE_NAME = 'en.json' 10const SCHEMA_FILE_NAME = 'schema.json' 11 12type Json = Record<string, unknown> 13type LocaleJson = Json & { $schema: string } 14 15interface JsonSchema { 16 $schema?: string 17 title?: string 18 description?: string 19 type: string 20 properties?: Record<string, JsonSchema> 21 additionalProperties?: boolean 22} 23 24const generateSubSchema = (obj: Json): JsonSchema => { 25 const properties: Record<string, JsonSchema> = {} 26 27 for (const [key, value] of Object.entries(obj)) { 28 if (value !== null && typeof value === 'object' && !Array.isArray(value)) { 29 properties[key] = generateSubSchema(value as Json) 30 } else { 31 properties[key] = { type: 'string' } 32 } 33 } 34 35 return { 36 type: 'object', 37 properties, 38 additionalProperties: false, 39 } 40} 41 42const generateSchema = (obj: LocaleJson): JsonSchema => { 43 const { $schema: _, ...rest } = obj // Exclude $schema from schema generation 44 const baseSchema = generateSubSchema(rest) 45 return { 46 $schema: 'http://json-schema.org/draft-07/schema#', 47 title: 'npmx i18n locale file', 48 description: 49 'Schema for npmx i18n translation files. Generated from en.json — do not edit manually.', 50 ...baseSchema, 51 // Allow $schema property at root level 52 properties: { 53 ...baseSchema.properties, 54 $schema: { type: 'string' }, 55 }, 56 } 57} 58 59/* 60 * Generates a JSON Schema from the reference locale file (en.json) and writes it to 61 * i18n/schema.json. All locale files include a $schema property that points to this file. 62 * 63 * This allows IDEs to provide validation, autocompletion, and other hints in translation files. 64 */ 65const main = async (): Promise<void> => { 66 const referenceFilePath = join(LOCALES_DIRECTORY, REFERENCE_FILE_NAME) 67 const referenceContent = JSON.parse(await readFile(referenceFilePath, 'utf-8')) as LocaleJson 68 69 const schema = generateSchema(referenceContent) 70 71 const schemaFilePath = join(I18N_DIRECTORY, SCHEMA_FILE_NAME) 72 await writeFile(schemaFilePath, JSON.stringify(schema, null, 2) + '\n', 'utf-8') 73 74 console.log(colors.green(`✅ Generated schema at ${schemaFilePath}`)) 75} 76 77await main()