-
Notifications
You must be signed in to change notification settings - Fork 2
Add JS/TS i18n custom rules #76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
13693e5
9cad841
34d0e06
b64743a
7c9ae50
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -38,6 +38,90 @@ rules: | |||||
| technology: | ||||||
| - java | ||||||
| impact: MEDIUM | ||||||
| confidence: HIGH | ||||||
| confidence: LOW | ||||||
| likelihood: HIGH | ||||||
|
|
||||||
| - id: codacy.js.i18n.no-hardcoded-alert-concat | ||||||
| severity: WARNING | ||||||
| languages: | ||||||
| - js | ||||||
| - ts | ||||||
| pattern-either: | ||||||
| # Direct hardcoded alert strings | ||||||
| - pattern: alert("...") | ||||||
| - pattern: window.alert("...") | ||||||
| # String concatenation in alerts | ||||||
| - pattern: alert("..." + ...) | ||||||
| - pattern: alert(... + "...") | ||||||
| - pattern: window.alert("..." + ...) | ||||||
| - pattern: window.alert(... + "...") | ||||||
| pattern-not: alert(t(...)) | ||||||
| message: >- | ||||||
| Avoid hardcoded or concatenated strings in alerts. Use an i18n translation function (e.g., t("key")) with interpolation. | ||||||
| metadata: | ||||||
| category: codestyle | ||||||
| subcategory: i18n | ||||||
| description: Flags hardcoded and concatenated strings in alert dialogs to enforce localization | ||||||
| technology: | ||||||
| - javascript | ||||||
| - typescript | ||||||
| impact: MEDIUM | ||||||
| confidence: LOW | ||||||
| likelihood: HIGH | ||||||
|
|
||||||
| - id: codacy.js.i18n.no-hardcoded-locale-date | ||||||
| severity: WARNING | ||||||
| languages: | ||||||
| - js | ||||||
| - ts | ||||||
| pattern-regex: "\\.(toLocale(Date|Time)?String)\\(\"[^\"]+\"" | ||||||
| message: Avoid hardcoded locale strings in date/time formatting. | ||||||
| metadata: | ||||||
| category: codestyle | ||||||
| subcategory: i18n | ||||||
| description: Flags explicit locale strings in date/time formatting which can break localization | ||||||
| technology: | ||||||
| - javascript | ||||||
| - typescript | ||||||
| impact: MEDIUM | ||||||
| confidence: LOW | ||||||
| likelihood: HIGH | ||||||
|
|
||||||
| - id: codacy.js.i18n.no-hardcoded-number-format | ||||||
| severity: WARNING | ||||||
| languages: | ||||||
| - js | ||||||
| - ts | ||||||
| pattern-regex: "\\.toFixed\\([^)]*\\)" | ||||||
| message: >- | ||||||
| Avoid using toFixed for user-visible number formatting. Use locale-aware formatting or translation helpers. | ||||||
| metadata: | ||||||
| category: codestyle | ||||||
| subcategory: i18n | ||||||
| description: Flags toFixed used for UI number formatting; recommends locale-aware alternatives | ||||||
| technology: | ||||||
| - javascript | ||||||
| - typescript | ||||||
| impact: MEDIUM | ||||||
| confidence: LOW | ||||||
| likelihood: HIGH | ||||||
|
|
||||||
| - id: codacy.js.i18n.no-raw-jsx-text | ||||||
| severity: WARNING | ||||||
| languages: | ||||||
| - js | ||||||
| - ts | ||||||
| pattern-regex: "<(h1|h2|h3|h4|h5|h6|p|span|div|td|th)[^>]*>[^<{]*[A-Za-z][^<{]*</\\1>" | ||||||
|
||||||
| pattern-regex: "<(h1|h2|h3|h4|h5|h6|p|span|div|td|th)[^>]*>[^<{]*[A-Za-z][^<{]*</\\1>" | |
| pattern-regex: "<(h1|h2|h3|h4|h5|h6|p|span|div|td|th)[^>]*>[^<{]*[A-Za-z]{2,}[^<{]*\\s+[A-Za-z]{2,}[^<{]*</\\1>" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <module name="root"> | ||
| <module name="codacy.csharp.ai.insecure-llm-model-usage"> | ||
| <property name="modelRegex" value="^(gemini-2.5-flash|gpt-3\\.5-turbo|old-llama-model)$" /> | ||
| <property name="modelAllowList" value="gemini-2.5-flash,gpt-3.5-turbo,old-llama-model" /> | ||
| </module> | ||
| </module> |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,9 @@ public static async Task main() { | |||||
| // The client gets the API key from the environment variable `GEMINI_API_KEY`. | ||||||
| var client = new Client(); | ||||||
| var response = await client.Models.GenerateContentAsync( | ||||||
| model: "deepseek-v3.2", contents: "Explain how AI works in a few words" | ||||||
| ); | ||||||
| var response2 = await client.Models.GenerateContentAsync( | ||||||
|
||||||
| var response2 = await client.Models.GenerateContentAsync( | |
| await client.Models.GenerateContentAsync( |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,7 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <module name="root"> | ||
| <module name="codacy.java.i18n.enforce-localized-output" /> | ||
| <module name="codacy.js.i18n.no-hardcoded-alert-concat" /> | ||
| <module name="codacy.js.i18n.no-hardcoded-locale-date" /> | ||
| <module name="codacy.js.i18n.no-hardcoded-number-format" /> | ||
| </module> |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -167,17 +167,23 @@ func replaceParameterPlaceholders(line string, pattern *codacy.Pattern) string { | |||||||||
| paramName := matches[1] | ||||||||||
| // Convert UPPER_CASE to camelCase to match parameter name format | ||||||||||
| formattedParamName := formatParameterName(paramName) | ||||||||||
|
|
||||||||||
| // Find the parameter in the pattern | ||||||||||
| for _, param := range pattern.Parameters { | ||||||||||
|
|
||||||||||
| if param.Name == formattedParamName { | ||||||||||
| // Use Value if set, otherwise use Default | ||||||||||
| value := param.Value | ||||||||||
| if value == nil { | ||||||||||
| value = param.Default | ||||||||||
| } | ||||||||||
| if value != nil { | ||||||||||
| return fmt.Sprintf("%v", value) | ||||||||||
| valueStr := fmt.Sprintf("%v", value) | ||||||||||
|
|
||||||||||
| // If parameter name ends with _ALLOW_LIST, convert comma-separated list to regex pattern | ||||||||||
| if strings.HasSuffix(paramName, "_ALLOW_LIST") { | ||||||||||
| return convertListToRegex(valueStr, false) | ||||||||||
| } | ||||||||||
| return valueStr | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
@@ -189,6 +195,27 @@ func replaceParameterPlaceholders(line string, pattern *codacy.Pattern) string { | |||||||||
| return result | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // convertListToRegex converts a comma-separated list into a regex alternation pattern | ||||||||||
| // Example: "gemini-2.5-flash,gpt-3.5-turbo,old-llama-model" -> "^(gemini-2\\.5-flash|gpt-3\\.5-turbo|old-llama-model)$" | ||||||||||
|
||||||||||
| // Example: "gemini-2.5-flash,gpt-3.5-turbo,old-llama-model" -> "^(gemini-2\\.5-flash|gpt-3\\.5-turbo|old-llama-model)$" | |
| // Examples: | |
| // convertListToRegex("gemini-2.5-flash,gpt-3.5-turbo,old-llama-model", true) -> "^(gemini-2\\.5-flash|gpt-3\\.5-turbo|old-llama-model)$" | |
| // convertListToRegex("gemini-2.5-flash,gpt-3.5-turbo,old-llama-model", false) -> "^(?!(gemini-2\\.5-flash|gpt-3\\.5-turbo|old-llama-model)$).*" |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex escaping in this function is incomplete and could cause incorrect pattern matching. Currently, only dots are escaped, but regex has many other special characters that need escaping (e.g., +, *, ?, [, ], (, ), {, }, ^, $, |, ). For example, if a model name contains "gpt-4+" or "model[v2]", these would be interpreted as regex operators rather than literal characters. Use a proper regex escaping function like regexp.QuoteMeta() to escape all special characters.
| // Escape dots for regex | |
| item = strings.ReplaceAll(item, ".", "\\.") | |
| // Escape all regex metacharacters | |
| item = regexp.QuoteMeta(item) |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new convertListToRegex function lacks test coverage. Given that this function performs critical regex pattern generation with special character escaping and complex logic for allow/deny lists, it should have comprehensive unit tests covering edge cases such as: empty lists, lists with special regex characters, single-item lists, and both include=true and include=false branches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex pattern may have unintended matches. The pattern
"\\.(toLocale(Date|Time)?String)\\(\"[^\"]+\""will only match cases where the locale string is immediately after the opening parenthesis with no whitespace. It won't match cases like.toLocaleDateString( "en-US")or.toLocaleDateString(options, "en-US"). Consider using a more flexible pattern that accounts for optional whitespace and multiple parameters.