browser-commander 0.2.0
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/.github/workflows/release.yml +296 -0
- package/.husky/pre-commit +1 -0
- package/.jscpd.json +20 -0
- package/.prettierignore +7 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +32 -0
- package/LICENSE +24 -0
- package/README.md +320 -0
- package/bunfig.toml +3 -0
- package/deno.json +7 -0
- package/eslint.config.js +125 -0
- package/examples/react-test-app/index.html +25 -0
- package/examples/react-test-app/package.json +19 -0
- package/examples/react-test-app/src/App.jsx +473 -0
- package/examples/react-test-app/src/main.jsx +10 -0
- package/examples/react-test-app/src/styles.css +323 -0
- package/examples/react-test-app/vite.config.js +9 -0
- package/package.json +89 -0
- package/scripts/changeset-version.mjs +38 -0
- package/scripts/create-github-release.mjs +93 -0
- package/scripts/create-manual-changeset.mjs +86 -0
- package/scripts/format-github-release.mjs +83 -0
- package/scripts/format-release-notes.mjs +216 -0
- package/scripts/instant-version-bump.mjs +121 -0
- package/scripts/merge-changesets.mjs +260 -0
- package/scripts/publish-to-npm.mjs +126 -0
- package/scripts/setup-npm.mjs +37 -0
- package/scripts/validate-changeset.mjs +262 -0
- package/scripts/version-and-commit.mjs +237 -0
- package/src/ARCHITECTURE.md +270 -0
- package/src/README.md +517 -0
- package/src/bindings.js +298 -0
- package/src/browser/launcher.js +93 -0
- package/src/browser/navigation.js +513 -0
- package/src/core/constants.js +24 -0
- package/src/core/engine-adapter.js +466 -0
- package/src/core/engine-detection.js +49 -0
- package/src/core/logger.js +21 -0
- package/src/core/navigation-manager.js +503 -0
- package/src/core/navigation-safety.js +160 -0
- package/src/core/network-tracker.js +373 -0
- package/src/core/page-session.js +299 -0
- package/src/core/page-trigger-manager.js +564 -0
- package/src/core/preferences.js +46 -0
- package/src/elements/content.js +197 -0
- package/src/elements/locators.js +243 -0
- package/src/elements/selectors.js +360 -0
- package/src/elements/visibility.js +166 -0
- package/src/exports.js +121 -0
- package/src/factory.js +192 -0
- package/src/high-level/universal-logic.js +206 -0
- package/src/index.js +17 -0
- package/src/interactions/click.js +684 -0
- package/src/interactions/fill.js +383 -0
- package/src/interactions/scroll.js +341 -0
- package/src/utilities/url.js +33 -0
- package/src/utilities/wait.js +135 -0
- package/tests/e2e/playwright.e2e.test.js +442 -0
- package/tests/e2e/puppeteer.e2e.test.js +408 -0
- package/tests/helpers/mocks.js +542 -0
- package/tests/unit/bindings.test.js +218 -0
- package/tests/unit/browser/navigation.test.js +345 -0
- package/tests/unit/core/constants.test.js +72 -0
- package/tests/unit/core/engine-adapter.test.js +170 -0
- package/tests/unit/core/engine-detection.test.js +81 -0
- package/tests/unit/core/logger.test.js +80 -0
- package/tests/unit/core/navigation-safety.test.js +202 -0
- package/tests/unit/core/network-tracker.test.js +198 -0
- package/tests/unit/core/page-trigger-manager.test.js +358 -0
- package/tests/unit/elements/content.test.js +318 -0
- package/tests/unit/elements/locators.test.js +236 -0
- package/tests/unit/elements/selectors.test.js +302 -0
- package/tests/unit/elements/visibility.test.js +234 -0
- package/tests/unit/factory.test.js +174 -0
- package/tests/unit/high-level/universal-logic.test.js +299 -0
- package/tests/unit/interactions/click.test.js +340 -0
- package/tests/unit/interactions/fill.test.js +378 -0
- package/tests/unit/interactions/scroll.test.js +330 -0
- package/tests/unit/utilities/url.test.js +63 -0
- package/tests/unit/utilities/wait.test.js +207 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
body {
|
|
6
|
+
font-family:
|
|
7
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
|
8
|
+
sans-serif;
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 20px;
|
|
11
|
+
background: #f5f5f5;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.app {
|
|
15
|
+
max-width: 800px;
|
|
16
|
+
margin: 0 auto;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
h1 {
|
|
20
|
+
color: #333;
|
|
21
|
+
border-bottom: 2px solid #667eea;
|
|
22
|
+
padding-bottom: 10px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
h2 {
|
|
26
|
+
color: #555;
|
|
27
|
+
margin-top: 30px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.section {
|
|
31
|
+
background: white;
|
|
32
|
+
padding: 20px;
|
|
33
|
+
border-radius: 8px;
|
|
34
|
+
margin-bottom: 20px;
|
|
35
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.form-group {
|
|
39
|
+
margin-bottom: 15px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
label {
|
|
43
|
+
display: block;
|
|
44
|
+
margin-bottom: 5px;
|
|
45
|
+
font-weight: 500;
|
|
46
|
+
color: #333;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
input[type='text'],
|
|
50
|
+
input[type='email'],
|
|
51
|
+
input[type='password'],
|
|
52
|
+
textarea,
|
|
53
|
+
select {
|
|
54
|
+
width: 100%;
|
|
55
|
+
padding: 10px;
|
|
56
|
+
border: 1px solid #ddd;
|
|
57
|
+
border-radius: 4px;
|
|
58
|
+
font-size: 14px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
input[type='text']:focus,
|
|
62
|
+
input[type='email']:focus,
|
|
63
|
+
input[type='password']:focus,
|
|
64
|
+
textarea:focus,
|
|
65
|
+
select:focus {
|
|
66
|
+
outline: none;
|
|
67
|
+
border-color: #667eea;
|
|
68
|
+
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
textarea {
|
|
72
|
+
min-height: 100px;
|
|
73
|
+
resize: vertical;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
button {
|
|
77
|
+
padding: 10px 20px;
|
|
78
|
+
border: none;
|
|
79
|
+
border-radius: 4px;
|
|
80
|
+
font-size: 14px;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
transition: all 0.2s;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
button.primary {
|
|
86
|
+
background: #667eea;
|
|
87
|
+
color: white;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
button.primary:hover {
|
|
91
|
+
background: #5a6fd6;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
button.primary:disabled {
|
|
95
|
+
background: #ccc;
|
|
96
|
+
cursor: not-allowed;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
button.secondary {
|
|
100
|
+
background: #f0f0f0;
|
|
101
|
+
color: #333;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
button.secondary:hover {
|
|
105
|
+
background: #e0e0e0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
button.danger {
|
|
109
|
+
background: #dc3545;
|
|
110
|
+
color: white;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
button.danger:hover {
|
|
114
|
+
background: #c82333;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.checkbox-group,
|
|
118
|
+
.radio-group {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
gap: 10px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.checkbox-item,
|
|
125
|
+
.radio-item {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
gap: 8px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.checkbox-item input,
|
|
132
|
+
.radio-item input {
|
|
133
|
+
width: auto;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.button-group {
|
|
137
|
+
display: flex;
|
|
138
|
+
gap: 10px;
|
|
139
|
+
flex-wrap: wrap;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.result {
|
|
143
|
+
margin-top: 15px;
|
|
144
|
+
padding: 15px;
|
|
145
|
+
background: #f8f9fa;
|
|
146
|
+
border-radius: 4px;
|
|
147
|
+
border-left: 4px solid #667eea;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.result.success {
|
|
151
|
+
border-left-color: #28a745;
|
|
152
|
+
background: #d4edda;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.result.error {
|
|
156
|
+
border-left-color: #dc3545;
|
|
157
|
+
background: #f8d7da;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.toggle-container {
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
gap: 10px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.toggle {
|
|
167
|
+
position: relative;
|
|
168
|
+
width: 50px;
|
|
169
|
+
height: 26px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.toggle input {
|
|
173
|
+
opacity: 0;
|
|
174
|
+
width: 0;
|
|
175
|
+
height: 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.toggle-slider {
|
|
179
|
+
position: absolute;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
top: 0;
|
|
182
|
+
left: 0;
|
|
183
|
+
right: 0;
|
|
184
|
+
bottom: 0;
|
|
185
|
+
background-color: #ccc;
|
|
186
|
+
transition: 0.4s;
|
|
187
|
+
border-radius: 26px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.toggle-slider:before {
|
|
191
|
+
position: absolute;
|
|
192
|
+
content: '';
|
|
193
|
+
height: 20px;
|
|
194
|
+
width: 20px;
|
|
195
|
+
left: 3px;
|
|
196
|
+
bottom: 3px;
|
|
197
|
+
background-color: white;
|
|
198
|
+
transition: 0.4s;
|
|
199
|
+
border-radius: 50%;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.toggle input:checked + .toggle-slider {
|
|
203
|
+
background-color: #667eea;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.toggle input:checked + .toggle-slider:before {
|
|
207
|
+
transform: translateX(24px);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.counter {
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
gap: 15px;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.counter-value {
|
|
217
|
+
font-size: 24px;
|
|
218
|
+
font-weight: bold;
|
|
219
|
+
min-width: 50px;
|
|
220
|
+
text-align: center;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.hidden {
|
|
224
|
+
display: none;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.modal-overlay {
|
|
228
|
+
position: fixed;
|
|
229
|
+
top: 0;
|
|
230
|
+
left: 0;
|
|
231
|
+
right: 0;
|
|
232
|
+
bottom: 0;
|
|
233
|
+
background: rgba(0, 0, 0, 0.5);
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
z-index: 1000;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.modal {
|
|
241
|
+
background: white;
|
|
242
|
+
padding: 30px;
|
|
243
|
+
border-radius: 8px;
|
|
244
|
+
max-width: 400px;
|
|
245
|
+
width: 90%;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.modal h3 {
|
|
249
|
+
margin-top: 0;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.modal-buttons {
|
|
253
|
+
display: flex;
|
|
254
|
+
justify-content: flex-end;
|
|
255
|
+
gap: 10px;
|
|
256
|
+
margin-top: 20px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.dropdown {
|
|
260
|
+
position: relative;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.dropdown-menu {
|
|
264
|
+
position: absolute;
|
|
265
|
+
top: 100%;
|
|
266
|
+
left: 0;
|
|
267
|
+
background: white;
|
|
268
|
+
border: 1px solid #ddd;
|
|
269
|
+
border-radius: 4px;
|
|
270
|
+
min-width: 150px;
|
|
271
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
272
|
+
z-index: 100;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.dropdown-menu button {
|
|
276
|
+
display: block;
|
|
277
|
+
width: 100%;
|
|
278
|
+
text-align: left;
|
|
279
|
+
padding: 10px 15px;
|
|
280
|
+
border: none;
|
|
281
|
+
background: none;
|
|
282
|
+
cursor: pointer;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.dropdown-menu button:hover {
|
|
286
|
+
background: #f5f5f5;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.scroll-test {
|
|
290
|
+
height: 300px;
|
|
291
|
+
overflow-y: auto;
|
|
292
|
+
border: 1px solid #ddd;
|
|
293
|
+
border-radius: 4px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.scroll-test .scroll-item {
|
|
297
|
+
padding: 20px;
|
|
298
|
+
border-bottom: 1px solid #eee;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.scroll-test .scroll-item:last-child {
|
|
302
|
+
border-bottom: none;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.scroll-test .scroll-item.target {
|
|
306
|
+
background: #e8f4f8;
|
|
307
|
+
border-left: 4px solid #667eea;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@keyframes fadeIn {
|
|
311
|
+
from {
|
|
312
|
+
opacity: 0;
|
|
313
|
+
transform: translateY(-10px);
|
|
314
|
+
}
|
|
315
|
+
to {
|
|
316
|
+
opacity: 1;
|
|
317
|
+
transform: translateY(0);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.animated {
|
|
322
|
+
animation: fadeIn 0.3s ease-out;
|
|
323
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "browser-commander",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Universal browser automation library that supports both Playwright and Puppeteer with a unified API",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node --test --test-reporter spec tests/unit/",
|
|
12
|
+
"test:unit": "node --test --test-reporter spec tests/unit/",
|
|
13
|
+
"test:coverage": "node --test --experimental-test-coverage tests/unit/",
|
|
14
|
+
"test:e2e": "RUN_E2E=true node --test tests/e2e/",
|
|
15
|
+
"test:e2e:playwright": "RUN_E2E=true node --test tests/e2e/playwright.e2e.test.js",
|
|
16
|
+
"test:e2e:puppeteer": "RUN_E2E=true node --test tests/e2e/puppeteer.e2e.test.js",
|
|
17
|
+
"test:all": "npm run test:unit && npm run test:e2e",
|
|
18
|
+
"lint": "eslint .",
|
|
19
|
+
"lint:fix": "eslint . --fix",
|
|
20
|
+
"format": "prettier --write .",
|
|
21
|
+
"format:check": "prettier --check .",
|
|
22
|
+
"check:duplication": "jscpd .",
|
|
23
|
+
"check": "npm run lint && npm run format:check && npm run check:duplication",
|
|
24
|
+
"prepare": "husky || true",
|
|
25
|
+
"changeset": "changeset",
|
|
26
|
+
"changeset:version": "node scripts/changeset-version.mjs",
|
|
27
|
+
"changeset:publish": "changeset publish",
|
|
28
|
+
"changeset:status": "changeset status --since=origin/main"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/link-foundation/browser-commander.git"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"browser",
|
|
36
|
+
"automation",
|
|
37
|
+
"playwright",
|
|
38
|
+
"puppeteer",
|
|
39
|
+
"testing",
|
|
40
|
+
"e2e"
|
|
41
|
+
],
|
|
42
|
+
"author": "",
|
|
43
|
+
"license": "UNLICENSE",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/link-foundation/browser-commander/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/link-foundation/browser-commander#readme",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=20.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"playwright": ">=1.40.0",
|
|
53
|
+
"puppeteer": ">=21.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"playwright": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"puppeteer": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"log-lazy": "^1.0.4"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@changesets/cli": "^2.29.7",
|
|
68
|
+
"eslint": "^9.39.0",
|
|
69
|
+
"eslint-config-prettier": "^10.1.8",
|
|
70
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
71
|
+
"husky": "^9.1.7",
|
|
72
|
+
"jscpd": "^4.0.5",
|
|
73
|
+
"lint-staged": "^16.2.6",
|
|
74
|
+
"playwright": "^1.56.1",
|
|
75
|
+
"prettier": "^3.6.2",
|
|
76
|
+
"puppeteer": "^24.27.0"
|
|
77
|
+
},
|
|
78
|
+
"lint-staged": {
|
|
79
|
+
"*.{js,mjs,cjs}": [
|
|
80
|
+
"eslint --fix",
|
|
81
|
+
"prettier --write",
|
|
82
|
+
"prettier --check"
|
|
83
|
+
],
|
|
84
|
+
"*.md": [
|
|
85
|
+
"prettier --write",
|
|
86
|
+
"prettier --check"
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom changeset version script that ensures package-lock.json is synchronized
|
|
5
|
+
* with package.json after version bumps.
|
|
6
|
+
*
|
|
7
|
+
* This script:
|
|
8
|
+
* 1. Runs `changeset version` to update package versions
|
|
9
|
+
* 2. Runs `npm install` to synchronize package-lock.json with the new versions
|
|
10
|
+
*
|
|
11
|
+
* Uses link-foundation libraries:
|
|
12
|
+
* - use-m: Dynamic package loading without package.json dependencies
|
|
13
|
+
* - command-stream: Modern shell command execution with streaming support
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Load use-m dynamically
|
|
17
|
+
const { use } = eval(
|
|
18
|
+
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Import command-stream for shell command execution
|
|
22
|
+
const { $ } = await use('command-stream');
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
console.log('Running changeset version...');
|
|
26
|
+
await $`npx changeset version`;
|
|
27
|
+
|
|
28
|
+
console.log('\nSynchronizing package-lock.json...');
|
|
29
|
+
await $`npm install --package-lock-only`;
|
|
30
|
+
|
|
31
|
+
console.log('\n✅ Version bump complete with synchronized package-lock.json');
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error('Error during version bump:', error.message);
|
|
34
|
+
if (process.env.DEBUG) {
|
|
35
|
+
console.error('Stack trace:', error.stack);
|
|
36
|
+
}
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create GitHub Release from CHANGELOG.md
|
|
5
|
+
* Usage: node scripts/create-github-release.mjs --release-version <version> --repository <repository>
|
|
6
|
+
* release-version: Version number (e.g., 1.0.0)
|
|
7
|
+
* repository: GitHub repository (e.g., owner/repo)
|
|
8
|
+
*
|
|
9
|
+
* Uses link-foundation libraries:
|
|
10
|
+
* - use-m: Dynamic package loading without package.json dependencies
|
|
11
|
+
* - command-stream: Modern shell command execution with streaming support
|
|
12
|
+
* - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync } from 'fs';
|
|
16
|
+
|
|
17
|
+
// Load use-m dynamically
|
|
18
|
+
const { use } = eval(
|
|
19
|
+
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// Import link-foundation libraries
|
|
23
|
+
const { $ } = await use('command-stream');
|
|
24
|
+
const { makeConfig } = await use('lino-arguments');
|
|
25
|
+
|
|
26
|
+
// Parse CLI arguments using lino-arguments
|
|
27
|
+
// Note: Using --release-version instead of --version to avoid conflict with yargs' built-in --version flag
|
|
28
|
+
const config = makeConfig({
|
|
29
|
+
yargs: ({ yargs, getenv }) =>
|
|
30
|
+
yargs
|
|
31
|
+
.option('release-version', {
|
|
32
|
+
type: 'string',
|
|
33
|
+
default: getenv('VERSION', ''),
|
|
34
|
+
describe: 'Version number (e.g., 1.0.0)',
|
|
35
|
+
})
|
|
36
|
+
.option('repository', {
|
|
37
|
+
type: 'string',
|
|
38
|
+
default: getenv('REPOSITORY', ''),
|
|
39
|
+
describe: 'GitHub repository (e.g., owner/repo)',
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const { releaseVersion: version, repository } = config;
|
|
44
|
+
|
|
45
|
+
if (!version || !repository) {
|
|
46
|
+
console.error('Error: Missing required arguments');
|
|
47
|
+
console.error(
|
|
48
|
+
'Usage: node scripts/create-github-release.mjs --release-version <version> --repository <repository>'
|
|
49
|
+
);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const tag = `v${version}`;
|
|
54
|
+
|
|
55
|
+
console.log(`Creating GitHub release for ${tag}...`);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Read CHANGELOG.md
|
|
59
|
+
const changelog = readFileSync('./CHANGELOG.md', 'utf8');
|
|
60
|
+
|
|
61
|
+
// Extract changelog entry for this version
|
|
62
|
+
// Read from CHANGELOG.md between this version header and the next version header
|
|
63
|
+
const versionHeaderRegex = new RegExp(`## ${version}[\\s\\S]*?(?=## \\d|$)`);
|
|
64
|
+
const match = changelog.match(versionHeaderRegex);
|
|
65
|
+
|
|
66
|
+
let releaseNotes = '';
|
|
67
|
+
if (match) {
|
|
68
|
+
// Remove the version header itself and trim
|
|
69
|
+
releaseNotes = match[0].replace(`## ${version}`, '').trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!releaseNotes) {
|
|
73
|
+
releaseNotes = `Release ${version}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Create release using GitHub API with JSON input
|
|
77
|
+
// This avoids shell escaping issues that occur when passing text via command-line arguments
|
|
78
|
+
// (Previously caused apostrophes like "didn't" to appear as "didn'''" in releases)
|
|
79
|
+
const payload = JSON.stringify({
|
|
80
|
+
tag_name: tag,
|
|
81
|
+
name: version,
|
|
82
|
+
body: releaseNotes,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await $`gh api repos/${repository}/releases -X POST --input -`.run({
|
|
86
|
+
stdin: payload,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log(`\u2705 Created GitHub release: ${tag}`);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Error creating release:', error.message);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a changeset file for manual releases
|
|
5
|
+
* Usage: node scripts/create-manual-changeset.mjs --bump-type <major|minor|patch> [--description <description>]
|
|
6
|
+
*
|
|
7
|
+
* Uses link-foundation libraries:
|
|
8
|
+
* - use-m: Dynamic package loading without package.json dependencies
|
|
9
|
+
* - command-stream: Modern shell command execution with streaming support
|
|
10
|
+
* - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { writeFileSync } from 'fs';
|
|
14
|
+
import { randomBytes } from 'crypto';
|
|
15
|
+
|
|
16
|
+
const PACKAGE_NAME = 'browser-commander';
|
|
17
|
+
|
|
18
|
+
// Load use-m dynamically
|
|
19
|
+
const { use } = eval(
|
|
20
|
+
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Import link-foundation libraries
|
|
24
|
+
const { $ } = await use('command-stream');
|
|
25
|
+
const { makeConfig } = await use('lino-arguments');
|
|
26
|
+
|
|
27
|
+
// Parse CLI arguments using lino-arguments
|
|
28
|
+
const config = makeConfig({
|
|
29
|
+
yargs: ({ yargs, getenv }) =>
|
|
30
|
+
yargs
|
|
31
|
+
.option('bump-type', {
|
|
32
|
+
type: 'string',
|
|
33
|
+
default: getenv('BUMP_TYPE', ''),
|
|
34
|
+
describe: 'Version bump type: major, minor, or patch',
|
|
35
|
+
choices: ['major', 'minor', 'patch'],
|
|
36
|
+
})
|
|
37
|
+
.option('description', {
|
|
38
|
+
type: 'string',
|
|
39
|
+
default: getenv('DESCRIPTION', ''),
|
|
40
|
+
describe: 'Description for the changeset',
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const { bumpType, description: descriptionArg } = config;
|
|
46
|
+
|
|
47
|
+
// Use provided description or default based on bump type
|
|
48
|
+
const description = descriptionArg || `Manual ${bumpType} release`;
|
|
49
|
+
|
|
50
|
+
if (!bumpType || !['major', 'minor', 'patch'].includes(bumpType)) {
|
|
51
|
+
console.error(
|
|
52
|
+
'Usage: node scripts/create-manual-changeset.mjs --bump-type <major|minor|patch> [--description <description>]'
|
|
53
|
+
);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Generate a random changeset ID
|
|
58
|
+
const changesetId = randomBytes(4).toString('hex');
|
|
59
|
+
const changesetFile = `.changeset/manual-release-${changesetId}.md`;
|
|
60
|
+
|
|
61
|
+
// Create the changeset file with single quotes to match Prettier config
|
|
62
|
+
const content = `---
|
|
63
|
+
'${PACKAGE_NAME}': ${bumpType}
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
${description}
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
writeFileSync(changesetFile, content, 'utf-8');
|
|
70
|
+
|
|
71
|
+
console.log(`Created changeset: ${changesetFile}`);
|
|
72
|
+
console.log('Content:');
|
|
73
|
+
console.log(content);
|
|
74
|
+
|
|
75
|
+
// Format with Prettier
|
|
76
|
+
console.log('\nFormatting with Prettier...');
|
|
77
|
+
await $`npx prettier --write "${changesetFile}"`;
|
|
78
|
+
|
|
79
|
+
console.log('\n✅ Changeset created and formatted successfully');
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('Error creating changeset:', error.message);
|
|
82
|
+
if (process.env.DEBUG) {
|
|
83
|
+
console.error('Stack trace:', error.stack);
|
|
84
|
+
}
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|