ldx 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +228 -2
  2. package/ldx.js +152 -0
  3. package/package.json +45 -8
package/README.md CHANGED
@@ -1,3 +1,229 @@
1
- # ldx - logging developer experience
2
- transform command outputs to custom logs
1
+ # LDX - Logging Developer Experience
3
2
 
3
+ A lightweight tool to enhance your development workflow by processing command output with customizable transformations.
4
+
5
+ ## Features
6
+
7
+ - **Custom static transformations**: Define string patterns in your command output and replace them with custom messages.
8
+
9
+ - **Custom dynamic transformations**: Supports function-based transformations
10
+
11
+ - **Easy Integration**: Works seamlessly with any command-line tool or script.
12
+
13
+ - **Developer-Friendly**: Improves readability and reduces noise in logs.
14
+
15
+ ## Installation
16
+
17
+ To install LDX globally, run:
18
+
19
+ ```bash
20
+ pnpm install -g ldx
21
+ ```
22
+
23
+ Alternatively, you can install it locally in your project:
24
+
25
+ ```bash
26
+ pnpm install --save-dev ldx
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### 1. Create a Configuration File
32
+
33
+ Create a `ldx.config.js` file in your project's root directory. This file defines the patterns and transformations for your command output.
34
+
35
+ Example:
36
+
37
+ ```js
38
+ module.exports = {
39
+ // Simple string replacement
40
+ "Test match 1": "✅ Test match 1 processed",
41
+
42
+ // Function-based processing
43
+ "Function match": (line) => `Processed: ${line}`,
44
+ };
45
+ ```
46
+
47
+ ### 2. Run Commands with LDX
48
+
49
+ Use LDX to run your commands and transform their output:
50
+
51
+ ```bash
52
+ ldx <your-command>
53
+ ```
54
+
55
+ For example:
56
+
57
+ ```bash
58
+ ldx pnpm run dev
59
+ ```
60
+
61
+ ## Configuration Options
62
+
63
+ ### String Matching
64
+
65
+ ```js
66
+ module.exports = {
67
+ "String contained in output line": "Replacement text for the entire line"
68
+ }
69
+ ```
70
+
71
+ ### Function Processing
72
+
73
+ ```js
74
+ module.exports = {
75
+ "String contained in output line": (line) => {
76
+ // Custom processing logic
77
+ return `Formatted: ${line}`;
78
+ }
79
+ }
80
+ ```
81
+
82
+ ## Requirements
83
+
84
+ - Node.js >= 18.0.0
85
+
86
+ ## Error Handling
87
+
88
+ LDX provides clear error messages for common issues:
89
+
90
+ ### Missing Configuration File
91
+
92
+ If `ldx.config.js` is not found in your project root:
93
+
94
+ ```text
95
+ Oops, no ldx.config.js file found!
96
+ ```
97
+
98
+ **Solution**: Create a `ldx.config.js` file in your project root. You can copy `ldx.config.example.js` as a starting point.
99
+
100
+ ### Invalid Configuration
101
+
102
+ If your configuration has invalid values:
103
+
104
+ ```text
105
+ LDX: Configuration error - Invalid value type for key "myKey". Expected string or function, got number.
106
+ ```
107
+
108
+ **Solution**: Ensure all configuration values are either strings or functions.
109
+
110
+ ### Empty Configuration
111
+
112
+ If your configuration object is empty:
113
+
114
+ ```text
115
+ LDX: Configuration error - Configuration cannot be empty.
116
+ ```
117
+
118
+ **Solution**: Add at least one pattern-transformation pair to your configuration.
119
+
120
+ ### Command Not Found
121
+
122
+ If the command you're trying to run doesn't exist:
123
+
124
+ ```text
125
+ Error executing command: Failed to start command: spawn xyz ENOENT
126
+ ```
127
+
128
+ **Solution**: Verify the command exists and is in your PATH.
129
+
130
+ ### Function Processing Errors
131
+
132
+ If a transformer function throws an error, LDX will:
133
+
134
+ 1. Log a warning: `LDX: provided function errored: <error message>`
135
+ 2. Output the original unprocessed line (to prevent data loss)
136
+
137
+ **Solution**: Add try-catch blocks in your transformer functions for graceful error handling.
138
+
139
+ ## Testing
140
+
141
+ Run tests with:
142
+
143
+ ```bash
144
+ pnpm test
145
+ ```
146
+
147
+ ## Usage examples
148
+
149
+ ### Basic Usage
150
+
151
+ ```bash
152
+ ldx echo "Testing LDX tool"
153
+ ```
154
+
155
+ ### With package manager scripts
156
+
157
+ ```bash
158
+ ldx pnpm run dev
159
+ ```
160
+
161
+ ### With complex commands
162
+
163
+ ```bash
164
+ ldx docker-compose up
165
+ ```
166
+
167
+ ## Development
168
+
169
+ 1. Clone the repository
170
+
171
+ 2. Install dependencies:
172
+
173
+ ```bash
174
+ pnpm i
175
+ ```
176
+
177
+ 3. Make changes
178
+
179
+ 4. Run tests:
180
+
181
+ ```bash
182
+ pnpm test
183
+ ```
184
+
185
+ ## Releasing
186
+
187
+ This project uses [standard-version](https://github.com/conventional-changelog/standard-version) for automated versioning and changelog generation based on [Conventional Commits](https://www.conventionalcommits.org/).
188
+
189
+ ### Commit Message Format
190
+
191
+ ```text
192
+ <type>(<scope>): <description>
193
+
194
+ [optional body]
195
+
196
+ [optional footer(s)]
197
+ ```
198
+
199
+ Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `build`
200
+
201
+ Examples:
202
+
203
+ ```bash
204
+ git commit -m "feat: add support for regex patterns"
205
+ git commit -m "fix: handle empty lines in output"
206
+ git commit -m "docs: update configuration examples"
207
+ ```
208
+
209
+ ### Creating a Release
210
+
211
+ ```bash
212
+ # Automatic version bump based on commits (recommended)
213
+ pnpm release
214
+
215
+ # Specific version bumps
216
+ pnpm release:patch # 1.0.2 -> 1.0.3
217
+ pnpm release:minor # 1.0.2 -> 1.1.0
218
+ pnpm release:major # 1.0.2 -> 2.0.0
219
+ ```
220
+
221
+ After running the release command:
222
+
223
+ ```bash
224
+ git push --follow-tags origin main && npm publish
225
+ ```
226
+
227
+ ## Contributing
228
+
229
+ Contributions are welcome! Please open issues or pull requests in this repo.
package/ldx.js ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { resolve } = require("node:path");
4
+ const { spawn } = require("child_process");
5
+
6
+ // Load configuration
7
+ const project = resolve(process.cwd(), "ldx.config.js");
8
+ let config;
9
+ try {
10
+ config = require(project);
11
+ } catch (e) {
12
+ console.error("Oops, no ldx.config.js file found!");
13
+ process.exit(1);
14
+ }
15
+
16
+ // Validate configuration
17
+ function validateConfig(cfg) {
18
+ if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) {
19
+ return { valid: false, error: "Configuration must be a non-null object." };
20
+ }
21
+
22
+ const entries = Object.entries(cfg);
23
+ if (entries.length === 0) {
24
+ return { valid: false, error: "Configuration cannot be empty." };
25
+ }
26
+
27
+ for (const [key, value] of entries) {
28
+ if (typeof value !== "string" && typeof value !== "function") {
29
+ return {
30
+ valid: false,
31
+ error: `Invalid value type for key "${key}". Expected string or function, got ${typeof value}.`,
32
+ };
33
+ }
34
+ }
35
+
36
+ return { valid: true };
37
+ }
38
+
39
+ const validation = validateConfig(config);
40
+ if (!validation.valid) {
41
+ console.error(`LDX: Configuration error - ${validation.error}`);
42
+ process.exit(1);
43
+ }
44
+
45
+ console.log(
46
+ "Thank you for using LDX! Collaborate or report issues at https://github.com/leog/ldx \n"
47
+ );
48
+
49
+ // Function to execute the command and process output
50
+ function executeAndProcessCommand() {
51
+ return new Promise((resolve, reject) => {
52
+ const command = process.argv.slice(2);
53
+ if (command.length === 0) {
54
+ reject(new Error("No command provided."));
55
+ return;
56
+ }
57
+
58
+ const child = spawn(command[0], command.slice(1));
59
+
60
+ // Handle spawn errors (e.g., command not found)
61
+ child.on("error", (error) => {
62
+ reject(new Error(`Failed to start command: ${error.message}`));
63
+ });
64
+
65
+ // Handle stdout
66
+ if (child.stdout) {
67
+ child.stdout.on("data", (data) => {
68
+ const lines = data.toString().split("\n");
69
+ lines.forEach((line) => {
70
+ const processedLine = processOutput(line);
71
+ if (processedLine) {
72
+ console.log(processedLine); // Output the processed line
73
+ }
74
+ });
75
+ });
76
+ }
77
+
78
+ // Handle stderr
79
+ if (child.stderr) {
80
+ child.stderr.on("data", (data) => {
81
+ const lines = data.toString().split("\n");
82
+ lines.forEach((line) => {
83
+ const processedLine = processOutput(line);
84
+ if (processedLine) {
85
+ console.error(processedLine); // Output processed error line to stderr
86
+ } else if (line.trim()) {
87
+ console.error(line); // Pass through unmatched non-empty lines
88
+ }
89
+ });
90
+ });
91
+ }
92
+
93
+ // Handle process exit
94
+ child.on("close", (code) => {
95
+ if (code !== 0) {
96
+ reject(new Error(`Command failed with exit code ${code}`));
97
+ } else {
98
+ resolve();
99
+ }
100
+ });
101
+ });
102
+ }
103
+
104
+ // Function to process each line of output
105
+ function processOutput(line) {
106
+ // Check static matches first (O(n) lookup, but optimized for small n)
107
+ const match = Object.entries(config).find(([key]) => line.includes(key));
108
+
109
+ if (match) {
110
+ const [key, value] = match;
111
+
112
+ // Handle string values
113
+ if (typeof value === "string") {
114
+ return value;
115
+ }
116
+
117
+ // Handle function values
118
+ if (typeof value === "function") {
119
+ try {
120
+ return value(line);
121
+ } catch (e) {
122
+ console.warn("LDX: provided function errored: ", e.message);
123
+ return line; // Return original line on error to prevent data loss
124
+ }
125
+ }
126
+
127
+ // Handle invalid configurations
128
+ console.warn(
129
+ `Invalid configuration for key: ${key}. Expected string or function.`
130
+ );
131
+ }
132
+
133
+ // No match found
134
+ return undefined;
135
+ }
136
+
137
+ // Export functions for testing
138
+ module.exports = {
139
+ processOutput,
140
+ executeAndProcessCommand,
141
+ validateConfig,
142
+ };
143
+
144
+ // Execute the command if this script is run directly
145
+ /* v8 ignore start */
146
+ if (require.main === module) {
147
+ // Main execution
148
+ executeAndProcessCommand()
149
+ .then(() => console.log("Command executed successfully."))
150
+ .catch((error) => console.error("Error executing command:", error));
151
+ }
152
+ /* v8 ignore end */
package/package.json CHANGED
@@ -1,12 +1,49 @@
1
1
  {
2
2
  "name": "ldx",
3
- "version": "1.0.0",
4
- "main": "index.js",
5
- "scripts": {
6
- "test": "echo \"Error: no test specified\" && exit 1"
3
+ "version": "1.0.2",
4
+ "main": "ldx.js",
5
+ "engines": {
6
+ "node": ">=18.0.0"
7
+ },
8
+ "bin": {
9
+ "ldx": "ldx.js"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/leog/ldx.git"
7
14
  },
8
- "keywords": [],
9
- "author": "",
10
- "license": "ISC",
11
- "description": ""
15
+ "keywords": [
16
+ "transform",
17
+ "output",
18
+ "logging",
19
+ "developer",
20
+ "experience",
21
+ "dx"
22
+ ],
23
+ "files": [
24
+ "package.json",
25
+ "ldx.js",
26
+ "README.md"
27
+ ],
28
+ "author": {
29
+ "name": "Leo Giovanetti",
30
+ "email": "hello@leog.me",
31
+ "url": "https://x.com/leog"
32
+ },
33
+ "license": "Apache-2.0",
34
+ "description": "Enhancing logging developer experience",
35
+ "devDependencies": {
36
+ "@vitest/coverage-v8": "3.0.9",
37
+ "mock-require": "^3.0.3",
38
+ "standard-version": "^9.5.0",
39
+ "vitest": "^3.0.9"
40
+ },
41
+ "scripts": {
42
+ "test": "vitest --coverage",
43
+ "release": "standard-version",
44
+ "release:minor": "standard-version --release-as minor",
45
+ "release:major": "standard-version --release-as major",
46
+ "release:patch": "standard-version --release-as patch",
47
+ "release:first": "standard-version --first-release"
48
+ }
12
49
  }