doc-detective 4.29.1 → 4.31.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.
Files changed (71) hide show
  1. package/bin/doc-detective-lsp.js +6 -0
  2. package/dist/cli.js +2 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/common/src/validate.d.ts +16 -1
  5. package/dist/common/src/validate.d.ts.map +1 -1
  6. package/dist/common/src/validate.js +18 -1
  7. package/dist/common/src/validate.js.map +1 -1
  8. package/dist/core/tests/saveScreenshot.d.ts.map +1 -1
  9. package/dist/core/tests/saveScreenshot.js +116 -59
  10. package/dist/core/tests/saveScreenshot.js.map +1 -1
  11. package/dist/core/tests/startSurface.d.ts.map +1 -1
  12. package/dist/core/tests/startSurface.js +17 -12
  13. package/dist/core/tests/startSurface.js.map +1 -1
  14. package/dist/core/tests.d.ts.map +1 -1
  15. package/dist/core/tests.js +33 -19
  16. package/dist/core/tests.js.map +1 -1
  17. package/dist/core/utils.d.ts +73 -0
  18. package/dist/core/utils.d.ts.map +1 -1
  19. package/dist/core/utils.js +100 -0
  20. package/dist/core/utils.js.map +1 -1
  21. package/dist/index.cjs +140 -55
  22. package/dist/lsp/command.d.ts +12 -0
  23. package/dist/lsp/command.d.ts.map +1 -0
  24. package/dist/lsp/command.js +24 -0
  25. package/dist/lsp/command.js.map +1 -0
  26. package/dist/lsp/completion.d.ts +27 -0
  27. package/dist/lsp/completion.d.ts.map +1 -0
  28. package/dist/lsp/completion.js +114 -0
  29. package/dist/lsp/completion.js.map +1 -0
  30. package/dist/lsp/diagnostics.d.ts +21 -0
  31. package/dist/lsp/diagnostics.d.ts.map +1 -0
  32. package/dist/lsp/diagnostics.js +137 -0
  33. package/dist/lsp/diagnostics.js.map +1 -0
  34. package/dist/lsp/gate.d.ts +30 -0
  35. package/dist/lsp/gate.d.ts.map +1 -0
  36. package/dist/lsp/gate.js +80 -0
  37. package/dist/lsp/gate.js.map +1 -0
  38. package/dist/lsp/hover.d.ts +9 -0
  39. package/dist/lsp/hover.d.ts.map +1 -0
  40. package/dist/lsp/hover.js +56 -0
  41. package/dist/lsp/hover.js.map +1 -0
  42. package/dist/lsp/inline.d.ts +25 -0
  43. package/dist/lsp/inline.d.ts.map +1 -0
  44. package/dist/lsp/inline.js +208 -0
  45. package/dist/lsp/inline.js.map +1 -0
  46. package/dist/lsp/json/positions.d.ts +51 -0
  47. package/dist/lsp/json/positions.d.ts.map +1 -0
  48. package/dist/lsp/json/positions.js +101 -0
  49. package/dist/lsp/json/positions.js.map +1 -0
  50. package/dist/lsp/messages.d.ts +27 -0
  51. package/dist/lsp/messages.d.ts.map +1 -0
  52. package/dist/lsp/messages.js +33 -0
  53. package/dist/lsp/messages.js.map +1 -0
  54. package/dist/lsp/model.d.ts +27 -0
  55. package/dist/lsp/model.d.ts.map +1 -0
  56. package/dist/lsp/model.js +49 -0
  57. package/dist/lsp/model.js.map +1 -0
  58. package/dist/lsp/registry.d.ts +61 -0
  59. package/dist/lsp/registry.d.ts.map +1 -0
  60. package/dist/lsp/registry.js +124 -0
  61. package/dist/lsp/registry.js.map +1 -0
  62. package/dist/lsp/server.d.ts +40 -0
  63. package/dist/lsp/server.d.ts.map +1 -0
  64. package/dist/lsp/server.js +64 -0
  65. package/dist/lsp/server.js.map +1 -0
  66. package/dist/lsp/yaml/positions.d.ts +32 -0
  67. package/dist/lsp/yaml/positions.d.ts.map +1 -0
  68. package/dist/lsp/yaml/positions.js +92 -0
  69. package/dist/lsp/yaml/positions.js.map +1 -0
  70. package/package.json +6 -2
  71. package/scripts/postinstall.js +144 -1
