@browserstack/accessibility-devtools-cli 0.0.5 → 0.0.7

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 (2) hide show
  1. package/index.js +162 -76
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -5564,7 +5564,7 @@ var require_command = __commonJS({
5564
5564
  "use strict";
5565
5565
  var EventEmitter = require("node:events").EventEmitter;
5566
5566
  var childProcess = require("node:child_process");
5567
- var path2 = require("node:path");
5567
+ var path3 = require("node:path");
5568
5568
  var fs2 = require("node:fs");
5569
5569
  var process3 = require("node:process");
5570
5570
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -6497,9 +6497,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
6497
6497
  let launchWithNode = false;
6498
6498
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
6499
6499
  function findFile(baseDir, baseName) {
6500
- const localBin = path2.resolve(baseDir, baseName);
6500
+ const localBin = path3.resolve(baseDir, baseName);
6501
6501
  if (fs2.existsSync(localBin)) return localBin;
6502
- if (sourceExt.includes(path2.extname(baseName))) return void 0;
6502
+ if (sourceExt.includes(path3.extname(baseName))) return void 0;
6503
6503
  const foundExt = sourceExt.find(
6504
6504
  (ext) => fs2.existsSync(`${localBin}${ext}`)
6505
6505
  );
@@ -6517,17 +6517,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
6517
6517
  } catch (err) {
6518
6518
  resolvedScriptPath = this._scriptPath;
6519
6519
  }
6520
- executableDir = path2.resolve(
6521
- path2.dirname(resolvedScriptPath),
6520
+ executableDir = path3.resolve(
6521
+ path3.dirname(resolvedScriptPath),
6522
6522
  executableDir
6523
6523
  );
6524
6524
  }
6525
6525
  if (executableDir) {
6526
6526
  let localFile = findFile(executableDir, executableFile);
6527
6527
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
6528
- const legacyName = path2.basename(
6528
+ const legacyName = path3.basename(
6529
6529
  this._scriptPath,
6530
- path2.extname(this._scriptPath)
6530
+ path3.extname(this._scriptPath)
6531
6531
  );
6532
6532
  if (legacyName !== this._name) {
6533
6533
  localFile = findFile(
@@ -6538,7 +6538,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
6538
6538
  }
6539
6539
  executableFile = localFile || executableFile;
6540
6540
  }
6541
- launchWithNode = sourceExt.includes(path2.extname(executableFile));
6541
+ launchWithNode = sourceExt.includes(path3.extname(executableFile));
6542
6542
  let proc;
6543
6543
  if (process3.platform !== "win32") {
6544
6544
  if (launchWithNode) {
@@ -7378,7 +7378,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
7378
7378
  * @return {Command}
7379
7379
  */
7380
7380
  nameFromFilename(filename) {
7381
- this._name = path2.basename(filename, path2.extname(filename));
7381
+ this._name = path3.basename(filename, path3.extname(filename));
7382
7382
  return this;
7383
7383
  }
7384
7384
  /**
@@ -7392,9 +7392,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
7392
7392
  * @param {string} [path]
7393
7393
  * @return {(string|null|Command)}
7394
7394
  */
7395
- executableDir(path3) {
7396
- if (path3 === void 0) return this._executableDir;
7397
- this._executableDir = path3;
7395
+ executableDir(path4) {
7396
+ if (path4 === void 0) return this._executableDir;
7397
+ this._executableDir = path4;
7398
7398
  return this;
7399
7399
  }
7400
7400
  /**
@@ -7639,19 +7639,19 @@ var require_globrex = __commonJS({
7639
7639
  function globrex(glob2, { extended = false, globstar = false, strict = false, filepath = false, flags = "" } = {}) {
7640
7640
  let regex = "";
7641
7641
  let segment = "";
7642
- let path2 = { regex: "", segments: [] };
7642
+ let path3 = { regex: "", segments: [] };
7643
7643
  let inGroup = false;
7644
7644
  let inRange = false;
7645
7645
  const ext = [];
7646
7646
  function add(str, { split, last, only } = {}) {
7647
7647
  if (only !== "path") regex += str;
7648
7648
  if (filepath && only !== "regex") {
7649
- path2.regex += str === "\\/" ? SEP : str;
7649
+ path3.regex += str === "\\/" ? SEP : str;
7650
7650
  if (split) {
7651
7651
  if (last) segment += str;
7652
7652
  if (segment !== "") {
7653
7653
  if (!flags.includes("g")) segment = `^${segment}$`;
7654
- path2.segments.push(new RegExp(segment, flags));
7654
+ path3.segments.push(new RegExp(segment, flags));
7655
7655
  }
7656
7656
  segment = "";
7657
7657
  } else {
@@ -7836,14 +7836,14 @@ var require_globrex = __commonJS({
7836
7836
  if (!flags.includes("g")) {
7837
7837
  regex = `^${regex}$`;
7838
7838
  segment = `^${segment}$`;
7839
- if (filepath) path2.regex = `^${path2.regex}$`;
7839
+ if (filepath) path3.regex = `^${path3.regex}$`;
7840
7840
  }
7841
7841
  const result = { regex: new RegExp(regex, flags) };
7842
7842
  if (filepath) {
7843
- path2.segments.push(new RegExp(segment, flags));
7844
- path2.regex = new RegExp(path2.regex, flags);
7845
- path2.globstar = new RegExp(!flags.includes("g") ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags);
7846
- result.path = path2;
7843
+ path3.segments.push(new RegExp(segment, flags));
7844
+ path3.regex = new RegExp(path3.regex, flags);
7845
+ path3.globstar = new RegExp(!flags.includes("g") ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags);
7846
+ result.path = path3;
7847
7847
  }
7848
7848
  return result;
7849
7849
  }
@@ -7856,7 +7856,7 @@ var require_src = __commonJS({
7856
7856
  "../node_modules/globalyzer/src/index.js"(exports2, module2) {
7857
7857
  "use strict";
7858
7858
  var os2 = require("os");
7859
- var path2 = require("path");
7859
+ var path3 = require("path");
7860
7860
  var isWin = os2.platform() === "win32";
7861
7861
  var CHARS = { "{": "}", "(": ")", "[": "]" };
7862
7862
  var STRICT = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\)|(\\).|([@?!+*]\(.*\)))/;
@@ -7883,7 +7883,7 @@ var require_src = __commonJS({
7883
7883
  if (/[\{\[].*[\/]*.*[\}\]]$/.test(str)) str += "/";
7884
7884
  str += "a";
7885
7885
  do {
7886
- str = path2.dirname(str);
7886
+ str = path3.dirname(str);
7887
7887
  } while (isglob(str, { strict }) || /(^|[^\\])([\{\[]|\([^\)]+$)/.test(str));
7888
7888
  return str.replace(/\\([\*\?\|\[\]\(\)\{\}])/g, "$1");
7889
7889
  }
@@ -7898,7 +7898,7 @@ var require_src = __commonJS({
7898
7898
  glob2 = pattern;
7899
7899
  }
7900
7900
  if (!isGlob) {
7901
- base = path2.dirname(pattern);
7901
+ base = path3.dirname(pattern);
7902
7902
  glob2 = base !== "." ? pattern.substr(base.length) : pattern;
7903
7903
  }
7904
7904
  if (glob2.startsWith("./")) glob2 = glob2.substr(2);
@@ -7963,9 +7963,9 @@ var require_tiny_glob = __commonJS({
7963
7963
  }
7964
7964
  if (opts.flush) CACHE = {};
7965
7965
  let matches = [];
7966
- const { path: path2 } = globrex(glob2.glob, { filepath: true, globstar: true, extended: true });
7967
- path2.globstar = path2.globstar.toString();
7968
- await walk(matches, glob2.base, path2, opts, ".", 0);
7966
+ const { path: path3 } = globrex(glob2.glob, { filepath: true, globstar: true, extended: true });
7967
+ path3.globstar = path3.globstar.toString();
7968
+ await walk(matches, glob2.base, path3, opts, ".", 0);
7969
7969
  return opts.absolute ? matches.map((x) => resolve(opts.cwd, x)) : matches;
7970
7970
  };
7971
7971
  }
@@ -8474,7 +8474,6 @@ var source_default = chalk;
8474
8474
  // src/index.ts
8475
8475
  var fs = __toESM(require("fs/promises"));
8476
8476
  var import_node_perf_hooks = require("node:perf_hooks");
8477
- var path = __toESM(require("path"));
8478
8477
 
8479
8478
  // ../node_modules/uuid/dist/esm/stringify.js
8480
8479
  var byteToHex = [];
@@ -8529,7 +8528,7 @@ var v4_default = v4;
8529
8528
 
8530
8529
  // src/buildConfig.ts
8531
8530
  var DEBUG = "production"?.toLocaleLowerCase() !== "production";
8532
- var LINTER_SERVER_ADDRESS = "wss://browserstack.com/ws";
8531
+ var LINTER_SERVER_ADDRESS = "wss://devtools-a11y-linter.browserstack.com/ws";
8533
8532
  var EDS_API_KEY = "5PJymLNdWrOwzQNC7J6SXBuUFQGWq4Vuw";
8534
8533
  var EDS_BACKEND = "eds.browserstack.com";
8535
8534
 
@@ -8576,6 +8575,7 @@ function parseArgs(args = process.argv) {
8576
8575
  return {
8577
8576
  include: opts.include,
8578
8577
  exclude: opts.exclude,
8578
+ format: opts.format,
8579
8579
  browserstackUsername: opts.username,
8580
8580
  browserstackAccessKey: opts.accessKey,
8581
8581
  nonStrict: !!opts.nonStrict
@@ -8606,6 +8606,106 @@ async function resolveLintFiles(args) {
8606
8606
  return files;
8607
8607
  }
8608
8608
 
8609
+ // src/formatters.ts
8610
+ var path2 = __toESM(require("path"));
8611
+ function tryParseMessage(message) {
8612
+ try {
8613
+ const parsed = JSON.parse(message);
8614
+ if (parsed && typeof parsed === "object") {
8615
+ return {
8616
+ ...parsed,
8617
+ description: parsed.description || message
8618
+ };
8619
+ }
8620
+ return null;
8621
+ } catch {
8622
+ return null;
8623
+ }
8624
+ }
8625
+ function formatLocation(filePath, line, column, endLine, endColumn) {
8626
+ const relativePath = path2.relative(process.cwd(), filePath);
8627
+ const endPos = endLine ? `-${endLine}:${endColumn || ""}` : "";
8628
+ return `${relativePath}:${line}:${column}${endPos}`;
8629
+ }
8630
+ function formatText(results) {
8631
+ return results.filter((r) => r.filePath && r.messages?.length > 0).flatMap(
8632
+ (r) => r.messages.map((msg) => {
8633
+ const { ruleId, message, line, column, endLine, endColumn } = msg;
8634
+ const parsed = tryParseMessage(message);
8635
+ if (!parsed) {
8636
+ return [
8637
+ source_default.cyan(formatLocation(r.filePath, line, column, endLine, endColumn)),
8638
+ source_default.yellow(`Rule: ${ruleId}`),
8639
+ source_default.white(`Description: ${message}`)
8640
+ ].join("\n");
8641
+ }
8642
+ const ruleName = ruleId?.includes("/") ? ruleId.split("/")[1] : ruleId;
8643
+ const lines = [
8644
+ source_default.cyan(formatLocation(r.filePath, line, column, endLine, endColumn)),
8645
+ source_default.yellow(`Rule: ${ruleName}`),
8646
+ source_default.white(`Description: ${parsed.description}`),
8647
+ parsed.help && source_default.green(`Help: ${parsed.help}`),
8648
+ parsed.failureSummary && source_default.magenta(`Failure Summary: ${parsed.failureSummary}`)
8649
+ ];
8650
+ return lines.filter(Boolean).join("\n");
8651
+ })
8652
+ ).join("\n\n");
8653
+ }
8654
+ function formatXcode(results) {
8655
+ return results.filter((r) => r.filePath && r.messages?.length > 0).flatMap(
8656
+ (r) => r.messages.map((msg) => {
8657
+ const { ruleId, message, line, column, severity } = msg;
8658
+ const parsed = tryParseMessage(message);
8659
+ const type = severity === 2 ? "error" : "warning";
8660
+ let text;
8661
+ if (parsed) {
8662
+ const { description, failureSummary, ruleName } = parsed;
8663
+ const finalM = [description];
8664
+ if (ruleName) {
8665
+ finalM.unshift(`${ruleName}: `);
8666
+ }
8667
+ if (failureSummary && failureSummary.trim().length > 0 && !["not applicable", "na", "n/a"].includes(failureSummary.toLowerCase())) {
8668
+ finalM.push(
8669
+ " ".repeat(600),
8670
+ // blank line
8671
+ "\u2800",
8672
+ " ".repeat(600),
8673
+ // blank line
8674
+ "How to fix:",
8675
+ " ".repeat(600),
8676
+ // End the How to fix last line
8677
+ failureSummary ?? "",
8678
+ " ".repeat(600),
8679
+ // blank line
8680
+ "\u2800",
8681
+ " ".repeat(600)
8682
+ // blank line
8683
+ );
8684
+ }
8685
+ finalM.push(`(Browserstack Accessibility DevTools/${ruleId.split("/")[1]})`);
8686
+ text = finalM.join("");
8687
+ } else {
8688
+ text = message;
8689
+ }
8690
+ const fileRelative = path2.relative(process.cwd(), r.filePath);
8691
+ return `${fileRelative}:${line}:${column}: ${type}: ${text}`;
8692
+ })
8693
+ ).join("\n");
8694
+ }
8695
+ function formatResults(results, format) {
8696
+ switch (format) {
8697
+ case "xcode":
8698
+ return formatXcode(results);
8699
+ // case 'junit':
8700
+ // return formatJUnit(results);
8701
+ // case 'json':
8702
+ // return formatJson(results);
8703
+ case "text":
8704
+ default:
8705
+ return formatText(results);
8706
+ }
8707
+ }
8708
+
8609
8709
  // src/index.ts
8610
8710
  var EXIT_CODES = {
8611
8711
  SUCCESS: 0,
@@ -8624,49 +8724,6 @@ var mockLogger = {
8624
8724
  log: () => {
8625
8725
  }
8626
8726
  };
8627
- function safeParseMessage(message) {
8628
- try {
8629
- const { description, help, failureSummary } = JSON.parse(message);
8630
- return {
8631
- success: true,
8632
- data: {
8633
- description: description || message,
8634
- help: help || "",
8635
- failureSummary: failureSummary || ""
8636
- }
8637
- };
8638
- } catch {
8639
- return { success: false, error: "Invalid JSON message" };
8640
- }
8641
- }
8642
- function formatLocation(filePath, line, column, endLine, endColumn) {
8643
- const relativePath = path.relative(process.cwd(), filePath);
8644
- const endPos = endLine ? `-${endLine}:${endColumn || ""}` : "";
8645
- return `${relativePath}:${line}:${column}${endPos}`;
8646
- }
8647
- function formatMessage(msg, filePath) {
8648
- const { ruleId, message, severity, line, column, endLine, endColumn } = msg;
8649
- const parsed = safeParseMessage(message);
8650
- if (!parsed.success) {
8651
- return [
8652
- source_default.cyan(formatLocation(filePath, line, column, endLine, endColumn)),
8653
- source_default.yellow(`Rule: ${ruleId}`),
8654
- source_default.white(`Description: ${message}`)
8655
- ].join("\n");
8656
- }
8657
- const { description, help, failureSummary } = parsed.data;
8658
- const lines = [
8659
- source_default.cyan(formatLocation(filePath, line, column, endLine, endColumn)),
8660
- source_default.yellow(`Rule: ${ruleId.split("/")[1]}`),
8661
- source_default.white(`Description: ${description}`),
8662
- help && source_default.green(`Help: ${help}`),
8663
- failureSummary && source_default.magenta(`Failure Summary: ${failureSummary}`)
8664
- ];
8665
- return lines.filter(Boolean).join("\n");
8666
- }
8667
- function formatResults(results) {
8668
- return results.filter((result) => result.filePath && result.messages?.length > 0).flatMap((result) => result.messages.map((msg) => formatMessage(msg, result.filePath))).filter(Boolean).join("\n\n");
8669
- }
8670
8727
  async function initializeAndAuthenticate(linterClient, args) {
8671
8728
  const { browserstackUsername, browserstackAccessKey } = args;
8672
8729
  if (!browserstackUsername || !browserstackAccessKey) {
@@ -8678,22 +8735,29 @@ async function initializeAndAuthenticate(linterClient, args) {
8678
8735
  try {
8679
8736
  const linterInitResult = await linterClient.initialize();
8680
8737
  if (linterInitResult instanceof Error) {
8681
- return { success: false, error: "Unable to connect to BrowserStack backend" };
8738
+ return {
8739
+ success: false,
8740
+ error: "Unable to connect to BrowserStack. Please check your network connection."
8741
+ };
8682
8742
  }
8683
8743
  const userProfile = await linterClient.authenticate(
8684
8744
  browserstackUsername,
8685
8745
  browserstackAccessKey
8686
8746
  );
8687
8747
  if (!userProfile || typeof userProfile.id !== "string") {
8688
- return { success: false, error: "Authentication failed. Please check your credentials." };
8748
+ return {
8749
+ success: false,
8750
+ error: "Unable to authenticate. Please check your credentials or plan."
8751
+ };
8689
8752
  }
8690
8753
  return { success: true, data: userProfile };
8691
8754
  } catch (e) {
8692
- return { success: false, error: e instanceof Error ? e.message : String(e) };
8755
+ return { success: false, error: "Something went wrong on our end. Please try again later." };
8693
8756
  }
8694
8757
  }
8695
8758
  function computeAnalytics(fileTimings, ruleCounts, perFileRuleRates, totalTimeTaken) {
8696
8759
  return {
8760
+ source: "cli",
8697
8761
  rule_counts: ruleCounts,
8698
8762
  averages: {
8699
8763
  per_file: fileTimings.length ? Math.round(fileTimings.reduce((a, b) => a + b, 0) / fileTimings.length) : 0,
@@ -8704,6 +8768,23 @@ function computeAnalytics(fileTimings, ruleCounts, perFileRuleRates, totalTimeTa
8704
8768
  total_time_taken: totalTimeTaken
8705
8769
  };
8706
8770
  }
8771
+ function inferOutputFormat(args) {
8772
+ const {
8773
+ XCODE_PRODUCT_BUILD_VERSION,
8774
+ XCODE_VERSION_MAJOR,
8775
+ XCODE_VERSION_MINOR,
8776
+ XCODE_VERSION_ACTUAL,
8777
+ XCODE_APP_SUPPORT_DIR
8778
+ } = process.env;
8779
+ switch (true) {
8780
+ case Boolean(
8781
+ XCODE_APP_SUPPORT_DIR || XCODE_PRODUCT_BUILD_VERSION || XCODE_VERSION_MAJOR || XCODE_VERSION_MINOR || XCODE_VERSION_ACTUAL
8782
+ ):
8783
+ return "xcode";
8784
+ default:
8785
+ return "text";
8786
+ }
8787
+ }
8707
8788
  async function main(args) {
8708
8789
  const linterClient = import_linterClient.default.getInstance({
8709
8790
  linterServerAddress: LINTER_SERVER_ADDRESS,
@@ -8728,9 +8809,14 @@ async function main(args) {
8728
8809
  process.exit(EXIT_CODES.SUCCESS);
8729
8810
  }
8730
8811
  if (fileList.some((file) => !linterClient.isFileExtensionSupported(file))) {
8812
+ const unsupportedExtensions = Array.from(
8813
+ new Set(
8814
+ fileList.filter((file) => !linterClient.isFileExtensionSupported(file)).map((file) => path.extname(file))
8815
+ )
8816
+ ).join(", ");
8731
8817
  console.error(
8732
8818
  source_default.red(
8733
- `Error: Unsupported file types. Supported extensions are: ${linterClient.getSupportedFileExtensions().join(", ")}`
8819
+ `{${unsupportedExtensions}} is not supported. Supported file types are ${linterClient.getSupportedFileExtensions().join(", ")}`
8734
8820
  )
8735
8821
  );
8736
8822
  process.exit(1);
@@ -8776,7 +8862,7 @@ async function main(args) {
8776
8862
  console.log(source_default.green("No accessibility violations found! Awesome!"));
8777
8863
  process.exit(EXIT_CODES.SUCCESS);
8778
8864
  }
8779
- console.log(formatResults(lintResultsFlat));
8865
+ console.log(formatResults(lintResultsFlat, inferOutputFormat(args)));
8780
8866
  process.exit(
8781
8867
  lintResultsFlat.length > 0 ? args.nonStrict ? EXIT_CODES.SUCCESS : EXIT_CODES.FAILURE : EXIT_CODES.SUCCESS
8782
8868
  );
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@browserstack/accessibility-devtools-cli",
3
3
  "displayName": "BrowserStack Accessibility Linter CLI (Beta)",
4
4
  "description": "Command-line interface for BrowserStack Accessibility Linter",
5
- "version": "0.0.5",
5
+ "version": "0.0.7",
6
6
  "main": "./index.js",
7
7
  "author": {
8
8
  "name": "Rishabh Jain",
@@ -17,4 +17,4 @@
17
17
  "scripts": {},
18
18
  "devDependencies": {},
19
19
  "dependencies": {}
20
- }
20
+ }