hardcode-string-detector
v0.4.2
Published
A CLI tool to detect hardcoded strings in your project based on hcs_config.json tasks.
Maintainers
Readme
Hard Code String Extractor (hcs)
A command-line tool to scan your project for hardcoded strings, helping you identify text that needs to be internationalized (i18n) or managed more effectively.
Why Use This Tool?
Keeping track of hardcoded strings is crucial for:
- Internationalization (i18n): Easily spot text that needs to be moved to translation files.
- Maintainability: Manage UI text and other string literals from a central or configured perspective.
- Consistency: Ensure that user-facing strings are handled systematically.
hard-code-string-extractor (hcs) scans your codebase based on flexible configurations and outputs a JSON report detailing the found strings and their locations.
Features
- Configurable Scanning: Define multiple scan tasks, each targeting different directories and file types.
- Broad File Support: Scans JavaScript, JSX, TypeScript, and TSX files by default (configurable).
- Flexible Detection Rules:
- Identifies strings in JSX text content (
<div>Hardcoded Text</div>). - Finds string literals within JSX expressions (
<p>{"Hardcoded Expression"}</p>). - Checks for strings in configurable JSX attributes (e.g.,
placeholder,alt,aria-label). - Detects strings passed as arguments to specific, user-defined functions (e.g.,
Alert.alert("Title"),enqueueSnackbar("Message")).
- Identifies strings in JSX text content (
- JSON Output: Generates a
detected.json(or custom-named) file with findings, including:- File path (relative to the scanned directory).
- Line and column number.
- The detected hardcoded string.
- Output paths are often clickable in modern terminals and IDEs like VS Code.
- Configuration via
hcs_config.json: Manage all your scanning profiles and rules from a single JSON configuration file.
Installation
You can install hard-code-string-extractor globally to use the hcs command anywhere:
npm install -g hard-code-string-extractorOr you can install it locally in your project:
npm install --save-dev hard-code-string-extractorIf installed locally, you can run it using npx hcs or by adding it to your package.json scripts.
Usage The primary way to use the tool is by defining your scan configurations in an hcs_config.json file in your project root.
Bash
hcs [taskName1 taskName2 ...] If you run hcs without any arguments, it will attempt to load hcs_config.json from the current directory and execute all tasks defined within it. You can specify one or more task names as arguments to run only those specific tasks. Example:
Bash
Run all tasks defined in hcs_config.json
hcs
Run only the "FrontendScan" and "MobileScan" tasks
hcs FrontendScan MobileScan The tool will generate JSON output files as specified in each task's configuration.
Configuration (hcs_config.json) Create an hcs_config.json file in the root of your project to define global settings and specific scan tasks.
Structure:
JSON
{
"globalExtensions": ["js", "jsx", "ts", "tsx"],
"globalAttributes": ["placeholder", "title", "alt", "aria-label", "label", "data-tooltip"],
"globalTargetFunctions": [
{
"functionNameForDisplay": "Default: Alert.alert",
"calleeType": "MemberExpression", "objectName": "Alert", "propertyName": "alert",
"argumentChecks": [
{ "index": 0, "type": "StringLiteral", "description": "title" },
{ "index": 1, "type": "StringLiteral", "description": "message" }
]
}
],
"tasks": [
{
"name": "WebAppUI",
"scanDir": "./src/webapp",
"output": "reports/webapp_hardcoded.json",
"extensions": ["jsx", "tsx"],
"attributes": ["placeholder", "aria-label", "title"],
"targetFunctions": [
{
"functionNameForDisplay": "enqueueSnackbar (notistack)",
"calleeType": "Identifier", "identifierName": "enqueueSnackbar",
"argumentChecks": [
{ "index": 0, "type": "StringLiteral", "description": "message" }
]
},
{
"functionNameForDisplay": "customTranslateFunction",
"calleeType": "Identifier", "identifierName": "translate",
"argumentChecks": [
// This example rule helps find if you accidentally pass a literal string
// to your translate function instead of a key.
{ "index": 0, "type": "StringLiteral", "description": "translation_key_or_default_literal" }
]
}
]
},
{
"name": "MobileAppStrings",
"scanDir": "./src/mobile",
"output": "reports/mobile_hardcoded.json",
// Uses globalExtensions
"attributes": ["label", "hint", "accessibilityLabel"], // Overrides globalAttributes
"targetFunctions": [
// Inherits Alert.alert from globalTargetFunctions if merging logic is implemented,
// or if this list is empty, globalTargetFunctions could be used by default.
// Current script behavior: If task.targetFunctions exists, it's used exclusively.
// If task.targetFunctions is undefined, config.globalTargetFunctions is used.
// If that's also undefined, SCRIPT_DEFAULTS.targetFunctions is used.
// To combine, you'd explicitly list global ones here or modify the script's merging logic.
// For clarity, let's assume this task wants its own specific list plus the global Alert.alert.
// The script would need to be adjusted to merge globalTargetFunctions with task-specific ones if both are present.
// As implemented in the provided script, if a task defines targetFunctions, it *replaces* the global/default.
// To use global and add more:
// "targetFunctions": "USE_GLOBAL_AND_ADD_MORE" (requires script change) or manually copy global ones here.
// Let's assume for this example, it defines its own complete list for this task:
{
"functionNameForDisplay": "Alert.alert (Mobile)", // Potentially overriding a global one with more specific checks
"calleeType": "MemberExpression", "objectName": "Alert", "propertyName": "alert",
"argumentChecks": [
{ "index": 0, "type": "StringLiteral", "description": "title" },
{ "index": 1, "type": "StringLiteral", "description": "message" }
]
},
{
"functionNameForDisplay": "Snackbar.show (react-native-snackbar)",
"calleeType": "MemberExpression", "objectName": "Snackbar", "propertyName": "show",
"argumentChecks": [
{
"index": 0,
"type": "ObjectExpression",
"properties": [
{ "keyName": "text", "valueType": "StringLiteral", "description": "snackbar text" }
]
}
]
}
]
},
{
"name": "SharedLibraries",
"scanDir": "./packages/shared-utils/src",
"output": "reports/shared_libs_hardcoded.json",
"extensions": ["js", "ts"]
// Uses globalAttributes and globalTargetFunctions (or script defaults if globals are not set)
}
]
}Configuration Fields:
- globalExtensions (Array<String>, optional): Default file extensions to scan if not specified per task.
- globalAttributes (Array<String>, optional): Default JSX attributes to check for hardcoded strings if not - specified per task.
- globalTargetFunctions (Array<Object>, optional): Default function call patterns to check if not specified per - task.
- tasks (Array<Object>, required): An array of scan task objects.
- name (String, required): A unique name for the task (used for selective execution).
- scanDir (String, required): The directory to scan for this task, relative to the project root.
- output (String, required): The output JSON file path for this task's results, relative to the project root.
- extensions (Array<String>, optional): Task-specific file extensions. Overrides globalExtensions.
- attributes (Array<String>, optional): Task-specific JSX attributes. Overrides globalAttributes.
- targetFunctions (Array<Object>, optional): Task-specific function call patterns. Overrides globalTargetFunctions.
- Each targetFunction object has:
- functionNameForDisplay (String): A descriptive name for the rule.
- calleeType (String): "Identifier" (e.g., myFunc()) or "MemberExpression" (e.g., object.myFunc()).
- identifierName (String, if calleeType is "Identifier"): The name of the function.
- objectName (String, if calleeType is "MemberExpression"): The name of the object (e.g., "Alert").
- propertyName (String, if calleeType is "MemberExpression"): The name of the property/method (e.g., "alert").
- argumentChecks (Array<Object>): Rules for checking arguments.
- index (Number): The 0-based index of the argument.
- type (String): Expected type of the argument, e.g., "StringLiteral" or "ObjectExpression".
- properties (Array<Object>, if type is "ObjectExpression"): Rules for checking object properties.
- keyName (String): The name of the object key.
- valueType (String): Expected type of the property's value (e.g., "StringLiteral").
- description (String, optional): A comment for the rule.
- Each targetFunction object has:
Output JSON Format
The output is a JSON object where keys are the location of the hardcoded string and values are the detected strings themselves:
JSON
{
"src/components/MyComponent.jsx:25:12": "Welcome to our application!",
"src/pages/HomePage.tsx:10:5": "Learn More",
"src/utils/toastHelper.js:5:22": "Operation successful"
}The filePath:lineNumber:columnNumber format is often clickable in IDEs like VS Code, taking you directly to the source.
Example Workflow Create hcs_config.json in your project root with your desired tasks (see example above). Run the extractor: Bash
Run all tasks
hcsRun a specific task
hcs WebAppUIReview the output JSON files (e.g., reports/webapp_hardcoded.json). Contributing Contributions are welcome! Please feel free to open an issue or submit a pull request. (TODO: Add contribution guidelines if you plan to open-source it formally).
License This project is licensed under the MIT License - see the LICENSE.md file for details (You would need to create a LICENSE.md file with the MIT license text).
To make hcs the short command for your CLI tool:
When you publish your package to npm, you'll need to configure the bin field in your package.json like this:
// package.json
{
"name": "hard-code-string-extractor",
"version": "0.3.0", // Or your current version
"description": "A CLI tool to detect hardcoded strings in your project.",
"main": "index.js", // Your main script file
"bin": {
"hard-code-string-extractor": "./index.js",
"hcs": "./index.js"
},
// ... other fields like author, license, dependencies, scripts
}
This tells npm to create a symlink for hcs (and hard-code-string-extractor) to your index.js script when the package is installed globally. Make sure index.js has the shebang #!/usr/bin/env node at the very top.
