npm package diff

Package: @forge/manifest

Versions: 7.6.1-next.0 - 7.6.1-next.1

File: package/out/validators/translations-validator.js

Index: package/out/validators/translations-validator.js
===================================================================
--- package/out/validators/translations-validator.js
+++ package/out/validators/translations-validator.js
@@ -0,0 +1,160 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.TranslationsValidator = void 0;
+const tslib_1 = require("tslib");
+const fs_1 = tslib_1.__importDefault(require("fs"));
+const path_1 = require("path");
+const text_1 = require("../text");
+const text_2 = require("../text");
+const utils_1 = require("../utils");
+class TranslationsValidator {
+    ensureValidResourcesDefinition(validationErrors, manifest) {
+        const { resources, fallback } = manifest.yamlContent.translations;
+        const resourcesMap = new Map();
+        resources.forEach(({ key, path }) => {
+            if (resourcesMap.has(key)) {
+                validationErrors.push({
+                    message: text_1.errors.translations.duplicateResourceKey(key),
+                    reference: text_2.References.SchemaError,
+                    level: 'error',
+                    ...(0, utils_1.findPosition)(`key: ${key}`, manifest.yamlContentByLine)
+                });
+            }
+            else {
+                resourcesMap.set(key, path);
+            }
+        });
+        let defaultLanguageLookup = {};
+        resourcesMap.forEach((path, key) => {
+            const resourcePath = (0, path_1.resolve)(path);
+            try {
+                if (fs_1.default.lstatSync(resourcePath).isFile()) {
+                    const data = JSON.parse(fs_1.default.readFileSync((0, path_1.resolve)(path), 'utf8'));
+                    if (fallback?.default === key) {
+                        defaultLanguageLookup = data;
+                    }
+                }
+            }
+            catch (e) {
+                validationErrors.push({
+                    message: text_1.errors.translations.invalidLanguageFile(key, path),
+                    reference: text_2.References.SchemaError,
+                    level: 'error',
+                    ...(0, utils_1.findPosition)(`path: ${path}`, manifest?.yamlContentByLine)
+                });
+            }
+        });
+        return defaultLanguageLookup;
+    }
+    ensureValidFallbackDefinition(validationErrors, manifest) {
+        const { resources, fallback } = manifest.yamlContent.translations;
+        const defaultLanguage = fallback.default;
+        const resourcesSet = new Set(resources.map((resource) => resource.key));
+        const fallbackLanguages = Object.keys(fallback).filter((fallbackLanguage) => fallbackLanguage !== 'default');
+        const allFallbackLanguagesSet = new Set([defaultLanguage, ...fallbackLanguages]);
+        allFallbackLanguagesSet.forEach((fallbackLanguage) => {
+            if (!resourcesSet.has(fallbackLanguage)) {
+                validationErrors.push({
+                    message: text_1.errors.translations.missingTranslationsJsonFile(fallbackLanguage),
+                    reference: text_2.References.SchemaError,
+                    level: 'error',
+                    ...(0, utils_1.findPosition)(fallbackLanguage === defaultLanguage ? `default: ${fallbackLanguage}` : `${fallbackLanguage}:`, manifest.yamlContentByLine)
+                });
+            }
+        });
+        const allLanguagesList = [
+            defaultLanguage,
+            ...fallbackLanguages,
+            ...fallbackLanguages.flatMap((language) => fallback[language])
+        ];
+        const [, duplicates] = allLanguagesList.reduce(([languageSet, duplicates], language) => {
+            languageSet.has(language) ? duplicates.add(language) : languageSet.add(language);
+            return [languageSet, duplicates];
+        }, [new Set(), new Set()]);
+        duplicates.forEach((duplicate) => {
+            validationErrors.push({
+                message: text_1.errors.translations.duplicateFallbackConfig(duplicate),
+                reference: text_2.References.SchemaError,
+                level: 'error',
+                ...(0, utils_1.findPosition)(duplicate, manifest.yamlContentByLine)
+            });
+        });
+    }
+    ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, defaultLanguageLookup, manifest) {
+        const i18nKeysSet = new Set(i18nKeys);
+        const defaultLocalCode = manifest.yamlContent.translations.fallback.default;
+        const languageLookUp = { [defaultLocalCode]: defaultLanguageLookup };
+        i18nKeysSet.forEach((key) => {
+            const i18nValue = (0, utils_1.getTranslationValue)(languageLookUp, key, defaultLocalCode);
+            if (!i18nValue) {
+                validationErrors.push({
+                    message: text_1.errors.translations.i18nKeyNotFound(key),
+                    reference: text_2.References.SchemaError,
+                    level: 'error',
+                    ...(0, utils_1.findPosition)(`i18n: ${key}`, manifest.yamlContentByLine)
+                });
+            }
+        });
+    }
+    validateManifestWithoutI18nConfig(manifest, i18nKeys) {
+        if (i18nKeys.length === 0) {
+            return {
+                success: true,
+                manifestObject: manifest
+            };
+        }
+        const missingTranslationsPropertyError = [
+            {
+                message: text_1.errors.translations.missingTranslationsPropertyError,
+                reference: text_2.References.SchemaError,
+                level: 'error',
+                ...(0, utils_1.findPosition)('i18n', manifest?.yamlContentByLine)
+            }
+        ];
+        return {
+            success: false,
+            manifestObject: manifest,
+            errors: missingTranslationsPropertyError
+        };
+    }
+    validateManifestI18nConfig(manifest, i18nKeys) {
+        const validationErrors = [];
+        const defaultLanguageLookup = this.ensureValidResourcesDefinition(validationErrors, manifest);
+        this.ensureValidFallbackDefinition(validationErrors, manifest);
+        this.ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, defaultLanguageLookup, manifest);
+        return validationErrors;
+    }
+    validateInternalI18nPropertyKeysNotInModules(manifest) {
+        const modules = manifest?.typedContent?.modules ?? {};
+        const internalI18nPropertyKeys = (0, utils_1.extractInternalI18nPropertyKeysFromModules)(modules);
+        return internalI18nPropertyKeys.map(([propertyKey, moduleKey]) => ({
+            message: text_1.errors.translations.internalI18nPropertyKeyFound(propertyKey, moduleKey),
+            reference: text_2.References.SchemaError,
+            level: 'error',
+            ...(0, utils_1.findPosition)(propertyKey, manifest.yamlContentByLine, moduleKey)
+        }));
+    }
+    async validate(manifest) {
+        if (!manifest || !manifest.typedContent || !manifest.filePath) {
+            return {
+                success: false,
+                manifestObject: manifest
+            };
+        }
+        const i18nKeys = (0, utils_1.extractI18nKeysFromModules)(manifest?.typedContent?.modules ?? {});
+        const i18nConfig = manifest?.yamlContent?.translations;
+        if (!i18nConfig) {
+            return this.validateManifestWithoutI18nConfig(manifest, i18nKeys);
+        }
+        const validationErrors = [
+            ...this.validateManifestI18nConfig(manifest, i18nKeys),
+            ...this.validateInternalI18nPropertyKeysNotInModules(manifest)
+        ];
+        return {
+            success: validationErrors.length === 0,
+            manifestObject: manifest,
+            errors: validationErrors
+        };
+    }
+}
+exports.TranslationsValidator = TranslationsValidator;