6.7.0 - Alpha12 - Fine tuning
This commit is contained in:
43
.utils/declarations/index.d.ts
vendored
43
.utils/declarations/index.d.ts
vendored
@@ -76,6 +76,49 @@ interface FindTargetRowsOptionsBase {
|
||||
interface FindTargetRowsOptions extends FindTargetRowsOptionsBase {
|
||||
/** @default [] */
|
||||
tableDataStructure?: Array<{ [dataItemName: TableDataStructureItemName]: TableDataStructureItem } | TableDataStructureItemName>;
|
||||
|
||||
/**
|
||||
* Configuration for "expand" actions needed before searching the table.
|
||||
* Example: { toggleSelector: 'a.exw-control' } will click Devsite's collapsible controls.
|
||||
* zh-CN:
|
||||
* 在查找表格前需要进行的 "展开" 动作配置.
|
||||
* 示例: { toggleSelector: 'a.exw-control' } 将点击 Devsite 的可折叠控件.
|
||||
*/
|
||||
expandBeforeFinding?: ExpandBeforeFindingOptions | ExpandBeforeFindingOptions[];
|
||||
}
|
||||
|
||||
interface ExpandBeforeFindingOptions {
|
||||
/**
|
||||
* Optional container selector to limit the scope of operation.
|
||||
* zh-CN: 限定作用范围容器选择器, 可选.
|
||||
*/
|
||||
containerSelector?: string;
|
||||
/**
|
||||
* Selector for the "expand/collapse" button or toggle that needs to be clicked (required).
|
||||
* zh-CN: 需要点击的 "展开/折叠" 按钮或开关的选择器 (必填).
|
||||
*/
|
||||
toggleSelector: string;
|
||||
/**
|
||||
* Attribute name to determine if expanded, defaults to 'aria-expanded'.
|
||||
* zh-CN: 判定已展开的属性名, 默认 'aria-expanded'.
|
||||
*
|
||||
* @default 'aria-expanded'
|
||||
*/
|
||||
expandedAttr?: string;
|
||||
/**
|
||||
* Attribute value to determine if expanded, defaults to 'true'.
|
||||
* zh-CN: 判定已展开的属性值, 默认 'true'.
|
||||
*
|
||||
* @default 'true'
|
||||
*/
|
||||
expandedValue?: string;
|
||||
/**
|
||||
* Maximum number of targets to click, no limit by default.
|
||||
* zh-CN: 最多点击的目标数量, 默认无限制.
|
||||
*
|
||||
* @default Infinity
|
||||
*/
|
||||
maxClicks?: number;
|
||||
}
|
||||
|
||||
interface FindTargetRowsOptionsForPageEvaluate extends FindTargetRowsOptionsBase {
|
||||
|
||||
@@ -18,6 +18,9 @@ export async function fetchStudioAgpTable() {
|
||||
// @ts-ignore
|
||||
return findTargetRows({
|
||||
url: URL,
|
||||
expandBeforeFinding: {
|
||||
toggleSelector: 'a.exw-control',
|
||||
},
|
||||
tableFilter: {
|
||||
th: /Android Studio version/i,
|
||||
},
|
||||
|
||||
@@ -248,7 +248,7 @@ async function getPRCommitStatsByAuthor(pr) {
|
||||
* zh-CN: 要处理的输入项列表.
|
||||
* @param {number} limit
|
||||
* Maximum concurrency (>=1).<br>
|
||||
* zh=CN: 最大并发数 (>=1).
|
||||
* zh-CN: 最大并发数 (>=1).
|
||||
* @param {(item: Item, idx: number) => Promise<MapperResult>} mapper
|
||||
* Async function to process one item.<br>
|
||||
* zh-CN: 处理单个项的异步函数.
|
||||
|
||||
@@ -55,6 +55,66 @@ function toEncodedRegexTagOptions(options) {
|
||||
return structuredClone(traverse(options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to click the "Expand" control before searching for the table.
|
||||
* zh-CN: 在查找表格前尝试点击 "展开" 控件.
|
||||
*
|
||||
* @param {import('puppeteer').Page} page
|
||||
* @param {FindTargetRowsOptions & PuppeteerOptions} options
|
||||
* @returns {Promise<number>} Actual number of clicks. (zh-CN: 实际点击次数.)
|
||||
*/
|
||||
async function expandContentIfNeeded(page, options) {
|
||||
const configs = options.expandBeforeFinding;
|
||||
if (!configs) return 0;
|
||||
|
||||
/** @type {ExpandBeforeFindingOptions[]} */
|
||||
const list = Array.isArray(configs) ? configs : [ configs ];
|
||||
|
||||
let totalClicked = 0;
|
||||
for (const cfg of list) {
|
||||
if (!cfg || !cfg.toggleSelector) continue;
|
||||
const {
|
||||
containerSelector,
|
||||
toggleSelector,
|
||||
expandedAttr = 'aria-expanded',
|
||||
expandedValue = 'true',
|
||||
maxClicks = Infinity,
|
||||
} = cfg;
|
||||
|
||||
const containerHandle = containerSelector ? await page.$(containerSelector) : null;
|
||||
const toggles = containerHandle
|
||||
? await containerHandle.$$(toggleSelector)
|
||||
: await page.$$(toggleSelector);
|
||||
|
||||
let clicked = 0;
|
||||
for (const toggle of toggles) {
|
||||
if (clicked >= maxClicks) break;
|
||||
const isExpanded = await toggle.evaluate((el, attr, val) => {
|
||||
const cur = el.getAttribute(attr);
|
||||
return cur === val;
|
||||
}, expandedAttr, expandedValue);
|
||||
if (!isExpanded) {
|
||||
try {
|
||||
await toggle.click({ delay: 10 });
|
||||
clicked++;
|
||||
totalClicked++;
|
||||
await sleep(200);
|
||||
} catch {
|
||||
/* Ignored. */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (containerHandle) {
|
||||
try {
|
||||
await containerHandle.dispose();
|
||||
} catch {
|
||||
/* Ignored. */
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalClicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Page} page
|
||||
* @returns {Promise<void>}
|
||||
@@ -87,7 +147,7 @@ async function findTargetRowsWithPage(page, options = {}) {
|
||||
return await page.evaluate((options, consts) => {
|
||||
const regex = new RegExp(consts.regexId + String.raw`(?:(\w+):)?(.+)`);
|
||||
const targets = Array.from(document.querySelectorAll(options.tableSelector ?? 'table'));
|
||||
const target = targets.find(t => {
|
||||
const filteredTargets = targets.filter(t => {
|
||||
for (const [ selector, filter ] of Object.entries(options.tableFilter ?? {})) {
|
||||
const elements = Array.from(t.querySelectorAll(selector));
|
||||
if (Array.isArray(filter)) {
|
||||
@@ -130,11 +190,11 @@ async function findTargetRowsWithPage(page, options = {}) {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!target) {
|
||||
if (!filteredTargets.length) {
|
||||
throw new Error('No target table found');
|
||||
}
|
||||
|
||||
const tableRows = Array.from(target.querySelectorAll(options.tableRowSelector ?? 'tbody tr'));
|
||||
const tableRows = filteredTargets.map(target => Array.from(target.querySelectorAll(options.tableRowSelector ?? 'tbody tr'))).flat(1);
|
||||
const tableDataList = [];
|
||||
tableRows.forEach((tr) => {
|
||||
const tableData = {};
|
||||
@@ -209,8 +269,11 @@ export async function findTargetRows(options) {
|
||||
let rows = null;
|
||||
const deadline = Date.now() + (options.findTargetRowsTimeout ?? 30000);
|
||||
while (Date.now() < deadline) {
|
||||
await expandContentIfNeeded(page, options);
|
||||
|
||||
rows = await findTargetRowsWithPage(page, options);
|
||||
if (rows && rows.length) break;
|
||||
|
||||
await autoScroll(page);
|
||||
await sleep(300);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user