extension-create 3.7.0 → 3.8.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/dist/module.cjs +80 -150
- package/package.json +4 -7
package/dist/module.cjs
CHANGED
|
@@ -202,23 +202,6 @@ function cantSetupBuiltInTests(projectName, error) {
|
|
|
202
202
|
return `${external_pintor_default().red('Error')} Couldn't set up built-in tests for ${external_pintor_default().yellow(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: run the setup step again or skip tests.')}`;
|
|
203
203
|
}
|
|
204
204
|
const promises_namespaceObject = require("fs/promises");
|
|
205
|
-
async function copyDirectoryWithSymlinks(source, destination) {
|
|
206
|
-
const entries = await promises_namespaceObject.readdir(source, {
|
|
207
|
-
withFileTypes: true
|
|
208
|
-
});
|
|
209
|
-
await promises_namespaceObject.mkdir(destination, {
|
|
210
|
-
recursive: true
|
|
211
|
-
});
|
|
212
|
-
for (const entry of entries){
|
|
213
|
-
const sourcePath = external_path_namespaceObject.join(source, entry.name);
|
|
214
|
-
const destPath = external_path_namespaceObject.join(destination, entry.name);
|
|
215
|
-
if (entry.isDirectory()) await copyDirectoryWithSymlinks(sourcePath, destPath);
|
|
216
|
-
else if (entry.isSymbolicLink()) {
|
|
217
|
-
const target = await promises_namespaceObject.readlink(sourcePath);
|
|
218
|
-
await promises_namespaceObject.symlink(target, destPath);
|
|
219
|
-
} else await promises_namespaceObject.copyFile(sourcePath, destPath);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
205
|
async function moveDirectoryContents(source, destination) {
|
|
223
206
|
await promises_namespaceObject.mkdir(destination, {
|
|
224
207
|
recursive: true
|
|
@@ -230,10 +213,18 @@ async function moveDirectoryContents(source, destination) {
|
|
|
230
213
|
const sourcePath = external_path_namespaceObject.join(source, entry.name);
|
|
231
214
|
const destPath = external_path_namespaceObject.join(destination, entry.name);
|
|
232
215
|
if (entry.isDirectory()) await moveDirectoryContents(sourcePath, destPath);
|
|
233
|
-
else if (entry.isSymbolicLink()) {
|
|
216
|
+
else if (entry.isSymbolicLink()) try {
|
|
234
217
|
const target = await promises_namespaceObject.readlink(sourcePath);
|
|
235
218
|
await promises_namespaceObject.symlink(target, destPath);
|
|
236
|
-
}
|
|
219
|
+
} catch (err) {
|
|
220
|
+
if (err?.code === 'EPERM' || err?.code === 'ENOTSUP') {
|
|
221
|
+
const real = await promises_namespaceObject.realpath(sourcePath);
|
|
222
|
+
await promises_namespaceObject.cp(real, destPath, {
|
|
223
|
+
recursive: true
|
|
224
|
+
});
|
|
225
|
+
} else throw err;
|
|
226
|
+
}
|
|
227
|
+
else try {
|
|
237
228
|
await promises_namespaceObject.rename(sourcePath, destPath);
|
|
238
229
|
} catch (err) {
|
|
239
230
|
if (err && ('EXDEV' === err.code || 'EINVAL' === err.code)) {
|
|
@@ -294,7 +285,6 @@ async function createDirectory(projectPath, projectName) {
|
|
|
294
285
|
throw new Error(createDirectoryError(projectName, error));
|
|
295
286
|
}
|
|
296
287
|
}
|
|
297
|
-
const external_url_namespaceObject = require("url");
|
|
298
288
|
const external_os_namespaceObject = require("os");
|
|
299
289
|
const external_axios_namespaceObject = require("axios");
|
|
300
290
|
var external_axios_default = /*#__PURE__*/ __webpack_require__.n(external_axios_namespaceObject);
|
|
@@ -302,149 +292,89 @@ const external_adm_zip_namespaceObject = require("adm-zip");
|
|
|
302
292
|
var external_adm_zip_default = /*#__PURE__*/ __webpack_require__.n(external_adm_zip_namespaceObject);
|
|
303
293
|
const external_go_git_it_namespaceObject = require("go-git-it");
|
|
304
294
|
var external_go_git_it_default = /*#__PURE__*/ __webpack_require__.n(external_go_git_it_namespaceObject);
|
|
305
|
-
|
|
306
|
-
const
|
|
295
|
+
async function withSuppressedOutput(task) {
|
|
296
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
297
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
298
|
+
process.stdout.write = ()=>true;
|
|
299
|
+
process.stderr.write = ()=>true;
|
|
300
|
+
try {
|
|
301
|
+
return await task();
|
|
302
|
+
} finally{
|
|
303
|
+
process.stdout.write = originalStdoutWrite;
|
|
304
|
+
process.stderr.write = originalStderrWrite;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function getArchiveBaseName(url) {
|
|
308
|
+
const withoutQuery = url.split('?')[0];
|
|
309
|
+
const fileName = external_path_namespaceObject.basename(withoutQuery);
|
|
310
|
+
if (!fileName.toLowerCase().endsWith('.zip')) return fileName;
|
|
311
|
+
return fileName.slice(0, -4);
|
|
312
|
+
}
|
|
313
|
+
async function getZipSourcePath(tempPath, templateUrl) {
|
|
314
|
+
const archiveBase = getArchiveBaseName(templateUrl);
|
|
315
|
+
let entries = [];
|
|
316
|
+
try {
|
|
317
|
+
entries = await promises_namespaceObject.readdir(tempPath, {
|
|
318
|
+
withFileTypes: true
|
|
319
|
+
});
|
|
320
|
+
} catch {
|
|
321
|
+
return tempPath;
|
|
322
|
+
}
|
|
323
|
+
const dirs = entries.filter((entry)=>entry.isDirectory());
|
|
324
|
+
if (1 !== dirs.length) return tempPath;
|
|
325
|
+
const onlyDir = dirs[0];
|
|
326
|
+
if (onlyDir.name === archiveBase) return external_path_namespaceObject.join(tempPath, onlyDir.name);
|
|
327
|
+
return tempPath;
|
|
328
|
+
}
|
|
307
329
|
async function importExternalTemplate(projectPath, projectName, template) {
|
|
308
330
|
const templateName = external_path_namespaceObject.basename(template);
|
|
309
331
|
const examplesUrl = 'https://github.com/extension-js/examples/tree/main/examples';
|
|
310
332
|
const resolvedTemplate = 'init' === templateName ? "javascript" : template;
|
|
311
333
|
const resolvedTemplateName = 'init' === templateName ? "javascript" : templateName;
|
|
312
334
|
const templateUrl = `${examplesUrl}/${resolvedTemplate}`;
|
|
313
|
-
const examplesZipUrl = 'https://codeload.github.com/extension-js/examples/zip/refs/heads/main';
|
|
314
335
|
try {
|
|
315
336
|
await promises_namespaceObject.mkdir(projectPath, {
|
|
316
337
|
recursive: true
|
|
317
338
|
});
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
const localTemplatesRoot = await findTemplatesRoot(import_external_template_dirname);
|
|
335
|
-
if (!localTemplatesRoot) throw new Error('Local templates directory not found');
|
|
336
|
-
const localTemplatePath = external_path_namespaceObject.join(localTemplatesRoot, resolvedTemplateName);
|
|
337
|
-
await copyDirectoryWithSymlinks(localTemplatePath, projectPath);
|
|
338
|
-
} else {
|
|
339
|
-
const tempRoot = await promises_namespaceObject.mkdtemp(external_path_namespaceObject.join(external_os_namespaceObject.tmpdir(), 'extension-js-create-'));
|
|
340
|
-
const tempPath = external_path_namespaceObject.join(tempRoot, projectName + '-temp');
|
|
341
|
-
await promises_namespaceObject.mkdir(tempPath, {
|
|
342
|
-
recursive: true
|
|
339
|
+
const tempRoot = await promises_namespaceObject.mkdtemp(external_path_namespaceObject.join(external_os_namespaceObject.tmpdir(), 'extension-js-create-'));
|
|
340
|
+
const tempPath = external_path_namespaceObject.join(tempRoot, projectName + '-temp');
|
|
341
|
+
await promises_namespaceObject.mkdir(tempPath, {
|
|
342
|
+
recursive: true
|
|
343
|
+
});
|
|
344
|
+
const isHttp = /^https?:\/\//i.test(template);
|
|
345
|
+
const isGithub = /^https?:\/\/github.com\//i.test(template);
|
|
346
|
+
const runGoGitIt = async (templatePath, destination)=>{
|
|
347
|
+
await withSuppressedOutput(async ()=>external_go_git_it_default()(templatePath, destination, installingFromTemplate(projectName, templateName)));
|
|
348
|
+
};
|
|
349
|
+
if (isGithub) {
|
|
350
|
+
await runGoGitIt(template, tempPath);
|
|
351
|
+
const candidates = await promises_namespaceObject.readdir(tempPath, {
|
|
352
|
+
withFileTypes: true
|
|
343
353
|
});
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
};
|
|
352
|
-
const stderrBuffer = {
|
|
353
|
-
value: ''
|
|
354
|
-
};
|
|
355
|
-
let suppressGoGitItStack = false;
|
|
356
|
-
const toText = (chunk)=>'string' == typeof chunk ? chunk : chunk?.toString?.() ?? '';
|
|
357
|
-
const shouldFilterLine = (line)=>{
|
|
358
|
-
if (!line) return false;
|
|
359
|
-
const trimmed = line.trim();
|
|
360
|
-
if (!trimmed) return false;
|
|
361
|
-
if (/Using git version/i.test(line) || /GitHub API rate limit reached, continuing without connectivity check/i.test(line) || /^Downloading extension\b/i.test(trimmed) || /^URL https?:\/\/codeload\.github\.com\/extension-js\/examples\/zip\/refs\/heads\/main\b/i.test(trimmed) || /^\[[=\s]+\]\s*\d+%/i.test(trimmed)) {
|
|
362
|
-
suppressGoGitItStack = true;
|
|
363
|
-
return true;
|
|
364
|
-
}
|
|
365
|
-
if (suppressGoGitItStack && /^\s+at\b/.test(line)) return true;
|
|
366
|
-
if (suppressGoGitItStack && !/^\s+at\b/.test(line)) suppressGoGitItStack = false;
|
|
367
|
-
return false;
|
|
368
|
-
};
|
|
369
|
-
const writeWithFilter = (originalWrite, buffer)=>(chunk, ...args)=>{
|
|
370
|
-
const text = buffer.value + toText(chunk);
|
|
371
|
-
if (!text) return true;
|
|
372
|
-
const parts = text.split(/\r?\n|\r/);
|
|
373
|
-
buffer.value = parts.pop() ?? '';
|
|
374
|
-
if (0 === parts.length) return true;
|
|
375
|
-
const kept = [];
|
|
376
|
-
for (const line of parts)if (!shouldFilterLine(line)) kept.push(line);
|
|
377
|
-
if (0 === kept.length) return true;
|
|
378
|
-
return originalWrite(kept.join('\n') + '\n', ...args);
|
|
379
|
-
};
|
|
380
|
-
process.stdout.write = writeWithFilter(originalStdoutWrite, stdoutBuffer);
|
|
381
|
-
process.stderr.write = writeWithFilter(originalStderrWrite, stderrBuffer);
|
|
382
|
-
try {
|
|
383
|
-
return await fn();
|
|
384
|
-
} finally{
|
|
385
|
-
process.stdout.write = originalStdoutWrite;
|
|
386
|
-
process.stderr.write = originalStderrWrite;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
if (isGithub) {
|
|
390
|
-
await withFilteredOutput(()=>external_go_git_it_default()(template, tempPath, installingFromTemplate(projectName, templateName)));
|
|
391
|
-
const candidates = await promises_namespaceObject.readdir(tempPath, {
|
|
392
|
-
withFileTypes: true
|
|
393
|
-
});
|
|
394
|
-
const preferred = candidates.find((d)=>d.isDirectory() && d.name === templateName);
|
|
395
|
-
const srcPath = preferred ? external_path_namespaceObject.join(tempPath, templateName) : tempPath;
|
|
396
|
-
await moveDirectoryContents(srcPath, projectPath);
|
|
397
|
-
} else if (isHttp) {
|
|
398
|
-
const { data, headers } = await external_axios_default().get(template, {
|
|
399
|
-
responseType: 'arraybuffer',
|
|
400
|
-
maxRedirects: 5
|
|
401
|
-
});
|
|
402
|
-
const contentType = String(headers?.['content-type'] || '');
|
|
403
|
-
const looksZip = /zip|octet-stream/i.test(contentType) || template.toLowerCase().endsWith('.zip');
|
|
404
|
-
if (!looksZip) throw new Error(`Remote template does not appear to be a ZIP archive: ${template}`);
|
|
405
|
-
const zip = new (external_adm_zip_default())(Buffer.from(data));
|
|
406
|
-
zip.extractAllTo(tempPath, true);
|
|
407
|
-
await moveDirectoryContents(tempPath, projectPath);
|
|
408
|
-
} else {
|
|
409
|
-
const ok = await (async ()=>{
|
|
410
|
-
const zipExtractRoot = external_path_namespaceObject.join(tempPath, 'zip-extract');
|
|
411
|
-
try {
|
|
412
|
-
const { data } = await external_axios_default().get(examplesZipUrl, {
|
|
413
|
-
responseType: 'arraybuffer',
|
|
414
|
-
maxRedirects: 5
|
|
415
|
-
});
|
|
416
|
-
const zip = new (external_adm_zip_default())(Buffer.from(data));
|
|
417
|
-
zip.extractAllTo(zipExtractRoot, true);
|
|
418
|
-
const entries = await promises_namespaceObject.readdir(zipExtractRoot, {
|
|
419
|
-
withFileTypes: true
|
|
420
|
-
});
|
|
421
|
-
const rootDir = entries.find((e)=>e.isDirectory())?.name;
|
|
422
|
-
if (!rootDir) return false;
|
|
423
|
-
const srcPath = external_path_namespaceObject.join(zipExtractRoot, rootDir, 'examples', resolvedTemplateName);
|
|
424
|
-
await moveDirectoryContents(srcPath, projectPath);
|
|
425
|
-
return true;
|
|
426
|
-
} catch {
|
|
427
|
-
return false;
|
|
428
|
-
} finally{
|
|
429
|
-
try {
|
|
430
|
-
await promises_namespaceObject.rm(zipExtractRoot, {
|
|
431
|
-
recursive: true,
|
|
432
|
-
force: true
|
|
433
|
-
});
|
|
434
|
-
} catch {}
|
|
435
|
-
}
|
|
436
|
-
})();
|
|
437
|
-
if (!ok) {
|
|
438
|
-
await withFilteredOutput(()=>external_go_git_it_default()(templateUrl, tempPath, installingFromTemplate(projectName, templateName)));
|
|
439
|
-
const srcPath = external_path_namespaceObject.join(tempPath, resolvedTemplateName);
|
|
440
|
-
await moveDirectoryContents(srcPath, projectPath);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
await promises_namespaceObject.rm(tempRoot, {
|
|
444
|
-
recursive: true,
|
|
445
|
-
force: true
|
|
354
|
+
const preferred = candidates.find((d)=>d.isDirectory() && d.name === templateName);
|
|
355
|
+
const srcPath = preferred ? external_path_namespaceObject.join(tempPath, templateName) : tempPath;
|
|
356
|
+
await moveDirectoryContents(srcPath, projectPath);
|
|
357
|
+
} else if (isHttp) {
|
|
358
|
+
const { data, headers } = await external_axios_default().get(template, {
|
|
359
|
+
responseType: 'arraybuffer',
|
|
360
|
+
maxRedirects: 5
|
|
446
361
|
});
|
|
362
|
+
const contentType = String(headers?.['content-type'] || '');
|
|
363
|
+
const looksZip = /zip|octet-stream/i.test(contentType) || template.toLowerCase().endsWith('.zip');
|
|
364
|
+
if (!looksZip) throw new Error(`Remote template does not appear to be a ZIP archive: ${template}`);
|
|
365
|
+
const zip = new (external_adm_zip_default())(Buffer.from(data));
|
|
366
|
+
zip.extractAllTo(tempPath, true);
|
|
367
|
+
const sourcePath = await getZipSourcePath(tempPath, template);
|
|
368
|
+
await moveDirectoryContents(sourcePath, projectPath);
|
|
369
|
+
} else {
|
|
370
|
+
await runGoGitIt(templateUrl, tempPath);
|
|
371
|
+
const srcPath = external_path_namespaceObject.join(tempPath, resolvedTemplateName);
|
|
372
|
+
await moveDirectoryContents(srcPath, projectPath);
|
|
447
373
|
}
|
|
374
|
+
await promises_namespaceObject.rm(tempRoot, {
|
|
375
|
+
recursive: true,
|
|
376
|
+
force: true
|
|
377
|
+
});
|
|
448
378
|
} catch (error) {
|
|
449
379
|
console.error(installingFromTemplateError(projectName, templateName, error));
|
|
450
380
|
throw error;
|
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"name": "extension-create",
|
|
26
|
-
"version": "3.
|
|
26
|
+
"version": "3.8.0",
|
|
27
27
|
"description": "The standalone extension creation engine for Extension.js",
|
|
28
28
|
"author": {
|
|
29
29
|
"name": "Cezar Augusto",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"clean": "rm -rf dist",
|
|
43
43
|
"watch": "rslib build --watch",
|
|
44
44
|
"compile": "rslib build",
|
|
45
|
-
"format": "
|
|
46
|
-
"lint": "
|
|
45
|
+
"format": "biome format --write .",
|
|
46
|
+
"lint": "biome lint .",
|
|
47
47
|
"pretest:create": "pnpm compile",
|
|
48
48
|
"test:create": "vitest run",
|
|
49
49
|
"test:coverage": "vitest run --coverage"
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
"tiny-glob": "^0.2.9"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
|
+
"@biomejs/biome": "^2.2.4",
|
|
82
83
|
"@changesets/cli": "^2.29.8",
|
|
83
|
-
"@eslint/js": "^9.39.2",
|
|
84
84
|
"@rslib/core": "^0.19.4",
|
|
85
85
|
"@types/adm-zip": "^0.5.7",
|
|
86
86
|
"@types/chrome": "^0.1.33",
|
|
@@ -88,9 +88,6 @@
|
|
|
88
88
|
"@types/node": "^25.2.0",
|
|
89
89
|
"@types/webextension-polyfill": "0.12.4",
|
|
90
90
|
"@vitest/coverage-v8": "^4.0.17",
|
|
91
|
-
"eslint": "^9.39.2",
|
|
92
|
-
"globals": "^17.3.0",
|
|
93
|
-
"prettier": "^3.8.0",
|
|
94
91
|
"tsconfig": "*",
|
|
95
92
|
"typescript": "5.9.3",
|
|
96
93
|
"vitest": "^4.0.17",
|