start-command 0.3.1
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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.changeset/isolation-support.md +30 -0
- package/.github/workflows/release.yml +292 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +6 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +24 -0
- package/LICENSE +24 -0
- package/README.md +249 -0
- package/REQUIREMENTS.md +229 -0
- package/bun.lock +453 -0
- package/bunfig.toml +3 -0
- package/eslint.config.mjs +122 -0
- package/experiments/debug-regex.js +49 -0
- package/experiments/isolation-design.md +142 -0
- package/experiments/test-cli.sh +42 -0
- package/experiments/test-substitution.js +143 -0
- package/package.json +63 -0
- package/scripts/changeset-version.mjs +38 -0
- package/scripts/check-file-size.mjs +103 -0
- package/scripts/create-github-release.mjs +93 -0
- package/scripts/create-manual-changeset.mjs +89 -0
- package/scripts/format-github-release.mjs +83 -0
- package/scripts/format-release-notes.mjs +219 -0
- package/scripts/instant-version-bump.mjs +121 -0
- package/scripts/publish-to-npm.mjs +129 -0
- package/scripts/setup-npm.mjs +37 -0
- package/scripts/validate-changeset.mjs +107 -0
- package/scripts/version-and-commit.mjs +237 -0
- package/src/bin/cli.js +670 -0
- package/src/lib/args-parser.js +259 -0
- package/src/lib/isolation.js +419 -0
- package/src/lib/substitution.js +323 -0
- package/src/lib/substitutions.lino +308 -0
- package/test/args-parser.test.js +389 -0
- package/test/isolation.test.js +248 -0
- package/test/substitution.test.js +236 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Unit tests for the substitution engine
|
|
4
|
+
* Tests pattern matching, variable substitution, and rule precedence
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const assert = require('assert');
|
|
8
|
+
const {
|
|
9
|
+
parseLinoContent,
|
|
10
|
+
matchAndSubstitute,
|
|
11
|
+
loadDefaultSubstitutions,
|
|
12
|
+
processCommand,
|
|
13
|
+
} = require('../src/lib/substitution');
|
|
14
|
+
|
|
15
|
+
// Test data
|
|
16
|
+
const testCases = [
|
|
17
|
+
// NPM install patterns
|
|
18
|
+
{
|
|
19
|
+
input: 'install gh-upload-log npm package',
|
|
20
|
+
expected: 'npm install gh-upload-log',
|
|
21
|
+
description: 'Basic npm install',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
input: 'install 0.0.1 version of gh-upload-log npm package',
|
|
25
|
+
expected: 'npm install gh-upload-log@0.0.1',
|
|
26
|
+
description: 'npm install with version',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
input: 'install lodash npm package globally',
|
|
30
|
+
expected: 'npm install -g lodash',
|
|
31
|
+
description: 'Global npm install',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
input: 'install 4.17.21 version of lodash npm package globally',
|
|
35
|
+
expected: 'npm install -g lodash@4.17.21',
|
|
36
|
+
description: 'Global npm install with version',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
input: 'uninstall lodash npm package',
|
|
40
|
+
expected: 'npm uninstall lodash',
|
|
41
|
+
description: 'npm uninstall',
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// Git patterns
|
|
45
|
+
{
|
|
46
|
+
input: 'clone https://github.com/user/repo repository',
|
|
47
|
+
expected: 'git clone https://github.com/user/repo',
|
|
48
|
+
description: 'Git clone with URL',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
input: 'clone git@github.com:user/repo.git repository',
|
|
52
|
+
expected: 'git clone git@github.com:user/repo.git',
|
|
53
|
+
description: 'Git clone with SSH URL',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
input: 'checkout main branch',
|
|
57
|
+
expected: 'git checkout main',
|
|
58
|
+
description: 'Git checkout branch',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
input: 'create feature-x branch',
|
|
62
|
+
expected: 'git checkout -b feature-x',
|
|
63
|
+
description: 'Git create branch',
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// Common operations
|
|
67
|
+
{
|
|
68
|
+
input: 'list files',
|
|
69
|
+
expected: 'ls -la',
|
|
70
|
+
description: 'List files',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
input: 'show current directory',
|
|
74
|
+
expected: 'pwd',
|
|
75
|
+
description: 'Show working directory',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
input: 'create my-project directory',
|
|
79
|
+
expected: 'mkdir -p my-project',
|
|
80
|
+
description: 'Create directory',
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Python patterns
|
|
84
|
+
{
|
|
85
|
+
input: 'install requests python package',
|
|
86
|
+
expected: 'pip install requests',
|
|
87
|
+
description: 'pip install',
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Non-matching patterns (should return original)
|
|
91
|
+
{
|
|
92
|
+
input: 'echo hello world',
|
|
93
|
+
expected: 'echo hello world',
|
|
94
|
+
description: 'Non-matching command (pass through)',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
input: 'npm test',
|
|
98
|
+
expected: 'npm test',
|
|
99
|
+
description: 'Regular npm command (pass through)',
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
// Test suite
|
|
104
|
+
function runTests() {
|
|
105
|
+
console.log('=== Substitution Engine Unit Tests ===\n');
|
|
106
|
+
|
|
107
|
+
let passed = 0;
|
|
108
|
+
let failed = 0;
|
|
109
|
+
const failures = [];
|
|
110
|
+
|
|
111
|
+
// Load default substitutions
|
|
112
|
+
const rules = loadDefaultSubstitutions();
|
|
113
|
+
console.log(`✓ Loaded ${rules.length} substitution rules\n`);
|
|
114
|
+
|
|
115
|
+
// Test: Loading substitutions
|
|
116
|
+
assert(rules.length > 0, 'Should load at least one substitution rule');
|
|
117
|
+
assert(Array.isArray(rules), 'Rules should be an array');
|
|
118
|
+
console.log('✓ Test: loadDefaultSubstitutions() returns array of rules');
|
|
119
|
+
|
|
120
|
+
// Test: Rule structure
|
|
121
|
+
const firstRule = rules[0];
|
|
122
|
+
assert(firstRule.pattern, 'Rule should have pattern property');
|
|
123
|
+
assert(firstRule.replacement, 'Rule should have replacement property');
|
|
124
|
+
assert(firstRule.regex, 'Rule should have regex property');
|
|
125
|
+
console.log(
|
|
126
|
+
'✓ Test: Rules have correct structure (pattern, replacement, regex)'
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Test: Pattern matching and substitution
|
|
130
|
+
console.log('\n=== Pattern Matching Tests ===\n');
|
|
131
|
+
for (const test of testCases) {
|
|
132
|
+
const result = matchAndSubstitute(test.input, rules);
|
|
133
|
+
|
|
134
|
+
if (result.command === test.expected) {
|
|
135
|
+
console.log(`✓ PASS: ${test.description}`);
|
|
136
|
+
console.log(` Input: "${test.input}"`);
|
|
137
|
+
console.log(` Output: "${result.command}"`);
|
|
138
|
+
passed++;
|
|
139
|
+
} else {
|
|
140
|
+
console.log(`✗ FAIL: ${test.description}`);
|
|
141
|
+
console.log(` Input: "${test.input}"`);
|
|
142
|
+
console.log(` Expected: "${test.expected}"`);
|
|
143
|
+
console.log(` Got: "${result.command}"`);
|
|
144
|
+
failed++;
|
|
145
|
+
failures.push({
|
|
146
|
+
test,
|
|
147
|
+
actual: result.command,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
console.log('');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Test: Pattern specificity (more specific patterns should match first)
|
|
154
|
+
console.log('=== Pattern Specificity Tests ===\n');
|
|
155
|
+
const specificityTest = matchAndSubstitute(
|
|
156
|
+
'install 1.0.0 version of express npm package globally',
|
|
157
|
+
rules
|
|
158
|
+
);
|
|
159
|
+
assert(
|
|
160
|
+
specificityTest.command === 'npm install -g express@1.0.0',
|
|
161
|
+
'Most specific pattern should match (with version and globally)'
|
|
162
|
+
);
|
|
163
|
+
console.log('✓ Test: Pattern specificity works correctly');
|
|
164
|
+
console.log(
|
|
165
|
+
` Input: "install 1.0.0 version of express npm package globally"`
|
|
166
|
+
);
|
|
167
|
+
console.log(` Output: "${specificityTest.command}"\n`);
|
|
168
|
+
|
|
169
|
+
// Test: Variable extraction
|
|
170
|
+
console.log('=== Variable Extraction Tests ===\n');
|
|
171
|
+
const varTest = matchAndSubstitute('install my-package npm package', rules);
|
|
172
|
+
assert(
|
|
173
|
+
varTest.matched && varTest.command === 'npm install my-package',
|
|
174
|
+
'Should extract and substitute packageName variable'
|
|
175
|
+
);
|
|
176
|
+
assert(
|
|
177
|
+
varTest.rule.variables.includes('packageName'),
|
|
178
|
+
'Rule should have packageName in variables list'
|
|
179
|
+
);
|
|
180
|
+
console.log('✓ Test: Variable extraction and substitution works correctly');
|
|
181
|
+
console.log(` Pattern matched: "${varTest.rule.pattern}"`);
|
|
182
|
+
console.log(` Variables in pattern: [${varTest.rule.variables.join(', ')}]`);
|
|
183
|
+
console.log(` Result command: "${varTest.command}"\n`);
|
|
184
|
+
|
|
185
|
+
// Test: processCommand function
|
|
186
|
+
console.log('=== processCommand Integration Tests ===\n');
|
|
187
|
+
const processedResult = processCommand('list files');
|
|
188
|
+
assert(
|
|
189
|
+
processedResult.command === 'ls -la',
|
|
190
|
+
'processCommand should apply substitutions'
|
|
191
|
+
);
|
|
192
|
+
assert(
|
|
193
|
+
processedResult.matched === true,
|
|
194
|
+
'processCommand should indicate match'
|
|
195
|
+
);
|
|
196
|
+
console.log('✓ Test: processCommand applies substitutions');
|
|
197
|
+
console.log(` Input: "list files"`);
|
|
198
|
+
console.log(` Output: "${processedResult.command}"`);
|
|
199
|
+
console.log(` Matched: ${processedResult.matched}\n`);
|
|
200
|
+
|
|
201
|
+
// Test with non-matching command
|
|
202
|
+
const nonMatchResult = processCommand('echo test');
|
|
203
|
+
assert(
|
|
204
|
+
nonMatchResult.command === 'echo test',
|
|
205
|
+
'processCommand should pass through non-matching commands'
|
|
206
|
+
);
|
|
207
|
+
assert(
|
|
208
|
+
nonMatchResult.matched === false,
|
|
209
|
+
'processCommand should indicate no match'
|
|
210
|
+
);
|
|
211
|
+
console.log('✓ Test: processCommand passes through non-matching commands');
|
|
212
|
+
console.log(` Input: "echo test"`);
|
|
213
|
+
console.log(` Output: "${nonMatchResult.command}"`);
|
|
214
|
+
console.log(` Matched: ${nonMatchResult.matched}\n`);
|
|
215
|
+
|
|
216
|
+
// Summary
|
|
217
|
+
console.log('=== Test Summary ===');
|
|
218
|
+
console.log(`Pattern Matching: ${passed}/${testCases.length} tests passed`);
|
|
219
|
+
console.log(`Total Tests: ${passed + 7}/${testCases.length + 7} passed`);
|
|
220
|
+
|
|
221
|
+
if (failed > 0) {
|
|
222
|
+
console.log(`\nFailed tests: ${failed}`);
|
|
223
|
+
failures.forEach(({ test, actual }) => {
|
|
224
|
+
console.log(` - ${test.description}`);
|
|
225
|
+
console.log(` Expected: "${test.expected}"`);
|
|
226
|
+
console.log(` Got: "${actual}"`);
|
|
227
|
+
});
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
console.log('\n✓ All tests passed!\n');
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Run tests
|
|
236
|
+
runTests();
|