UNPKG

@intlayer/chokidar

Version:

Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.

1 lines 6.35 kB
{"version":3,"file":"filterInvalidDictionaries.cjs","names":["formatPath","ANSIColors","formatLocale","x"],"sources":["../../src/filterInvalidDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n colorizeKey,\n colorizePath,\n getAppLogger,\n x,\n} from '@intlayer/config/logger';\nimport { getBasePlugins, getContent } from '@intlayer/core/interpreter';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { formatLocale, formatPath } from './utils/formatter';\n\ntype IsInvalidDictionaryOptions = { checkSchema: boolean };\n\nexport const isInvalidDictionary = (\n dictionary: Dictionary | undefined,\n configuration?: IntlayerConfig,\n options?: IsInvalidDictionaryOptions\n): boolean => {\n const appLogger = getAppLogger(configuration);\n\n if (!dictionary) return false;\n\n const isLocal = Boolean(\n dictionary.location === 'local' || typeof dictionary.filePath === 'string'\n );\n const location = isLocal ? 'Local' : 'Remote';\n const hasKey = Boolean(dictionary.key);\n const hasContent = Boolean(dictionary.content);\n\n if (!hasKey) {\n appLogger(`${location} dictionary has no key`, {\n level: 'error',\n });\n\n return false;\n }\n\n // Reject keys that contain path-unsafe characters.\n // A key is used as a filename component ({key}.json), so slashes, backslashes,\n // null bytes, or pure dot-segments can escape the output directory or break\n // dictionary resolution.\n // Allows alphanumeric characters, dashes, and underscores.\n // Allows dots, but not as the first or last character, and no consecutive dots.\n // Allows chinese or russian characters e.g. 你好\n const isInsecureKey = !/^[\\p{L}\\p{N}]+([._-][\\p{L}\\p{N}]+)*$/u.test(\n dictionary.key\n );\n\n if (isInsecureKey) {\n appLogger(\n `Insecure key ${colorizeKey(dictionary.key)} at ${dictionary.filePath ? formatPath(dictionary.filePath) : colorizePath('Remote')} - dictionary filtered out`,\n { level: 'error' }\n );\n return false;\n }\n\n if (!hasContent) {\n appLogger(\n `${location} dictionary ${colorizeKey(dictionary.key)} has no content - ${dictionary.filePath ? formatPath(dictionary.filePath) : colorizePath('Remote')}`,\n {\n level: 'error',\n }\n );\n return false;\n }\n\n if (dictionary.schema && options?.checkSchema) {\n const isAsync =\n typeof dictionary.content === 'function' ||\n (typeof dictionary.content === 'object' &&\n dictionary.content !== null &&\n typeof (dictionary.content as any).then === 'function');\n\n if (!isAsync) {\n const locales = configuration?.internationalization?.locales ?? [];\n const isStrict =\n configuration?.internationalization.strictMode === 'strict';\n\n const schema =\n typeof dictionary.schema === 'string'\n ? configuration?.schemas?.[dictionary.schema]\n : undefined;\n\n if (schema && typeof schema.safeParse === 'function') {\n for (const locale of locales) {\n const resolvedContent = getContent(\n dictionary.content,\n {\n dictionaryKey: dictionary.key,\n keyPath: [],\n locale,\n },\n getBasePlugins(locale, !isStrict)\n );\n const result = (schema as any).safeParse(resolvedContent);\n\n if (!result.success) {\n appLogger(\n `${location} dictionary ${colorizeKey(dictionary.key)} has invalid content according to schema ${colorize(dictionary.schema as string, ANSIColors.ORANGE)} for locale ${formatLocale(locale)} - ${dictionary.filePath ? formatPath(dictionary.filePath) : colorizePath('Remote')}`,\n {\n level: 'error',\n }\n );\n\n result.error.issues.forEach((issue: any) => {\n appLogger(\n `${x} Error: ${colorizeKey(dictionary.key)} - ${formatLocale(locale)} - ${colorize(`${issue.path.join('.')}:`, ANSIColors.BLUE)} ${colorize(issue.message, ANSIColors.GREY)}`,\n {\n level: 'error',\n }\n );\n });\n\n return false;\n }\n }\n }\n }\n }\n\n return true;\n};\n\nexport const filterInvalidDictionaries = (\n dictionaries: (Dictionary | undefined)[] | undefined,\n configuration: IntlayerConfig,\n options?: IsInvalidDictionaryOptions\n): Dictionary[] =>\n (dictionaries ?? [])?.filter((dictionary) =>\n isInvalidDictionary(dictionary, configuration, options)\n ) as Dictionary[];\n"],"mappings":";;;;;;;;;AAeA,MAAa,uBACX,YACA,eACA,YACY;CACZ,MAAM,sDAAyB,aAAa;CAE5C,IAAI,CAAC,YAAY,OAAO;CAKxB,MAAM,WAHU,QACd,WAAW,aAAa,WAAW,OAAO,WAAW,aAAa,QAE7C,IAAI,UAAU;CACrC,MAAM,SAAS,QAAQ,WAAW,GAAG;CACrC,MAAM,aAAa,QAAQ,WAAW,OAAO;CAE7C,IAAI,CAAC,QAAQ;EACX,UAAU,GAAG,SAAS,yBAAyB,EAC7C,OAAO,QACT,CAAC;EAED,OAAO;CACT;CAaA,IAAI,CAJmB,wCAAwC,KAC7D,WAAW,GACb,GAEmB;EACjB,UACE,yDAA4B,WAAW,GAAG,EAAE,MAAM,WAAW,WAAWA,mCAAW,WAAW,QAAQ,8CAAiB,QAAQ,EAAE,6BACjI,EAAE,OAAO,QAAQ,CACnB;EACA,OAAO;CACT;CAEA,IAAI,CAAC,YAAY;EACf,UACE,GAAG,SAAS,uDAA0B,WAAW,GAAG,EAAE,oBAAoB,WAAW,WAAWA,mCAAW,WAAW,QAAQ,8CAAiB,QAAQ,KACvJ,EACE,OAAO,QACT,CACF;EACA,OAAO;CACT;CAEA,IAAI,WAAW,UAAU,SAAS,aAOhC;MAAI,EALF,OAAO,WAAW,YAAY,cAC7B,OAAO,WAAW,YAAY,YAC7B,WAAW,YAAY,QACvB,OAAQ,WAAW,QAAgB,SAAS,aAElC;GACZ,MAAM,UAAU,eAAe,sBAAsB,WAAW,CAAC;GACjE,MAAM,WACJ,eAAe,qBAAqB,eAAe;GAErD,MAAM,SACJ,OAAO,WAAW,WAAW,WACzB,eAAe,UAAU,WAAW,UACpC;GAEN,IAAI,UAAU,OAAO,OAAO,cAAc,YACxC,KAAK,MAAM,UAAU,SAAS;IAC5B,MAAM,6DACJ,WAAW,SACX;KACE,eAAe,WAAW;KAC1B,SAAS,CAAC;KACV;IACF,kDACe,QAAQ,CAAC,QAAQ,CAClC;IACA,MAAM,SAAU,OAAe,UAAU,eAAe;IAExD,IAAI,CAAC,OAAO,SAAS;KACnB,UACE,GAAG,SAAS,uDAA0B,WAAW,GAAG,EAAE,iFAAoD,WAAW,QAAkBC,wBAAW,MAAM,EAAE,cAAcC,qCAAa,MAAM,EAAE,KAAK,WAAW,WAAWF,mCAAW,WAAW,QAAQ,8CAAiB,QAAQ,KAC/Q,EACE,OAAO,QACT,CACF;KAEA,OAAO,MAAM,OAAO,SAAS,UAAe;MAC1C,UACE,GAAGG,0BAAE,mDAAsB,WAAW,GAAG,EAAE,KAAKD,qCAAa,MAAM,EAAE,2CAAc,GAAG,MAAM,KAAK,KAAK,GAAG,EAAE,IAAID,wBAAW,IAAI,EAAE,yCAAY,MAAM,SAASA,wBAAW,IAAI,KAC1K,EACE,OAAO,QACT,CACF;KACF,CAAC;KAED,OAAO;IACT;GACF;EAEJ;;CAGF,OAAO;AACT;AAEA,MAAa,6BACX,cACA,eACA,aAEC,gBAAgB,CAAC,IAAI,QAAQ,eAC5B,oBAAoB,YAAY,eAAe,OAAO,CACxD"}