auto-webmcp 0.3.9 → 0.3.10

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.
@@ -631,6 +631,19 @@ function resolveNativeControlFallbackKey(control) {
631
631
  }
632
632
  return null;
633
633
  }
634
+ function resolveAriaElementKey(el) {
635
+ if (el.dataset["webmcpName"])
636
+ return sanitizeName(el.dataset["webmcpName"]);
637
+ if (el.id && !AUTO_GENERATED_ID_RE.test(el.id))
638
+ return sanitizeName(el.id);
639
+ const label = el.getAttribute("aria-label");
640
+ if (label)
641
+ return sanitizeName(label);
642
+ const placeholder = el.getAttribute("placeholder");
643
+ if (placeholder)
644
+ return sanitizeName(placeholder);
645
+ return null;
646
+ }
634
647
  function collectAriaControls(form) {
635
648
  const selector = ARIA_ROLES_TO_SCAN.map((r) => `[role="${r}"]`).join(", ");
636
649
  const rawResults = [];
@@ -889,6 +902,22 @@ function buildSchemaFromInputs(inputs) {
889
902
  const processedRadioGroups = /* @__PURE__ */ new Set();
890
903
  const processedCheckboxGroups = /* @__PURE__ */ new Set();
891
904
  for (const control of inputs) {
905
+ if (!(control instanceof HTMLInputElement) && !(control instanceof HTMLTextAreaElement) && !(control instanceof HTMLSelectElement)) {
906
+ const fieldKey2 = resolveAriaElementKey(control);
907
+ if (!fieldKey2)
908
+ continue;
909
+ if (!isControlVisible(control))
910
+ continue;
911
+ const prop = { type: "string" };
912
+ prop.title = control.getAttribute("aria-label") ?? fieldKey2;
913
+ const desc2 = control.getAttribute("aria-description") ?? control.getAttribute("aria-describedby") ? null : null;
914
+ if (desc2)
915
+ prop.description = desc2;
916
+ properties[fieldKey2] = prop;
917
+ fieldElements.set(fieldKey2, control);
918
+ required.push(fieldKey2);
919
+ continue;
920
+ }
892
921
  const rawName = control.name;
893
922
  const fieldKey = (rawName ? sanitizeName(rawName) : null) || resolveNativeControlFallbackKey(control);
894
923
  if (!fieldKey)
@@ -1284,10 +1313,17 @@ function fillAriaField(el, value) {
1284
1313
  }
1285
1314
  const htmlEl = el;
1286
1315
  if (htmlEl.isContentEditable) {
1287
- htmlEl.textContent = String(value ?? "");
1316
+ htmlEl.focus();
1317
+ const range = document.createRange();
1318
+ range.selectNodeContents(htmlEl);
1319
+ const sel = window.getSelection();
1320
+ sel?.removeAllRanges();
1321
+ sel?.addRange(range);
1322
+ document.execCommand("insertText", false, String(value ?? ""));
1323
+ } else {
1324
+ el.dispatchEvent(new Event("input", { bubbles: true }));
1325
+ el.dispatchEvent(new Event("change", { bubbles: true }));
1288
1326
  }
1289
- el.dispatchEvent(new Event("input", { bubbles: true }));
1290
- el.dispatchEvent(new Event("change", { bubbles: true }));
1291
1327
  }
1292
1328
  function serializeFormData(form, params, fieldEls) {
1293
1329
  const result = {};
@@ -1560,10 +1596,10 @@ async function scanOrphanInputs(config) {
1560
1596
  return;
1561
1597
  const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button[data-variant="primary"]:not([disabled])';
1562
1598
  const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"], button[data-variant="primary"]';
1563
- const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search/i;
1599
+ const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search|post|tweet|publish/i;
1564
1600
  const orphanInputs = Array.from(
1565
1601
  document.querySelectorAll(
1566
- "input:not(form input), textarea:not(form textarea), select:not(form select)"
1602
+ 'input:not(form input), textarea:not(form textarea), select:not(form select), [role="textbox"]:not(form [role="textbox"]):not(input):not(textarea), [role="searchbox"]:not(form [role="searchbox"]):not(input):not(textarea), [contenteditable="true"]:not(form [contenteditable="true"]):not(input):not(textarea)'
1567
1603
  )
1568
1604
  ).filter((el) => {
1569
1605
  if (el instanceof HTMLInputElement && ORPHAN_EXCLUDED_TYPES.has(el.type.toLowerCase())) {
@@ -1619,6 +1655,15 @@ async function scanOrphanInputs(config) {
1619
1655
  if (submitBtn)
1620
1656
  console.log(`[auto-webmcp] orphan: using disabled submit button as reference: "${submitBtn.textContent?.trim()}"`);
1621
1657
  }
1658
+ if (!submitBtn) {
1659
+ const containerBtns = Array.from(container.querySelectorAll("button")).filter((b) => {
1660
+ const r = b.getBoundingClientRect();
1661
+ return r.width > 0 && r.height > 0 && !b.disabled && SUBMIT_TEXT_RE.test(b.textContent ?? "");
1662
+ });
1663
+ submitBtn = containerBtns[containerBtns.length - 1] ?? null;
1664
+ if (submitBtn)
1665
+ console.log(`[auto-webmcp] orphan: using text-matched button in container: "${submitBtn.textContent?.trim()}"`);
1666
+ }
1622
1667
  if (!submitBtn) {
1623
1668
  const pageBtns = Array.from(document.querySelectorAll("button")).filter(
1624
1669
  (b) => {
@@ -1638,10 +1683,10 @@ async function scanOrphanInputs(config) {
1638
1683
  const AUTO_ID_RE = /^_r_[0-9a-z]+_$/i;
1639
1684
  for (const el of inputs) {
1640
1685
  const id = el.id && !AUTO_ID_RE.test(el.id) ? el.id : null;
1641
- const key = el.name || el.dataset["webmcpName"] || id || el.getAttribute("aria-label") || (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement ? el.placeholder || null : null) || null;
1686
+ const key = el.name || el.getAttribute("name") || el.dataset["webmcpName"] || id || el.getAttribute("aria-label") || el.getAttribute("placeholder") || null;
1642
1687
  const safeKey = key ? key.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 64) : null;
1643
1688
  const matched = !!(safeKey && schemaProps[safeKey]);
1644
- console.log(`[auto-webmcp] orphan: field (name="${el.name}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
1689
+ console.log(`[auto-webmcp] orphan: field (name="${el.name ?? ""}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
1645
1690
  if (matched) {
1646
1691
  inputPairs.push({ key: safeKey, el });
1647
1692
  }