Source: scripts/duplicates.js

import * as Types from '../ri18next.config.js'

/**
 * @function traverse
 * @description Traverse the translation object and add the key-value pairs to a map
 * @param {Object} node The current node
 * @param {Map<string, string>} map The map with the key-value pairs
 * @param {Array<string>} path The path of the current node
 * @returns {Map<string, string>} The map with the key-value pairs
 */
const traverse = (node, map, path = []) => {
	if (typeof node === 'object') {
		Object.entries(node).forEach(([key, value]) => {
			const currentPath = [...path, key]
			if (typeof value === 'string') {
				if (map.has(value)) {
					map.set(value, [...map.get(value), currentPath.join('.')])
				} else {
					map.set(value, [currentPath.join('.')])
				}
			}
			traverse(value, map, currentPath)
		})
	}
	return map
}

/**
 * @function checkForDuplicateValues
 * @description Check for duplicate values in translation file
 * @param {Map} translation The translation file
 * @param {Types.Config} config The config for the validator
 * @returns {void}
 */
export const checkForDuplicateValues = (translation, config) => {
	const keyValueMap = new Map()
	const traversedMap = traverse(translation, keyValueMap)

	console.info('[🟡] Checking for duplicates...')
	const result = []
	const regex = /\$t\(([^)]+)\)/

	traversedMap.forEach((keys, value) => {
		if (keys.length > 1 && !regex.test(value) && !config.ignoreKeys.some(key => keys.includes(key)))
			result.push({ value, keys })
	})

	if (config.errorLevel === 'off') return
	if (result.length > 0) {
		const errorMessage = `[❌] Duplicate values found in translation.json:\n${JSON.stringify(result, null, 2)}`
		if (config.errorLevel === 'error') throw new Error(errorMessage)
		if (config.errorLevel === 'warn') console.warn(errorMessage)
	} else {
		console.info('[✅] No duplicates found.')
	}

	console.info('----------------------------------------')
}