package/dist/index.cjs CHANGED
@@ -631871,10 +631871,13 @@ function getRandomUUID() {
631871
631871
  function cloneForValidation(object) {
631872
631872
  return JSON.parse(JSON.stringify(object));
631873
631873
  }
631874
+ function snapshotErrors(errors) {
631875
+ return errors.map((error) => ({ ...error }));
631876
+ }
631874
631877
  function escapeRegExp(string) {
631875
631878
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
631876
631879
  }
631877
- function validate({ schemaKey, object, addDefaults = true }) {
631880
+ function validate({ schemaKey, object, addDefaults = true, structuredErrors = false }) {
631878
631881
  if (!schemaKey) {
631879
631882
  throw new Error("Schema key is required.");
631880
631883
  }
@@ -631886,6 +631889,9 @@ function validate({ schemaKey, object, addDefaults = true }) {
631886
631889
  errors: "",
631887
631890
  object
631888
631891
  };
631892
+ if (structuredErrors) {
631893
+ result.errorObjects = [];
631894
+ }
631889
631895
  let validationObject;
631890
631896
  let check = ajv.getSchema(schemaKey);
631891
631897
  if (!check) {
@@ -631902,6 +631908,9 @@ function validate({ schemaKey, object, addDefaults = true }) {
631902
631908
  const compatibleSchemasList = compatibleSchemas[schemaKey];
631903
631909
  if (!compatibleSchemasList) {
631904
631910
  result.errors = targetErrors.map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`).join(", ");
631911
+ if (structuredErrors) {
631912
+ result.errorObjects = snapshotErrors(targetErrors);
631913
+ }
631905
631914
  result.object = object;
631906
631915
  result.valid = false;
631907
631916
  return result;
@@ -631918,6 +631927,9 @@ function validate({ schemaKey, object, addDefaults = true }) {
631918
631927
  }
631919
631928
  if (!matchedSchemaKey) {
631920
631929
  result.errors = targetErrors.map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`).join(", ");
631930
+ if (structuredErrors) {
631931
+ result.errorObjects = snapshotErrors(targetErrors);
631932
+ }
631921
631933
  result.object = object;
631922
631934
  result.valid = false;
631923
631935
  return result;
@@ -634095,6 +634107,49 @@ function logLevelEnabled(config, level) {
634095
634107
  return true;
634096
634108
  return false;
634097
634109
  }
634110
+ function viewportMismatchWarning(requested, actual, tolerance = 0) {
634111
+ const parts = [];
634112
+ for (const dim of ["width", "height"]) {
634113
+ const req = Number(requested?.[dim]);
634114
+ if (!(req > 0))
634115
+ continue;
634116
+ const act = Number(actual?.[dim]);
634117
+ if (!Number.isFinite(act)) {
634118
+ parts.push(`${dim} requested ${req}px, rendered unknown`);
634119
+ } else if (Math.abs(act - req) > tolerance) {
634120
+ parts.push(`${dim} requested ${req}px, rendered ${act}px`);
634121
+ }
634122
+ }
634123
+ if (parts.length === 0)
634124
+ return null;
634125
+ return `Requested viewport not fully realized \u2014 the browser or OS enforces a minimum window size: ${parts.join("; ")}. Screenshots and measurements reflect the rendered size, not the requested size.`;
634126
+ }
634127
+ function resolveViewportTarget(requested, current) {
634128
+ const w = Number(requested?.width);
634129
+ const h = Number(requested?.height);
634130
+ return {
634131
+ width: w > 0 ? w : Number(current?.width),
634132
+ height: h > 0 ? h : Number(current?.height)
634133
+ };
634134
+ }
634135
+ async function readViewport(driver) {
634136
+ const v = await driver.execute("return { width: window.innerWidth, height: window.innerHeight }", []);
634137
+ return { width: Number(v?.width), height: Number(v?.height) };
634138
+ }
634139
+ async function realizeViewport(driver, requested, config = {}, label) {
634140
+ const current = await readViewport(driver);
634141
+ const target = resolveViewportTarget(requested, current);
634142
+ const windowSize = await driver.getWindowSize();
634143
+ const deltaWidth = Number.isFinite(current.width) && Number.isFinite(target.width) ? target.width - current.width : 0;
634144
+ const deltaHeight = Number.isFinite(current.height) && Number.isFinite(target.height) ? target.height - current.height : 0;
634145
+ await driver.setWindowSize(Math.round(windowSize.width + deltaWidth), Math.round(windowSize.height + deltaHeight));
634146
+ const actual = await readViewport(driver);
634147
+ const warning = viewportMismatchWarning(requested, actual, VIEWPORT_TOLERANCE_PX);
634148
+ if (warning) {
634149
+ await log(config, "warning", label ? `${label}: ${warning}` : warning);
634150
+ }
634151
+ return actual;
634152
+ }
634098
634153
  async function log(config, level, message) {
634099
634154
  if (message === void 0) {
634100
634155
  message = config;
@@ -634429,7 +634484,7 @@ function llevenshteinDistance(s, t) {
634429
634484
  }
634430
634485
  return arr[t.length][s.length];
634431
634486
  }
634432
- var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, ENV_VAR_REGEX, posixBashProbe;
634487
+ var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, VIEWPORT_TOLERANCE_PX, ENV_VAR_REGEX, posixBashProbe;
634433
634488
  var init_utils = __esm({
634434
634489
  "dist/core/utils.js"() {
634435
634490
  "use strict";
@@ -634471,6 +634526,7 @@ var init_utils = __esm({
634471
634526
  maxBodyLength: 50 * 1024 * 1024,
634472
634527
  maxRedirects: 5
634473
634528
  };
634529
+ VIEWPORT_TOLERANCE_PX = 16;
634474
634530
  ENV_VAR_REGEX = /\$[a-zA-Z0-9_]+(?![a-zA-Z0-9_$])/g;
634475
634531
  }
634476
634532
  });
@@ -646372,7 +646428,6 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646372
646428
  return result;
646373
646429
  } else {
646374
646430
  existFilePath = filePath;
646375
- filePath = import_node_path17.default.join(dir, `${step.stepId}_${Date.now()}.png`);
646376
646431
  }
646377
646432
  }
646378
646433
  }
@@ -646458,6 +646513,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646458
646513
  await driver.pause(100);
646459
646514
  }
646460
646515
  const recordingActive = !isAppCapture && isRecordingActive(driver);
646516
+ let captureBuffer;
646517
+ let appScratchPath;
646461
646518
  try {
646462
646519
  if (recordingActive) {
646463
646520
  await driver.execute(() => {
@@ -646467,18 +646524,24 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646467
646524
  });
646468
646525
  }
646469
646526
  if (isAppCapture) {
646470
- await appWindowScreenshot(appEntry, appWindowTarget, filePath);
646527
+ appScratchPath = import_node_path17.default.join(dir, `.appcapture_${step.stepId || "screenshot"}_${Date.now()}.png`);
646528
+ await appWindowScreenshot(appEntry, appWindowTarget, appScratchPath);
646529
+ captureBuffer = import_node_fs20.default.readFileSync(appScratchPath);
646471
646530
  } else {
646472
- await captureDriver.saveScreenshot(filePath);
646531
+ const base64 = await captureDriver.takeScreenshot();
646532
+ captureBuffer = Buffer.from(base64, "base64");
646473
646533
  }
646474
646534
  } catch (error) {
646475
646535
  result.status = "FAIL";
646476
646536
  result.description = `Couldn't save screenshot. ${error}`;
646477
- if (existFilePath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646478
- import_node_fs20.default.unlinkSync(filePath);
646479
- }
646480
646537
  return result;
646481
646538
  } finally {
646539
+ if (appScratchPath && import_node_fs20.default.existsSync(appScratchPath)) {
646540
+ try {
646541
+ import_node_fs20.default.unlinkSync(appScratchPath);
646542
+ } catch {
646543
+ }
646544
+ }
646482
646545
  if (recordingActive) {
646483
646546
  try {
646484
646547
  await driver.execute(() => {
@@ -646490,6 +646553,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646490
646553
  }
646491
646554
  }
646492
646555
  }
646556
+ let finalBuffer = captureBuffer;
646493
646557
  if (step.screenshot.crop) {
646494
646558
  let padding = { top: 0, right: 0, bottom: 0, left: 0 };
646495
646559
  if (typeof step.screenshot.crop.padding === "number") {
@@ -646523,35 +646587,53 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646523
646587
  rect.y = Math.round(rect.y);
646524
646588
  rect.width = Math.round(rect.width);
646525
646589
  rect.height = Math.round(rect.height);
646526
- const imgMeta = await sharp(filePath).metadata();
646590
+ const imgMeta = await sharp(captureBuffer).metadata();
646527
646591
  const clamped = clampCropRect(rect, imgMeta.width, imgMeta.height);
646528
646592
  rect.x = clamped.x;
646529
646593
  rect.y = clamped.y;
646530
646594
  rect.width = clamped.width;
646531
646595
  rect.height = clamped.height;
646532
646596
  log(config, "debug", { padded_rect: rect });
646533
- const croppedPath = import_node_path17.default.join(dir, `cropped_${step.stepId || Date.now()}.png`);
646534
646597
  try {
646535
- await sharp(filePath).extract({
646598
+ finalBuffer = await sharp(captureBuffer).extract({
646536
646599
  left: rect.x,
646537
646600
  top: rect.y,
646538
646601
  width: rect.width,
646539
646602
  height: rect.height
646540
- }).toFile(croppedPath);
646541
- import_node_fs20.default.renameSync(croppedPath, filePath);
646603
+ }).png().toBuffer();
646542
646604
  } catch (error) {
646543
646605
  result.status = "FAIL";
646544
646606
  result.description = `Couldn't crop image. ${error}`;
646545
- if (existFilePath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646546
- import_node_fs20.default.unlinkSync(filePath);
646547
- }
646548
646607
  return result;
646549
646608
  }
646550
646609
  }
646610
+ try {
646611
+ const savedMeta = await sharp(finalBuffer).metadata();
646612
+ if (savedMeta.width && savedMeta.height) {
646613
+ result.outputs.width = savedMeta.width;
646614
+ result.outputs.height = savedMeta.height;
646615
+ }
646616
+ } catch {
646617
+ }
646618
+ const writeFinalPng = (destination) => {
646619
+ try {
646620
+ import_node_fs20.default.writeFileSync(destination, finalBuffer);
646621
+ return true;
646622
+ } catch (error) {
646623
+ result.status = "FAIL";
646624
+ result.description = `Couldn't save screenshot. ${error}`;
646625
+ return false;
646626
+ }
646627
+ };
646628
+ if (isUrlPath) {
646629
+ if (!writeFinalPng(filePath))
646630
+ return result;
646631
+ }
646551
646632
  if (existFilePath) {
646552
646633
  if (step.screenshot.overwrite == "true" && !isUrlPath) {
646634
+ if (!writeFinalPng(existFilePath))
646635
+ return result;
646553
646636
  result.description += ` Overwrote existing file.`;
646554
- import_node_fs20.default.renameSync(filePath, existFilePath);
646555
646637
  result.outputs.screenshotPath = existFilePath;
646556
646638
  result.outputs.changed = true;
646557
646639
  if (step.screenshot.sourceIntegration) {
@@ -646565,13 +646647,10 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646565
646647
  let img2;
646566
646648
  try {
646567
646649
  img1 = PNG.sync.read(import_node_fs20.default.readFileSync(existFilePath));
646568
- img2 = PNG.sync.read(import_node_fs20.default.readFileSync(filePath));
646650
+ img2 = PNG.sync.read(finalBuffer);
646569
646651
  } catch (error) {
646570
646652
  result.status = "FAIL";
646571
646653
  result.description = isUrlPath ? `Couldn't decode PNG for comparison. The URL reference (${redactedUrl}) may not be a valid PNG. ${error}` : `Couldn't decode PNG for comparison. ${error}`;
646572
- if (!isUrlPath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646573
- import_node_fs20.default.unlinkSync(filePath);
646574
- }
646575
646654
  return result;
646576
646655
  }
646577
646656
  const aspectRatioMatch = aspectRatiosMatch(img1, img2);
@@ -646582,9 +646661,6 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646582
646661
  });
646583
646662
  if (!aspectRatioMatch) {
646584
646663
  result.description = `Couldn't compare images. Images have different aspect ratios.`;
646585
- if (!isUrlPath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646586
- import_node_fs20.default.unlinkSync(filePath);
646587
- }
646588
646664
  return await evaluateApplicable();
646589
646665
  }
646590
646666
  if (img1.width !== img2.width || img1.height !== img2.height) {
@@ -646592,14 +646668,12 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646592
646668
  const height2 = Math.min(img1.height, img2.height);
646593
646669
  const img1ResizedBuffer = await sharp(img1.data, {
646594
646670
  raw: { width: img1.width, height: img1.height, channels: 4 }
646595
- }).resize(width2, height2).png().toBuffer();
646671
+ }).resize(width2, height2).raw().toBuffer();
646596
646672
  const img2ResizedBuffer = await sharp(img2.data, {
646597
646673
  raw: { width: img2.width, height: img2.height, channels: 4 }
646598
- }).resize(width2, height2).png().toBuffer();
646599
- const resizedImg1 = PNG.sync.read(img1ResizedBuffer);
646600
- const resizedImg2 = PNG.sync.read(img2ResizedBuffer);
646601
- img1.data = resizedImg1.data;
646602
- img2.data = resizedImg2.data;
646674
+ }).resize(width2, height2).raw().toBuffer();
646675
+ img1.data = img1ResizedBuffer;
646676
+ img2.data = img2ResizedBuffer;
646603
646677
  img1.width = width2;
646604
646678
  img1.height = height2;
646605
646679
  }
@@ -646610,9 +646684,6 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646610
646684
  } catch (error) {
646611
646685
  result.status = "FAIL";
646612
646686
  result.description = `Couldn't load screenshot comparison dependency (pixelmatch). ${error?.message ?? error}`;
646613
- if (!isUrlPath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646614
- import_node_fs20.default.unlinkSync(filePath);
646615
- }
646616
646687
  return result;
646617
646688
  }
646618
646689
  const numDiffPixels = pixelmatchFn(img1.data, img2.data, null, width, height, { threshold: 5e-4 });
@@ -646629,7 +646700,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646629
646700
  });
