@saeroon/cli 0.2.7 → 0.2.8
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/index.js +181 -37
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2514,19 +2514,27 @@ var ELEMENT_TYPE_PROPS = {
|
|
|
2514
2514
|
"pre",
|
|
2515
2515
|
"code",
|
|
2516
2516
|
"progress",
|
|
2517
|
-
"meter"
|
|
2517
|
+
"meter",
|
|
2518
|
+
"output",
|
|
2519
|
+
"label",
|
|
2520
|
+
"search",
|
|
2521
|
+
"time",
|
|
2522
|
+
"mark",
|
|
2523
|
+
"abbr"
|
|
2518
2524
|
]),
|
|
2519
2525
|
coerce: () => null
|
|
2520
2526
|
}
|
|
2521
2527
|
};
|
|
2522
2528
|
var VALID_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
2523
|
-
// Primitives (
|
|
2529
|
+
// Primitives (13)
|
|
2524
2530
|
"container",
|
|
2525
2531
|
"text-block",
|
|
2532
|
+
"rich-text-block",
|
|
2526
2533
|
"heading-block",
|
|
2527
2534
|
"button-block",
|
|
2528
2535
|
"image-block",
|
|
2529
2536
|
"video-block",
|
|
2537
|
+
"audio-block",
|
|
2530
2538
|
"embed-block",
|
|
2531
2539
|
"icon-block",
|
|
2532
2540
|
"input-block",
|
|
@@ -4032,32 +4040,43 @@ var EXTRACTION_SCRIPT = `
|
|
|
4032
4040
|
let expanded = false;
|
|
4033
4041
|
els.forEach(el => {
|
|
4034
4042
|
const tag = el.tagName.toLowerCase();
|
|
4035
|
-
//
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4043
|
+
// \uC2DC\uB9E8\uD2F1 \uD0DC\uADF8: header/footer/nav/section/article/aside\uB294 \uC139\uC158\uC73C\uB85C \uC720\uC9C0
|
|
4044
|
+
const keepTags = new Set(['header', 'footer', 'nav', 'section', 'article', 'aside']);
|
|
4045
|
+
// main/form\uC740 \uB798\uD37C \uC5ED\uD560\uC774 \uB9CE\uC74C \u2014 \uC790\uC2DD\uC774 \uC5EC\uB7EC \uAC1C\uBA74 \uD3BC\uCE68
|
|
4046
|
+
const unwrapTags = new Set(['main', 'form']);
|
|
4047
|
+
|
|
4048
|
+
if (keepTags.has(tag)) {
|
|
4049
|
+
result.push(el);
|
|
4050
|
+
return;
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
const children = Array.from(el.children).filter(c => c.getBoundingClientRect().height >= 10);
|
|
4054
|
+
|
|
4055
|
+
if (unwrapTags.has(tag)) {
|
|
4056
|
+
// main/form: \uC790\uC2DD\uC774 \uC5EC\uB7EC \uAC1C\uBA74 \uD3BC\uCE68
|
|
4057
|
+
if (children.length > 1) {
|
|
4058
|
+
result.push(...children);
|
|
4059
|
+
expanded = true;
|
|
4046
4060
|
} else {
|
|
4047
4061
|
result.push(el);
|
|
4048
4062
|
}
|
|
4049
4063
|
return;
|
|
4050
4064
|
}
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
if (children.length
|
|
4054
|
-
// \uB2E8\uC77C \uC790\uC2DD wrapper \u2192 \uBC97\uAE40
|
|
4055
|
-
result.push(...children);
|
|
4056
|
-
expanded = true;
|
|
4057
|
-
} else if (children.length > 1 && depth >= 4) {
|
|
4058
|
-
// \uAE4A\uC774 \uC0C1\uC704 2\uB2E8\uACC4(depth 5\u21924)\uC5D0\uC11C\uB9CC multi-child \uD655\uC7A5
|
|
4065
|
+
|
|
4066
|
+
// div \uB4F1 \uBE44\uC2DC\uB9E8\uD2F1 \uB798\uD37C \uBC97\uAE30\uAE30
|
|
4067
|
+
if (children.length <= 1 && children.length > 0) {
|
|
4059
4068
|
result.push(...children);
|
|
4060
4069
|
expanded = true;
|
|
4070
|
+
} else if (children.length > 1) {
|
|
4071
|
+
// \uD398\uC774\uC9C0 \uB192\uC774 \uB300\uBD80\uBD84\uC744 \uCC28\uC9C0\uD558\uB294 \uB798\uD37C\uB294 \uD3BC\uCE68
|
|
4072
|
+
const elHeight = el.getBoundingClientRect().height;
|
|
4073
|
+
const pageHeight = document.body.scrollHeight || 1;
|
|
4074
|
+
if (elHeight > pageHeight * 0.5) {
|
|
4075
|
+
result.push(...children);
|
|
4076
|
+
expanded = true;
|
|
4077
|
+
} else {
|
|
4078
|
+
result.push(el);
|
|
4079
|
+
}
|
|
4061
4080
|
} else {
|
|
4062
4081
|
result.push(el);
|
|
4063
4082
|
}
|
|
@@ -4110,7 +4129,18 @@ var EXTRACTION_SCRIPT = `
|
|
|
4110
4129
|
});
|
|
4111
4130
|
|
|
4112
4131
|
// heading hierarchy (\uC2DC\uB9E8\uD2F1 + \uB300\uD615 \uD3F0\uD2B8 pseudo-heading)
|
|
4113
|
-
|
|
4132
|
+
// \uD31D\uC5C5/\uBAA8\uB2EC/dialog \uB0B4\uBD80 heading \uC81C\uC678
|
|
4133
|
+
const headings = Array.from(document.querySelectorAll('h1, h2, h3, h4, h5, h6')).filter(h => {
|
|
4134
|
+
const popup = h.closest('dialog, [class*=popup], [class*=modal], [class*=layer], [role=dialog], [style*="display: none"], [style*="display:none"]');
|
|
4135
|
+
if (popup) {
|
|
4136
|
+
const rect = popup.getBoundingClientRect();
|
|
4137
|
+
// \uD654\uBA74 \uBC16\uC774\uAC70\uB098 display:none\uC774\uBA74 \uD31D\uC5C5 heading
|
|
4138
|
+
if (rect.width === 0 || rect.height === 0) return false;
|
|
4139
|
+
// \uD31D\uC5C5\uC774 \uD654\uBA74 \uAC00\uC6B4\uB370 \uB5A0 \uC788\uC73C\uBA74 (\uC804\uCCB4 \uB108\uBE44\uC758 90% \uBBF8\uB9CC) \uD31D\uC5C5 heading
|
|
4140
|
+
if (rect.width < window.innerWidth * 0.9) return false;
|
|
4141
|
+
}
|
|
4142
|
+
return true;
|
|
4143
|
+
});
|
|
4114
4144
|
const headingHierarchy = headings.map(h => h.tagName.toLowerCase() + ': ' + (h.textContent || '').trim().slice(0, 80));
|
|
4115
4145
|
|
|
4116
4146
|
// \uC2DC\uB9E8\uD2F1 heading\uC774 \uBD80\uC871\uD558\uBA74 \uD070 \uD3F0\uD2B8 \uC694\uC18C\uB97C pseudo-heading\uC73C\uB85C \uBCF4\uC644
|
|
@@ -4341,10 +4371,40 @@ var EXTRACTION_SCRIPT = `
|
|
|
4341
4371
|
const hasHoverEffects = transitionProps.size > 0;
|
|
4342
4372
|
|
|
4343
4373
|
// \u2500\u2500 4. Images \u2500\u2500
|
|
4374
|
+
// inline style + \uC8FC\uC694 \uCEE8\uD14C\uC774\uB108\uC758 computed background-image \uD0D0\uC0C9
|
|
4344
4375
|
const imgEls = document.querySelectorAll('img, picture source, [style*="background-image"]');
|
|
4345
4376
|
const images = [];
|
|
4346
4377
|
const seenImageSrcs = new Set();
|
|
4347
4378
|
|
|
4379
|
+
// computed background-image\uAC00 \uC788\uB294 \uCEE8\uD14C\uC774\uB108 \uC694\uC18C \uCD94\uAC00 \uD0D0\uC0C9
|
|
4380
|
+
const bgCandidates = document.querySelectorAll('div, section, header, footer, main, article, aside, figure, span, a');
|
|
4381
|
+
const bgCandidateArr = Array.from(bgCandidates).filter((_, i) => i % Math.max(1, Math.ceil(bgCandidates.length / 300)) === 0);
|
|
4382
|
+
bgCandidateArr.forEach(el => {
|
|
4383
|
+
const bg = getComputedProp(el, 'background-image');
|
|
4384
|
+
if (bg && bg !== 'none') {
|
|
4385
|
+
const match = bg.match(/url\\(["']?(.+?)["']?\\)/);
|
|
4386
|
+
if (match && match[1] && !match[1].startsWith('data:') && !match[1].includes('.svg')) {
|
|
4387
|
+
const src = match[1];
|
|
4388
|
+
if (seenImageSrcs.has(src)) return;
|
|
4389
|
+
seenImageSrcs.add(src);
|
|
4390
|
+
const rect = el.getBoundingClientRect();
|
|
4391
|
+
if (rect.width < 20 || rect.height < 20) return;
|
|
4392
|
+
const parentSection = el.closest('section, header, footer, main, [class*=hero], [class*=banner]');
|
|
4393
|
+
const parentRole = parentSection ? inferSectionRole(parentSection) : 'unknown';
|
|
4394
|
+
images.push({
|
|
4395
|
+
src: src.slice(0, 500),
|
|
4396
|
+
alt: '',
|
|
4397
|
+
width: Math.round(rect.width),
|
|
4398
|
+
height: Math.round(rect.height),
|
|
4399
|
+
aspectRatio: guessAspectRatio(Math.round(rect.width), Math.round(rect.height)),
|
|
4400
|
+
role: rect.width > window.innerWidth * 0.8 && rect.height > 300 ? 'hero-bg' : 'background',
|
|
4401
|
+
dominantColor: '',
|
|
4402
|
+
position: parentRole,
|
|
4403
|
+
});
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
});
|
|
4407
|
+
|
|
4348
4408
|
imgEls.forEach(el => {
|
|
4349
4409
|
let src = '';
|
|
4350
4410
|
let alt = '';
|
|
@@ -4634,6 +4694,22 @@ function captureScreenshot(url, outputPath, width, height, timeout) {
|
|
|
4634
4694
|
// \uD31D\uC5C5 \uC790\uB3D9 \uB2EB\uAE30
|
|
4635
4695
|
await page.evaluate(() => { ${POPUP_DISMISS_SCRIPT} });
|
|
4636
4696
|
await page.waitForTimeout(500);
|
|
4697
|
+
// scroll simulation \u2014 lazy-load/IntersectionObserver \uCF58\uD150\uCE20 \uD2B8\uB9AC\uAC70
|
|
4698
|
+
await page.evaluate(async () => {
|
|
4699
|
+
const delay = (ms) => new Promise(r => setTimeout(r, ms));
|
|
4700
|
+
const scrollHeight = document.body.scrollHeight;
|
|
4701
|
+
const viewportHeight = window.innerHeight;
|
|
4702
|
+
const step = Math.floor(viewportHeight * 0.7);
|
|
4703
|
+
for (let y = 0; y < scrollHeight; y += step) {
|
|
4704
|
+
window.scrollTo(0, y);
|
|
4705
|
+
await delay(300);
|
|
4706
|
+
}
|
|
4707
|
+
window.scrollTo(0, scrollHeight);
|
|
4708
|
+
await delay(500);
|
|
4709
|
+
window.scrollTo(0, 0);
|
|
4710
|
+
await delay(500);
|
|
4711
|
+
});
|
|
4712
|
+
await page.waitForTimeout(1000);
|
|
4637
4713
|
await page.screenshot({ path: ${JSON.stringify(outputPath)}, fullPage: true });
|
|
4638
4714
|
await browser.close();
|
|
4639
4715
|
})().catch(e => {
|
|
@@ -4686,6 +4762,22 @@ async function extractPageData(url, timeout) {
|
|
|
4686
4762
|
await page.evaluate(() => { ${POPUP_DISMISS_SCRIPT} });
|
|
4687
4763
|
await page.waitForTimeout(500);
|
|
4688
4764
|
|
|
4765
|
+
// scroll simulation \u2014 lazy-load \uCF58\uD150\uCE20 \uD2B8\uB9AC\uAC70 (DOM \uCD94\uCD9C \uC804)
|
|
4766
|
+
await page.evaluate(async () => {
|
|
4767
|
+
const delay = (ms) => new Promise(r => setTimeout(r, ms));
|
|
4768
|
+
const scrollHeight = document.body.scrollHeight;
|
|
4769
|
+
const step = Math.floor(window.innerHeight * 0.7);
|
|
4770
|
+
for (let y = 0; y < scrollHeight; y += step) {
|
|
4771
|
+
window.scrollTo(0, y);
|
|
4772
|
+
await delay(300);
|
|
4773
|
+
}
|
|
4774
|
+
window.scrollTo(0, scrollHeight);
|
|
4775
|
+
await delay(500);
|
|
4776
|
+
window.scrollTo(0, 0);
|
|
4777
|
+
await delay(500);
|
|
4778
|
+
});
|
|
4779
|
+
await page.waitForTimeout(1000);
|
|
4780
|
+
|
|
4689
4781
|
const data = await page.evaluate(${JSON.stringify(EXTRACTION_SCRIPT)});
|
|
4690
4782
|
await browser.close();
|
|
4691
4783
|
process.stdout.write(JSON.stringify(data));
|
|
@@ -5318,25 +5410,77 @@ function checkCommand(cmd) {
|
|
|
5318
5410
|
}
|
|
5319
5411
|
}
|
|
5320
5412
|
function captureScreenshot2(url, outputPath, width, height) {
|
|
5321
|
-
const
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5413
|
+
const scriptContent = `
|
|
5414
|
+
const { chromium } = require('playwright');
|
|
5415
|
+
(async () => {
|
|
5416
|
+
const browser = await chromium.launch({ headless: true });
|
|
5417
|
+
const context = await browser.newContext({
|
|
5418
|
+
viewport: { width: ${width}, height: ${height} },
|
|
5419
|
+
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
5420
|
+
});
|
|
5421
|
+
const page = await context.newPage();
|
|
5422
|
+
await page.goto(${JSON.stringify(url)}, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
5423
|
+
await page.waitForTimeout(3000);
|
|
5424
|
+
// \uD31D\uC5C5/\uBAA8\uB2EC \uC790\uB3D9 \uB2EB\uAE30
|
|
5425
|
+
await page.evaluate(() => {
|
|
5426
|
+
document.querySelectorAll('dialog[open]').forEach(d => d.close());
|
|
5427
|
+
['[class*=popup] [class*=close]','[class*=modal] [class*=close]',
|
|
5428
|
+
'[aria-label*=close]','[aria-label*="\uB2EB\uAE30"]','[aria-label*=Close]',
|
|
5429
|
+
'.popup-close','.modal-close','.btn-close'].forEach(sel => {
|
|
5430
|
+
document.querySelectorAll(sel).forEach(btn => { try { btn.click(); } catch {} });
|
|
5431
|
+
});
|
|
5432
|
+
document.querySelectorAll('[class*=overlay],[class*=dimmed],.modal-backdrop').forEach(el => {
|
|
5433
|
+
if (el.getBoundingClientRect().width >= window.innerWidth * 0.8) el.style.display = 'none';
|
|
5434
|
+
});
|
|
5435
|
+
document.body.style.overflow = '';
|
|
5436
|
+
document.body.style.position = '';
|
|
5437
|
+
document.documentElement.style.overflow = '';
|
|
5438
|
+
});
|
|
5439
|
+
await page.waitForTimeout(500);
|
|
5440
|
+
// scroll simulation \u2014 lazy-load \uCF58\uD150\uCE20 \uD2B8\uB9AC\uAC70
|
|
5441
|
+
await page.evaluate(async () => {
|
|
5442
|
+
const delay = (ms) => new Promise(r => setTimeout(r, ms));
|
|
5443
|
+
const step = Math.floor(window.innerHeight * 0.7);
|
|
5444
|
+
for (let y = 0; y < document.body.scrollHeight; y += step) {
|
|
5445
|
+
window.scrollTo(0, y);
|
|
5446
|
+
await delay(300);
|
|
5447
|
+
}
|
|
5448
|
+
window.scrollTo(0, document.body.scrollHeight);
|
|
5449
|
+
await delay(500);
|
|
5450
|
+
window.scrollTo(0, 0);
|
|
5451
|
+
await delay(500);
|
|
5452
|
+
});
|
|
5453
|
+
await page.waitForTimeout(1000);
|
|
5454
|
+
await page.screenshot({ path: ${JSON.stringify(outputPath)}, fullPage: true });
|
|
5455
|
+
await browser.close();
|
|
5456
|
+
})().catch(e => {
|
|
5457
|
+
process.stderr.write(e.message);
|
|
5458
|
+
process.exit(1);
|
|
5459
|
+
});
|
|
5460
|
+
`;
|
|
5461
|
+
const result = spawnSync2("node", ["-e", scriptContent], {
|
|
5334
5462
|
stdio: "pipe",
|
|
5335
|
-
timeout:
|
|
5463
|
+
timeout: 9e4,
|
|
5464
|
+
env: { ...process.env }
|
|
5336
5465
|
});
|
|
5337
5466
|
if (result.status !== 0) {
|
|
5338
5467
|
const stderr = result.stderr?.toString() ?? "";
|
|
5339
|
-
|
|
5468
|
+
const fallback = spawnSync2("npx", [
|
|
5469
|
+
"playwright",
|
|
5470
|
+
"screenshot",
|
|
5471
|
+
"--browser",
|
|
5472
|
+
"chromium",
|
|
5473
|
+
"--viewport-size",
|
|
5474
|
+
`${width},${height}`,
|
|
5475
|
+
"--wait-for-timeout",
|
|
5476
|
+
"3000",
|
|
5477
|
+
"--full-page",
|
|
5478
|
+
url,
|
|
5479
|
+
outputPath
|
|
5480
|
+
], { stdio: "pipe", timeout: 6e4 });
|
|
5481
|
+
if (fallback.status !== 0) {
|
|
5482
|
+
throw new Error(`\uC2A4\uD06C\uB9B0\uC0F7 \uCEA1\uCC98 \uC2E4\uD328: ${stderr || "unknown error"}`);
|
|
5483
|
+
}
|
|
5340
5484
|
}
|
|
5341
5485
|
}
|
|
5342
5486
|
|