diff --git a/packages/qwik-speak/tools/core/autokeys.ts b/packages/qwik-speak/tools/core/autokeys.ts index a001f20..5463e8f 100644 --- a/packages/qwik-speak/tools/core/autokeys.ts +++ b/packages/qwik-speak/tools/core/autokeys.ts @@ -36,45 +36,62 @@ export function generateAutoKey(input: string | number | Record) { /** * Evaluate if the key could be an existing object path */ -export function isObjectPath(key: string): boolean { - const regex = /^(?!\.)(?!.*\.\s)(?!.*\s\.)(?!.*\.$)(?=.*\..*)[^\s]+$/; - return regex.test(key); +export function isObjectPath(key: string, separator: string): boolean { + const regex = new RegExp(`^(?!\\${separator})(?!.*\\${separator}\\s)(?!.*\\s\\${separator})(?!.*\\${separator}$)(?=.*\\${separator}.*[^\\s]+)$`); + if (!regex.test(key)) { + return false; + } + + const segments = key.split(separator); + const variableNameRegex = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/; + for (const segment of segments) { + if (!variableNameRegex.test(segment)) { + return false; + } + } + + return true; } /** - * Evaluate if the key could be an existing object path. If the path does no exist in an asset, it will return false. + * Evaluate if the key could be an existing object path. If the path does not exist in an asset, it will return false. * It will return true if the path exists in all assets */ export function isExistingKey(data: Map | Translation, path: string, keySeparator: string) { const keys = path.split(keySeparator); + let keyFound = false; // Iterate if data is a Map if (data instanceof Map) { for (const translation of data.values()) { let value = translation; for (const key of keys) { - if (value[key] === undefined) { - return false; + if (value[key] !== undefined) { + keyFound = true; + } else { + keyFound = false; + break; } value = value[key]; } + if (!keyFound) { + break; + } } - return true; - } - - // Iterate if data is an object - if (typeof data === 'object') { + } else if (typeof data === 'object') { let value = data; for (const key of keys) { - if (value[key] === undefined) { - return false; + if (value[key] !== undefined) { + keyFound = true; + } else { + keyFound = false; + break; } value = value[key]; } - return true; } - return true; + return keyFound; } /** diff --git a/packages/qwik-speak/tools/extract/index.ts b/packages/qwik-speak/tools/extract/index.ts index 4d7d063..265c5d5 100644 --- a/packages/qwik-speak/tools/extract/index.ts +++ b/packages/qwik-speak/tools/extract/index.ts @@ -353,9 +353,12 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { if (resolvedOptions.autoKeys) { // Auto keys should be backward compatible with existing keys. We don't want to override them. - // Let's be conservative and only generate auto keys for keys that have no default value, don't resemble - // an object path and don't already exist in the assets. - if (key && !defaultValue && !isObjectPath(key) && !isExistingKey(assetsData, key, resolvedOptions.keySeparator)) { + if ( + key + && !defaultValue + && !isExistingKey(assetsData, key, resolvedOptions.keySeparator) + && !isObjectPath(key, resolvedOptions.keySeparator) + ) { defaultValue = `${key}`; key = generateAutoKey(key); }