646630
646701
  if (fractionalDiff > step.screenshot.maxVariation) {
646631
646702
  if (step.screenshot.overwrite == "aboveVariation" && !isUrlPath) {
646632
- import_node_fs20.default.renameSync(filePath, existFilePath);
646703
+ if (!writeFinalPng(existFilePath))
646704
+ return result;
646633
646705
  }
646634
646706
  result.description += ` The difference between the existing screenshot and new screenshot (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.screenshot.maxVariation}).`;
646635
646707
  if (isUrlPath) {
@@ -646653,14 +646725,13 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646653
646725
  if (step.screenshot.sourceIntegration) {
646654
646726
  result.outputs.sourceIntegration = step.screenshot.sourceIntegration;
646655
646727
  }
646656
- if (step.screenshot.overwrite != "true") {
646657
- import_node_fs20.default.unlinkSync(filePath);
646658
- }
646659
646728
  }
646660
646729
  }
646661
646730
  }
646662
646731
  }
646663
646732
  if (!result.outputs.screenshotPath) {
646733
+ if (!writeFinalPng(filePath))
646734
+ return result;
646664
646735
  result.outputs.screenshotPath = filePath;
646665
646736
  result.outputs.changed = true;
646666
646737
  if (step.screenshot.sourceIntegration) {
@@ -648745,20 +648816,31 @@ async function startSurfaceStep({ config, step, platform, driver, processRegistr
648745
648816
  }
648746
648817
  const vw = Number(d.viewport?.width);
648747
648818
  const vh = Number(d.viewport?.height);
648819
+ let viewportOutput;
648748
648820
  if (vw > 0 || vh > 0) {
648821
+ const requested = {
648822
+ ...vw > 0 ? { width: vw } : {},
648823
+ ...vh > 0 ? { height: vh } : {}
648824
+ };
648825
+ let rendered;
648749
648826
  try {
648750
- await applyViewport(opened.driver, d.viewport);
648827
+ rendered = await realizeViewport(opened.driver, requested, config, `startSurface "${opened.name}"`);
648751
648828
  } catch (error) {
648752
648829
  return {
648753
648830
  status: "FAIL",
648754
648831
  description: `Opened browser surface "${opened.name}" but couldn't apply the viewport: ${error?.message ?? error}`
648755
648832
  };
648756
648833
  }
648834
+ viewportOutput = { requested, actual: rendered };
648757
648835
  }
648758
648836
  return {
648759
648837
  status: "PASS",
648760
648838
  description: `Opened browser surface "${opened.name}" (${engine}).`,
648761
- outputs: { name: opened.name, engine }
648839
+ outputs: {
648840
+ name: opened.name,
648841
+ engine,
648842
+ ...viewportOutput ? { viewport: viewportOutput } : {}
648843
+ }
648762
648844
  };
648763
648845
  };
648764
648846
  const runProcessDescriptor = async (d) => {
@@ -648873,13 +648955,6 @@ async function startSurfaceStep({ config, step, platform, driver, processRegistr
648873
648955
  outputs: { surfaces: results }
648874
648956
  };
648875
648957
  }
648876
- async function applyViewport(driver, viewport) {
648877
- const viewportSize = await driver.execute("return { width: window.innerWidth, height: window.innerHeight }", []);
648878
- const windowSize = await driver.getWindowSize();
648879
- const deltaWidth = (viewport.width || viewportSize.width) - viewportSize.width;
648880
- const deltaHeight = (viewport.height || viewportSize.height) - viewportSize.height;
648881
- await driver.setWindowSize(windowSize.width + deltaWidth, windowSize.height + deltaHeight);
648882
- }
648883
648958
 
648884
648959
  // dist/core/tests/mobileBrowser.js
648885
648960
  var import_node_path24 = __toESM(require("node:path"), 1);
@@ -650089,6 +650164,10 @@ function getDriverCapabilities({ runnerDetails, name, options }) {
650089
650164
  // 10 minutes
650090
650165
  "appium:executable": chromium.driver,
650091
650166
  browserName: "chrome",
650167
+ // Classic WebDriver, no BiDi socket. Enabling `webSocketUrl` for
650168
+ // viewport emulation (driver.setViewport) crashed headed recording
650169
+ // contexts with a stack overflow and can't be gated off recording
650170
+ // (viewport+recording is a supported combo) — see ADR 01072 (rejected).
650092
650171
  "wdio:enforceWebDriverClassic": true,
650093
650172
  // Disable BiDi, use classic mode
650094
650173
  "goog:chromeOptions": {
@@ -650446,14 +650525,18 @@ function driverSkipDiagnostic({ requestedName, platform, platformMatches, attemp
650446
650525
  msg += ` A present-but-broken driver (for example a partially downloaded ${driverHint}) can cause this; reinstall the driver or its browser.`;
650447
650526
  return msg;
650448
650527
  }
650449
- async function setViewportSize(context, driver) {
650450
- if (context.browser?.viewport?.width || context.browser?.viewport?.height) {
650451
- const viewportSize = await driver.execute("return { width: window.innerWidth, height: window.innerHeight }", []);
650452
- const windowSize = await driver.getWindowSize();
650453
- const deltaWidth = (context.browser?.viewport?.width || viewportSize.width) - viewportSize.width;
650454
- const deltaHeight = (context.browser?.viewport?.height || viewportSize.height) - viewportSize.height;
650455
- await driver.setWindowSize(windowSize.width + deltaWidth, windowSize.height + deltaHeight);
650528
+ async function setViewportSize(context, driver, config = {}) {
650529
+ const vw = Number(context.browser?.viewport?.width);
650530
+ const vh = Number(context.browser?.viewport?.height);
650531
+ if (vw > 0 || vh > 0) {
650532
+ const requested = {
650533
+ ...vw > 0 ? { width: vw } : {},
650534
+ ...vh > 0 ? { height: vh } : {}
650535
+ };
650536
+ const label = `viewport for ${context.browser?.name ?? "browser"} on ${context.platform ?? "host"}`;
650537
+ return realizeViewport(driver, requested, config, label);
650456
650538
  }
650539
+ return void 0;
650457
650540
  }
650458
650541
  async function allowUnsafeSteps({ config }) {
650459
650542
  if (config.allowUnsafeSteps === true)
@@ -652172,8 +652255,10 @@ ${JSON.stringify(context, null, 2)}`);
652172
652255
  driver
652173
652256
  });
652174
652257
  }
652175
- if (context.browser?.viewport?.width || context.browser?.viewport?.height) {
652176
- await setViewportSize(context, driver);
652258
+ const viewportW = Number(context.browser?.viewport?.width);
652259
+ const viewportH = Number(context.browser?.viewport?.height);
652260
+ if (viewportW > 0 || viewportH > 0) {
652261
+ await setViewportSize(context, driver, config);
652177
652262
  } else if (context.browser?.window?.width || context.browser?.window?.height) {
652178
652263
  const windowSize = await driver.getWindowSize();
652179
652264
  await driver.setWindowSize(context.browser?.window?.width || windowSize.width, context.browser?.window?.height || windowSize.height);
@@ -0,0 +1,12 @@
1
+ import type { CommandModule } from "yargs";
2
+ export interface LspArgv {
3
+ stdio: boolean;
4
+ }
5
+ /**
6
+ * `doc-detective lsp` — start the Doc Detective language server. Registered
7
+ * lazily in `src/cli.ts`: the handler imports the server (and its
8
+ * `vscode-languageserver` dependency graph) only when this subcommand runs, so
9
+ * ordinary `runTests` invocations never pay that import cost.
10
+ */
11
+ export declare const lspCommand: CommandModule<{}, LspArgv>;
12
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lsp/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,aAAa,CAAC,EAAE,EAAE,OAAO,CAmBjD,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `doc-detective lsp` — start the Doc Detective language server. Registered
3
+ * lazily in `src/cli.ts`: the handler imports the server (and its
4
+ * `vscode-languageserver` dependency graph) only when this subcommand runs, so
5
+ * ordinary `runTests` invocations never pay that import cost.
6
+ */
7
+ export const lspCommand = {
8
+ command: "lsp",
9
+ describe: "Start the Doc Detective language server (LSP) over stdio for editors and AI agents.",
10
+ builder: (yargs) => yargs.option("stdio", {
11
+ type: "boolean",
12
+ default: true,
13
+ describe: "Communicate over stdio (the only supported transport). Present for explicitness and editor configs.",
14
+ }),
15
+ /* c8 ignore start - thin lazy-load + real stdio server start; the server's
16
+ pure wiring is unit-tested via registerHandlers and end-to-end via the
17
+ spawned protocol test. */
18
+ handler: async () => {
19
+ const { startServer } = await import("./server.js");
20
+ startServer();
21
+ },
22
+ /* c8 ignore stop */
23
+ };
24
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/lsp/command.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAA+B;IACpD,OAAO,EAAE,KAAK;IACd,QAAQ,EACN,qFAAqF;IACvF,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE;QACpB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,IAAI;QACb,QAAQ,EACN,qGAAqG;KACxG,CAA6C;IAChD;;gCAE4B;IAC5B,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACpD,WAAW,EAAE,CAAC;IAChB,CAAC;IACD,oBAAoB;CACrB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { CompletionItem, MarkupKind } from "vscode-languageserver";
2
+ import type { Position } from "vscode-languageserver";
3
+ import type { TextDocument } from "vscode-languageserver-textdocument";
4
+ type JsonPath = Array<string | number>;
5
+ /**
6
+ * Cursor is at a step-object key position: `…/steps/<index>/<partialKey>`.
7
+ * Offers action-key completions.
8
+ */
9
+ export declare function isStepKeyContext(path: JsonPath): boolean;
10
+ /**
11
+ * Cursor is at a key position inside an action object:
12
+ * `…/steps/<index>/<actionKey>/<partialKey>`. Returns the action key, or null.
13
+ */
14
+ export declare function actionFieldContext(path: JsonPath): string | null;
15
+ /** A Markdown documentation payload, or undefined when there's no text. */
16
+ export declare function markdownDoc(text: string | undefined): {
17
+ kind: MarkupKind;
18
+ value: string;
19
+ } | undefined;
20
+ /**
21
+ * Compute completions at a position. Phase 2: action-key completion inside a
22
+ * `steps` element, and field-name completion inside a known action's object.
23
+ * Spec documents only, JSON only, key positions only.
24
+ */
25
+ export declare function computeCompletions(doc: TextDocument, position: Position): CompletionItem[];
26
+ export {};
27
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/lsp/completion.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAGd,UAAU,EAEX,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAKvE,KAAK,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAQxD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAYhE;AAcD,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEjD;AAsDD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,QAAQ,GACjB,cAAc,EAAE,CAyBlB"}
@@ -0,0 +1,114 @@
1
+ import { CompletionItemKind, InsertTextFormat, MarkupKind, TextEdit, } from "vscode-languageserver";
2
+ import { getLocation } from "jsonc-parser";
3
+ import { classifyDocument, isJsonUri } from "./gate.js";
4
+ import { getRegistry } from "./registry.js";
5
+ /**
6
+ * Cursor is at a step-object key position: `…/steps/<index>/<partialKey>`.
7
+ * Offers action-key completions.
8
+ */
9
+ export function isStepKeyContext(path) {
10
+ const n = path.length;
11
+ return (n >= 3 &&
12
+ typeof path[n - 1] === "string" &&
13
+ typeof path[n - 2] === "number" &&
14
+ path[n - 3] === "steps");
15
+ }
16
+ /**
17
+ * Cursor is at a key position inside an action object:
18
+ * `…/steps/<index>/<actionKey>/<partialKey>`. Returns the action key, or null.
19
+ */
20
+ export function actionFieldContext(path) {
21
+ const n = path.length;
22
+ if (n >= 4 &&
23
+ typeof path[n - 1] === "string" &&
24
+ typeof path[n - 2] === "string" &&
25
+ typeof path[n - 3] === "number" &&
26
+ path[n - 4] === "steps") {
27
+ return path[n - 2];
28
+ }
29
+ return null;
30
+ }
31
+ /**
32
+ * The value placeholder inserted after an action key. Quotes the tab-stop only
33
+ * for string scalars — a numeric (`wait`) or boolean (`stopRecord`) action gets
34
+ * a bare placeholder so the starter isn't schema-invalid; object-only actions
35
+ * get a brace body.
36
+ */
37
+ function valueSnippet(primitiveKind) {
38
+ if (primitiveKind === "string")
39
+ return '"$1"';
40
+ if (primitiveKind === "number" || primitiveKind === "boolean")
41
+ return "$1";
42
+ return "{\n\t$1\n}";
43
+ }
44
+ /** A Markdown documentation payload, or undefined when there's no text. */
45
+ export function markdownDoc(text) {
46
+ return text ? { kind: MarkupKind.Markdown, value: text } : undefined;
47
+ }
48
+ /** Build a snippet TextEdit that replaces the partial key node, if present. */
49
+ function keyTextEdit(doc, previousNode, insertText) {
50
+ // When the cursor is on a partial key, jsonc reports the enclosing node whose
51
+ // span covers the key (and any `:value` already typed). We're gated on
52
+ // isAtPropertyKey, so replacing that whole span with the snippet avoids
53
+ // doubled quotes and leftover `:` fragments.
54
+ if (previousNode) {
55
+ const start = doc.positionAt(previousNode.offset);
56
+ const end = doc.positionAt(previousNode.offset + previousNode.length);
57
+ return { textEdit: TextEdit.replace({ start, end }, insertText) };
58
+ }
59
+ // Truly empty object (`{}`): no key token to replace — insert at the cursor.
60
+ return { insertText };
61
+ }
62
+ function actionItem(action, doc, previousNode) {
63
+ const insert = `"${action.key}": ${valueSnippet(action.primitiveKind)}`;
64
+ const edit = keyTextEdit(doc, previousNode, insert);
65
+ return {
66
+ label: action.key,
67
+ kind: CompletionItemKind.Property,
68
+ detail: action.title,
69
+ documentation: markdownDoc(action.description),
70
+ insertTextFormat: InsertTextFormat.Snippet,
71
+ ...edit,
72
+ };
73
+ }
74
+ function fieldItem(field, doc, previousNode) {
75
+ const insert = `"${field.name}": ${valueSnippet(field.primitiveKind)}`;
76
+ const edit = keyTextEdit(doc, previousNode, insert);
77
+ return {
78
+ label: field.name,
79
+ kind: CompletionItemKind.Field,
80
+ documentation: markdownDoc(field.description),
81
+ insertTextFormat: InsertTextFormat.Snippet,
82
+ ...edit,
83
+ };
84
+ }
85
+ /**
86
+ * Compute completions at a position. Phase 2: action-key completion inside a
87
+ * `steps` element, and field-name completion inside a known action's object.
88
+ * Spec documents only, JSON only, key positions only.
89
+ */
90
+ export function computeCompletions(doc, position) {
91
+ const text = doc.getText();
92
+ if (classifyDocument({ uri: doc.uri, text }) !== "spec")
93
+ return [];
94
+ if (!isJsonUri(doc.uri))
95
+ return [];
96
+ const offset = doc.offsetAt(position);
97
+ const location = getLocation(text, offset);
98
+ if (!location.isAtPropertyKey)
99
+ return [];
100
+ const registry = getRegistry();
101
+ const previousNode = location.previousNode;
102
+ if (isStepKeyContext(location.path)) {
103
+ return registry.actions.map((a) => actionItem(a, doc, previousNode));
104
+ }
105
+ const actionKey = actionFieldContext(location.path);
106
+ if (actionKey) {
107
+ const action = registry.byKey.get(actionKey);
108
+ if (action) {
109
+ return action.fields.map((f) => fieldItem(f, doc, previousNode));
110
+ }
111
+ }
112
+ return [];
113
+ }
114
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../../src/lsp/completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACV,QAAQ,GACT,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,WAAW,EAAa,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,WAAW,EAA0C,MAAM,eAAe,CAAC;AAIpF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,OAAO,CACL,CAAC,IAAI,CAAC;QACN,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ;QAC/B,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ;QAC/B,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,CACxB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,IACE,CAAC,IAAI,CAAC;QACN,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ;QAC/B,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ;QAC/B,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ;QAC/B,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,EACvB,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,aAA4B;IAChD,IAAI,aAAa,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC3E,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,WAAW,CACzB,IAAwB;IAExB,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,+EAA+E;AAC/E,SAAS,WAAW,CAClB,GAAiB,EACjB,YAA8B,EAC9B,UAAkB;IAElB,8EAA8E;IAC9E,uEAAuE;IACvE,wEAAwE;IACxE,6CAA6C;IAC7C,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACtE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC;IACpE,CAAC;IACD,6EAA6E;IAC7E,OAAO,EAAE,UAAU,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CACjB,MAAkB,EAClB,GAAiB,EACjB,YAA8B;IAE9B,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;IACxE,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IACpD,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,GAAG;QACjB,IAAI,EAAE,kBAAkB,CAAC,QAAQ;QACjC,MAAM,EAAE,MAAM,CAAC,KAAK;QACpB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC;QAC9C,gBAAgB,EAAE,gBAAgB,CAAC,OAAO;QAC1C,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAChB,KAAkB,EAClB,GAAiB,EACjB,YAA8B;IAE9B,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,MAAM,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;IACvE,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IACpD,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,IAAI;QACjB,IAAI,EAAE,kBAAkB,CAAC,KAAK;QAC9B,aAAa,EAAE,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;QAC7C,gBAAgB,EAAE,gBAAgB,CAAC,OAAO;QAC1C,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAiB,EACjB,QAAkB;IAElB,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;IAC3B,IAAI,gBAAgB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IACnE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,eAAe;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;IAE3C,IAAI,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { Diagnostic } from "vscode-languageserver";
2
+ import type { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { DIAGNOSTIC_SOURCE, ACTION_KEYED_MESSAGE, V2_DEPRECATION_MESSAGE, schemaMessage } from "./messages.js";
4
+ export { DIAGNOSTIC_SOURCE, ACTION_KEYED_MESSAGE, V2_DEPRECATION_MESSAGE, schemaMessage, };
5
+ /**
6
+ * Should this schema error be dropped because an action-keyed step already
7
+ * explains it? Two cases: (1) the error sits at/under the offending step, or
8
+ * (2) it's a vague container `anyOf`/`oneOf` failure on an *ancestor* of that
9
+ * step — the propagation of the same problem up to the test/spec level, which
10
+ * says only "must match a schema in anyOf" and is useless next to the precise
11
+ * action-keyed diagnostic.
12
+ */
13
+ export declare function isSuppressedByActionKeyed(instancePath: string, keyword: string | undefined, suppressedPointers: string[]): boolean;
14
+ /**
15
+ * Compute all diagnostics for a document. Pure over (uri, text): no filesystem,
16
+ * no network. Handles JSON and YAML specs/configs. Returns `[]` for anything the
17
+ * detection gate doesn't recognize and for empty/unparseable buffers (beyond
18
+ * the syntax errors themselves).
19
+ */
20
+ export declare function computeDiagnostics(doc: TextDocument): Diagnostic[];
21
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/lsp/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAGX,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAMvE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,GACd,CAAC;AA4BF;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,kBAAkB,EAAE,MAAM,EAAE,GAC3B,OAAO,CAWT;AAGD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,EAAE,CAwFlE"}