next-a11y 0.1.6 → 0.1.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.
- package/dist/cli/index.js +67 -62
- package/dist/cli/index.mjs +67 -62
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -24,13 +24,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
|
|
25
25
|
// src/cli/index.ts
|
|
26
26
|
var fs9 = __toESM(require("fs"));
|
|
27
|
-
var
|
|
27
|
+
var path10 = __toESM(require("path"));
|
|
28
28
|
var import_dotenv2 = require("dotenv");
|
|
29
29
|
var import_commander = require("commander");
|
|
30
30
|
|
|
31
31
|
// src/cli/scan-command.ts
|
|
32
32
|
var fs7 = __toESM(require("fs"));
|
|
33
|
-
var
|
|
33
|
+
var path8 = __toESM(require("path"));
|
|
34
34
|
var import_dotenv = require("dotenv");
|
|
35
35
|
var import_picocolors4 = __toESM(require("picocolors"));
|
|
36
36
|
|
|
@@ -145,7 +145,7 @@ function deepMerge(target, source) {
|
|
|
145
145
|
|
|
146
146
|
// src/scan/scan.ts
|
|
147
147
|
var fs6 = __toESM(require("fs"));
|
|
148
|
-
var
|
|
148
|
+
var path7 = __toESM(require("path"));
|
|
149
149
|
var import_ts_morph19 = require("ts-morph");
|
|
150
150
|
|
|
151
151
|
// src/scan/glob.ts
|
|
@@ -157,13 +157,13 @@ async function discoverFiles(basePath, include, exclude) {
|
|
|
157
157
|
if (typeof fs2.glob === "function") {
|
|
158
158
|
for (const pattern of include) {
|
|
159
159
|
try {
|
|
160
|
-
const matches = await new Promise((
|
|
160
|
+
const matches = await new Promise((resolve7, reject) => {
|
|
161
161
|
fs2.glob(
|
|
162
162
|
pattern,
|
|
163
163
|
{ cwd: absBase },
|
|
164
164
|
(err, files) => {
|
|
165
165
|
if (err) reject(err);
|
|
166
|
-
else
|
|
166
|
+
else resolve7(files);
|
|
167
167
|
}
|
|
168
168
|
);
|
|
169
169
|
});
|
|
@@ -1694,6 +1694,8 @@ function removeElement(file, line) {
|
|
|
1694
1694
|
}
|
|
1695
1695
|
|
|
1696
1696
|
// src/ai/create-provider.ts
|
|
1697
|
+
var import_node_module = require("module");
|
|
1698
|
+
var path4 = __toESM(require("path"));
|
|
1697
1699
|
var PROVIDER_PACKAGES = {
|
|
1698
1700
|
openai: "@ai-sdk/openai",
|
|
1699
1701
|
anthropic: "@ai-sdk/anthropic",
|
|
@@ -1708,9 +1710,12 @@ var PROVIDER_INSTALL = {
|
|
|
1708
1710
|
};
|
|
1709
1711
|
function createProvider(provider, model) {
|
|
1710
1712
|
const pkg2 = PROVIDER_PACKAGES[provider];
|
|
1713
|
+
const projectRequire = (0, import_node_module.createRequire)(
|
|
1714
|
+
path4.resolve(process.cwd(), "package.json")
|
|
1715
|
+
);
|
|
1711
1716
|
let mod;
|
|
1712
1717
|
try {
|
|
1713
|
-
mod =
|
|
1718
|
+
mod = projectRequire(pkg2);
|
|
1714
1719
|
} catch {
|
|
1715
1720
|
throw new Error(
|
|
1716
1721
|
`AI provider "${provider}" requires the "${pkg2}" package.
|
|
@@ -1789,12 +1794,12 @@ async function generate(options) {
|
|
|
1789
1794
|
|
|
1790
1795
|
// src/cache/fs-cache.ts
|
|
1791
1796
|
var fs4 = __toESM(require("fs"));
|
|
1792
|
-
var
|
|
1797
|
+
var path5 = __toESM(require("path"));
|
|
1793
1798
|
var crypto = __toESM(require("crypto"));
|
|
1794
1799
|
var FsCache = class {
|
|
1795
1800
|
constructor(cacheDir) {
|
|
1796
1801
|
this.cacheDir = cacheDir;
|
|
1797
|
-
this.cachePath =
|
|
1802
|
+
this.cachePath = path5.join(cacheDir, "cache.json");
|
|
1798
1803
|
this.data = this.load();
|
|
1799
1804
|
}
|
|
1800
1805
|
load() {
|
|
@@ -1936,7 +1941,7 @@ function buildImgAltPrompt(context) {
|
|
|
1936
1941
|
|
|
1937
1942
|
// src/rules/img-alt/img-alt.resolve.ts
|
|
1938
1943
|
var fs5 = __toESM(require("fs"));
|
|
1939
|
-
var
|
|
1944
|
+
var path6 = __toESM(require("path"));
|
|
1940
1945
|
var https = __toESM(require("https"));
|
|
1941
1946
|
var http = __toESM(require("http"));
|
|
1942
1947
|
var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg", ".avif"];
|
|
@@ -1944,7 +1949,7 @@ function isImagePath(p) {
|
|
|
1944
1949
|
return IMAGE_EXTENSIONS.some((ext) => p.endsWith(ext));
|
|
1945
1950
|
}
|
|
1946
1951
|
async function resolveImageSource(src, file, projectRoot) {
|
|
1947
|
-
if (
|
|
1952
|
+
if (path6.isAbsolute(src) && isImagePath(src)) {
|
|
1948
1953
|
try {
|
|
1949
1954
|
const buffer = fs5.readFileSync(src);
|
|
1950
1955
|
return { type: "file", buffer, path: src };
|
|
@@ -1952,7 +1957,7 @@ async function resolveImageSource(src, file, projectRoot) {
|
|
|
1952
1957
|
}
|
|
1953
1958
|
}
|
|
1954
1959
|
if (src.startsWith("/")) {
|
|
1955
|
-
const publicPath =
|
|
1960
|
+
const publicPath = path6.join(projectRoot, "public", src);
|
|
1956
1961
|
try {
|
|
1957
1962
|
const buffer = fs5.readFileSync(publicPath);
|
|
1958
1963
|
return { type: "file", buffer, path: publicPath };
|
|
@@ -1962,7 +1967,7 @@ async function resolveImageSource(src, file, projectRoot) {
|
|
|
1962
1967
|
}
|
|
1963
1968
|
if (src.startsWith(".")) {
|
|
1964
1969
|
const filePath = file.getFilePath();
|
|
1965
|
-
const resolved =
|
|
1970
|
+
const resolved = path6.resolve(path6.dirname(filePath), src);
|
|
1966
1971
|
try {
|
|
1967
1972
|
const buffer = fs5.readFileSync(resolved);
|
|
1968
1973
|
return { type: "file", buffer, path: resolved };
|
|
@@ -2026,7 +2031,7 @@ function resolveModuleToImage(moduleSpecifier, fromFile, projectRoot, namedExpor
|
|
|
2026
2031
|
function resolveModulePath(moduleSpecifier, fromFile, projectRoot, project) {
|
|
2027
2032
|
let resolved;
|
|
2028
2033
|
if (moduleSpecifier.startsWith(".")) {
|
|
2029
|
-
resolved =
|
|
2034
|
+
resolved = path6.resolve(path6.dirname(fromFile), moduleSpecifier);
|
|
2030
2035
|
} else {
|
|
2031
2036
|
const aliasResolved = resolvePathAlias(moduleSpecifier, projectRoot, project);
|
|
2032
2037
|
if (aliasResolved) {
|
|
@@ -2045,7 +2050,7 @@ function resolveModulePath(moduleSpecifier, fromFile, projectRoot, project) {
|
|
|
2045
2050
|
}
|
|
2046
2051
|
const indexFiles = ["index.ts", "index.tsx", "index.js", "index.jsx"];
|
|
2047
2052
|
for (const idx of indexFiles) {
|
|
2048
|
-
const indexPath =
|
|
2053
|
+
const indexPath = path6.join(resolved, idx);
|
|
2049
2054
|
if (fs5.existsSync(indexPath)) return indexPath;
|
|
2050
2055
|
}
|
|
2051
2056
|
return void 0;
|
|
@@ -2060,7 +2065,7 @@ function followReExport(barrelPath, exportName) {
|
|
|
2060
2065
|
if (match) {
|
|
2061
2066
|
const reExportPath = match[1];
|
|
2062
2067
|
if (isImagePath(reExportPath)) {
|
|
2063
|
-
return
|
|
2068
|
+
return path6.resolve(path6.dirname(barrelPath), reExportPath);
|
|
2064
2069
|
}
|
|
2065
2070
|
}
|
|
2066
2071
|
} catch {
|
|
@@ -2080,13 +2085,13 @@ function resolvePathAlias(moduleSpecifier, projectRoot, project) {
|
|
|
2080
2085
|
const rest = moduleSpecifier.slice(prefix.length);
|
|
2081
2086
|
for (const mapping of mappings) {
|
|
2082
2087
|
const mappingBase = mapping.endsWith("/*") ? mapping.slice(0, -1) : mapping;
|
|
2083
|
-
const resolved =
|
|
2088
|
+
const resolved = path6.resolve(baseDir, mappingBase + rest);
|
|
2084
2089
|
return resolved;
|
|
2085
2090
|
}
|
|
2086
2091
|
}
|
|
2087
2092
|
} else if (pattern === moduleSpecifier) {
|
|
2088
2093
|
if (mappings.length > 0) {
|
|
2089
|
-
return
|
|
2094
|
+
return path6.resolve(baseDir, mappings[0]);
|
|
2090
2095
|
}
|
|
2091
2096
|
}
|
|
2092
2097
|
}
|
|
@@ -2096,22 +2101,22 @@ function escapeRegex(str) {
|
|
|
2096
2101
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2097
2102
|
}
|
|
2098
2103
|
function findProjectRootFromFile(filePath) {
|
|
2099
|
-
let dir =
|
|
2100
|
-
while (dir !==
|
|
2101
|
-
if (fs5.existsSync(
|
|
2102
|
-
if (fs5.existsSync(
|
|
2103
|
-
if (fs5.existsSync(
|
|
2104
|
-
if (fs5.existsSync(
|
|
2105
|
-
dir =
|
|
2104
|
+
let dir = path6.dirname(filePath);
|
|
2105
|
+
while (dir !== path6.dirname(dir)) {
|
|
2106
|
+
if (fs5.existsSync(path6.join(dir, "package.json"))) return dir;
|
|
2107
|
+
if (fs5.existsSync(path6.join(dir, "next.config.js"))) return dir;
|
|
2108
|
+
if (fs5.existsSync(path6.join(dir, "next.config.mjs"))) return dir;
|
|
2109
|
+
if (fs5.existsSync(path6.join(dir, "next.config.ts"))) return dir;
|
|
2110
|
+
dir = path6.dirname(dir);
|
|
2106
2111
|
}
|
|
2107
|
-
return
|
|
2112
|
+
return path6.dirname(filePath);
|
|
2108
2113
|
}
|
|
2109
2114
|
function fetchImage(url) {
|
|
2110
|
-
return new Promise((
|
|
2115
|
+
return new Promise((resolve7, reject) => {
|
|
2111
2116
|
const client = url.startsWith("https") ? https : http;
|
|
2112
2117
|
const req = client.get(url, { timeout: 1e4 }, (res) => {
|
|
2113
2118
|
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
2114
|
-
fetchImage(res.headers.location).then(
|
|
2119
|
+
fetchImage(res.headers.location).then(resolve7).catch(reject);
|
|
2115
2120
|
return;
|
|
2116
2121
|
}
|
|
2117
2122
|
const chunks = [];
|
|
@@ -2126,7 +2131,7 @@ function fetchImage(url) {
|
|
|
2126
2131
|
}
|
|
2127
2132
|
chunks.push(chunk);
|
|
2128
2133
|
});
|
|
2129
|
-
res.on("end", () =>
|
|
2134
|
+
res.on("end", () => resolve7(Buffer.concat(chunks)));
|
|
2130
2135
|
res.on("error", reject);
|
|
2131
2136
|
});
|
|
2132
2137
|
req.on("error", reject);
|
|
@@ -2302,28 +2307,28 @@ function findElement(file, line) {
|
|
|
2302
2307
|
return elements.find((el) => el.getStartLineNumber() === line);
|
|
2303
2308
|
}
|
|
2304
2309
|
function findProjectRoot(filePath) {
|
|
2305
|
-
const
|
|
2310
|
+
const path11 = require("path");
|
|
2306
2311
|
const fs10 = require("fs");
|
|
2307
|
-
let dir =
|
|
2308
|
-
while (dir !==
|
|
2309
|
-
if (fs10.existsSync(
|
|
2310
|
-
if (fs10.existsSync(
|
|
2311
|
-
if (fs10.existsSync(
|
|
2312
|
-
if (fs10.existsSync(
|
|
2313
|
-
dir =
|
|
2312
|
+
let dir = path11.dirname(filePath);
|
|
2313
|
+
while (dir !== path11.dirname(dir)) {
|
|
2314
|
+
if (fs10.existsSync(path11.join(dir, "package.json"))) return dir;
|
|
2315
|
+
if (fs10.existsSync(path11.join(dir, "next.config.js"))) return dir;
|
|
2316
|
+
if (fs10.existsSync(path11.join(dir, "next.config.mjs"))) return dir;
|
|
2317
|
+
if (fs10.existsSync(path11.join(dir, "next.config.ts"))) return dir;
|
|
2318
|
+
dir = path11.dirname(dir);
|
|
2314
2319
|
}
|
|
2315
|
-
return
|
|
2320
|
+
return path11.dirname(filePath);
|
|
2316
2321
|
}
|
|
2317
2322
|
|
|
2318
2323
|
// src/scan/scan.ts
|
|
2319
2324
|
function resolveTargetPath(targetPath) {
|
|
2320
|
-
const absPath =
|
|
2325
|
+
const absPath = path7.resolve(targetPath);
|
|
2321
2326
|
if (!fs6.existsSync(absPath)) {
|
|
2322
2327
|
throw new Error(`Path does not exist: ${absPath}`);
|
|
2323
2328
|
}
|
|
2324
2329
|
const stat = fs6.statSync(absPath);
|
|
2325
2330
|
if (stat.isFile()) {
|
|
2326
|
-
return
|
|
2331
|
+
return path7.dirname(absPath);
|
|
2327
2332
|
}
|
|
2328
2333
|
return absPath;
|
|
2329
2334
|
}
|
|
@@ -2334,7 +2339,7 @@ async function detect(targetPath, config2) {
|
|
|
2334
2339
|
config2.scanner.include,
|
|
2335
2340
|
config2.scanner.exclude
|
|
2336
2341
|
);
|
|
2337
|
-
const tsconfigPath =
|
|
2342
|
+
const tsconfigPath = path7.join(absPath, "tsconfig.json");
|
|
2338
2343
|
const project = new import_ts_morph19.Project({
|
|
2339
2344
|
tsConfigFilePath: fs6.existsSync(tsconfigPath) ? tsconfigPath : void 0,
|
|
2340
2345
|
skipAddingFilesFromTsConfig: true,
|
|
@@ -2642,7 +2647,7 @@ async function interactiveReview(violations, onAccept) {
|
|
|
2642
2647
|
return { applied, skipped };
|
|
2643
2648
|
}
|
|
2644
2649
|
function promptAction() {
|
|
2645
|
-
return new Promise((
|
|
2650
|
+
return new Promise((resolve7) => {
|
|
2646
2651
|
const rl = readline.createInterface({
|
|
2647
2652
|
input: process.stdin,
|
|
2648
2653
|
output: process.stdout
|
|
@@ -2653,10 +2658,10 @@ function promptAction() {
|
|
|
2653
2658
|
(answer) => {
|
|
2654
2659
|
rl.close();
|
|
2655
2660
|
const normalized = answer.trim().toLowerCase();
|
|
2656
|
-
if (normalized === "n" || normalized === "no")
|
|
2657
|
-
else if (normalized === "s" || normalized === "skip")
|
|
2658
|
-
else if (normalized === "q" || normalized === "quit")
|
|
2659
|
-
else
|
|
2661
|
+
if (normalized === "n" || normalized === "no") resolve7("no");
|
|
2662
|
+
else if (normalized === "s" || normalized === "skip") resolve7("skip");
|
|
2663
|
+
else if (normalized === "q" || normalized === "quit") resolve7("quit");
|
|
2664
|
+
else resolve7("yes");
|
|
2660
2665
|
}
|
|
2661
2666
|
);
|
|
2662
2667
|
});
|
|
@@ -2666,20 +2671,20 @@ function promptAction() {
|
|
|
2666
2671
|
function registerScanCommand(program2) {
|
|
2667
2672
|
const version = program2.version();
|
|
2668
2673
|
program2.command("scan").description("Scan files for accessibility issues").argument("<path>", "Path to scan").option("--fix", "Auto-fix issues").option("-i, --interactive", "Review each fix interactively").option("--no-ai", "Skip AI-powered fixes").option("--provider <provider>", "Override AI provider").option("--model <model>", "Override AI model").option("--min-score <score>", "Minimum score threshold (exit code 1 if below)", parseInt).action(async (targetPath, options) => {
|
|
2669
|
-
let envDir =
|
|
2674
|
+
let envDir = path8.resolve(targetPath);
|
|
2670
2675
|
if (fs7.existsSync(envDir) && fs7.statSync(envDir).isFile()) {
|
|
2671
|
-
envDir =
|
|
2676
|
+
envDir = path8.dirname(envDir);
|
|
2672
2677
|
}
|
|
2673
2678
|
let searchDir = envDir;
|
|
2674
|
-
while (searchDir !==
|
|
2679
|
+
while (searchDir !== path8.dirname(searchDir)) {
|
|
2675
2680
|
for (const envFile of [".env", ".env.local"]) {
|
|
2676
|
-
const envPath =
|
|
2681
|
+
const envPath = path8.join(searchDir, envFile);
|
|
2677
2682
|
if (fs7.existsSync(envPath)) {
|
|
2678
2683
|
(0, import_dotenv.config)({ path: envPath, override: false, quiet: true });
|
|
2679
2684
|
}
|
|
2680
2685
|
}
|
|
2681
|
-
if (fs7.existsSync(
|
|
2682
|
-
searchDir =
|
|
2686
|
+
if (fs7.existsSync(path8.join(searchDir, "package.json"))) break;
|
|
2687
|
+
searchDir = path8.dirname(searchDir);
|
|
2683
2688
|
}
|
|
2684
2689
|
const fileConfig = await loadConfigFile(process.cwd());
|
|
2685
2690
|
const config2 = resolveConfig(fileConfig, {
|
|
@@ -2754,7 +2759,7 @@ function registerScanCommand(program2) {
|
|
|
2754
2759
|
|
|
2755
2760
|
// src/cli/init-command.ts
|
|
2756
2761
|
var fs8 = __toESM(require("fs"));
|
|
2757
|
-
var
|
|
2762
|
+
var path9 = __toESM(require("path"));
|
|
2758
2763
|
var readline2 = __toESM(require("readline"));
|
|
2759
2764
|
var import_node_child_process = require("child_process");
|
|
2760
2765
|
var import_picocolors5 = __toESM(require("picocolors"));
|
|
@@ -2767,14 +2772,14 @@ function registerInitCommand(program2) {
|
|
|
2767
2772
|
`));
|
|
2768
2773
|
const options = await promptInitOptions();
|
|
2769
2774
|
const cwd = process.cwd();
|
|
2770
|
-
const hasAppDir = fs8.existsSync(
|
|
2771
|
-
const hasSrcDir = fs8.existsSync(
|
|
2775
|
+
const hasAppDir = fs8.existsSync(path9.join(cwd, "app"));
|
|
2776
|
+
const hasSrcDir = fs8.existsSync(path9.join(cwd, "src"));
|
|
2772
2777
|
const include = [];
|
|
2773
2778
|
if (hasSrcDir) include.push("src/**/*.{tsx,jsx}");
|
|
2774
2779
|
if (hasAppDir) include.push("app/**/*.{tsx,jsx}");
|
|
2775
2780
|
if (include.length === 0) include.push("**/*.{tsx,jsx}");
|
|
2776
2781
|
const configContent = generateConfig(options.provider, include);
|
|
2777
|
-
const configPath =
|
|
2782
|
+
const configPath = path9.join(cwd, "a11y.config.ts");
|
|
2778
2783
|
fs8.writeFileSync(configPath, configContent);
|
|
2779
2784
|
console.log(import_picocolors5.default.green(" Created a11y.config.ts"));
|
|
2780
2785
|
if (options.provider !== "none" && options.installDep) {
|
|
@@ -2799,7 +2804,7 @@ function registerInitCommand(program2) {
|
|
|
2799
2804
|
}
|
|
2800
2805
|
}
|
|
2801
2806
|
if (options.addGitignore) {
|
|
2802
|
-
const gitignorePath =
|
|
2807
|
+
const gitignorePath = path9.join(cwd, ".gitignore");
|
|
2803
2808
|
let content = "";
|
|
2804
2809
|
if (fs8.existsSync(gitignorePath)) {
|
|
2805
2810
|
content = fs8.readFileSync(gitignorePath, "utf-8");
|
|
@@ -2847,7 +2852,7 @@ async function promptInitOptions() {
|
|
|
2847
2852
|
return { provider, installDep, addGitignore };
|
|
2848
2853
|
}
|
|
2849
2854
|
function promptSelect(question, options) {
|
|
2850
|
-
return new Promise((
|
|
2855
|
+
return new Promise((resolve7) => {
|
|
2851
2856
|
const rl = readline2.createInterface({
|
|
2852
2857
|
input: process.stdin,
|
|
2853
2858
|
output: process.stdout
|
|
@@ -2860,15 +2865,15 @@ function promptSelect(question, options) {
|
|
|
2860
2865
|
rl.close();
|
|
2861
2866
|
const idx = parseInt(answer.trim()) - 1;
|
|
2862
2867
|
if (idx >= 0 && idx < options.length) {
|
|
2863
|
-
|
|
2868
|
+
resolve7(options[idx].value);
|
|
2864
2869
|
} else {
|
|
2865
|
-
|
|
2870
|
+
resolve7(options[0].value);
|
|
2866
2871
|
}
|
|
2867
2872
|
});
|
|
2868
2873
|
});
|
|
2869
2874
|
}
|
|
2870
2875
|
function promptYesNo(question) {
|
|
2871
|
-
return new Promise((
|
|
2876
|
+
return new Promise((resolve7) => {
|
|
2872
2877
|
const rl = readline2.createInterface({
|
|
2873
2878
|
input: process.stdin,
|
|
2874
2879
|
output: process.stdout
|
|
@@ -2876,7 +2881,7 @@ function promptYesNo(question) {
|
|
|
2876
2881
|
rl.question(` ${question} ${import_picocolors5.default.dim("[Y/n]")} `, (answer) => {
|
|
2877
2882
|
rl.close();
|
|
2878
2883
|
const normalized = answer.trim().toLowerCase();
|
|
2879
|
-
|
|
2884
|
+
resolve7(normalized !== "n" && normalized !== "no");
|
|
2880
2885
|
});
|
|
2881
2886
|
});
|
|
2882
2887
|
}
|
|
@@ -2954,7 +2959,7 @@ function formatBytes(bytes) {
|
|
|
2954
2959
|
}
|
|
2955
2960
|
|
|
2956
2961
|
// src/cli/index.ts
|
|
2957
|
-
var pkgPath =
|
|
2962
|
+
var pkgPath = path10.resolve(__dirname, "../../package.json");
|
|
2958
2963
|
var pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
|
|
2959
2964
|
(0, import_dotenv2.config)({ path: ".env", override: false, quiet: true });
|
|
2960
2965
|
(0, import_dotenv2.config)({ path: ".env.local", override: true, quiet: true });
|
package/dist/cli/index.mjs
CHANGED
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
|
|
9
9
|
// src/cli/index.ts
|
|
10
10
|
import * as fs9 from "fs";
|
|
11
|
-
import * as
|
|
11
|
+
import * as path10 from "path";
|
|
12
12
|
import { config } from "dotenv";
|
|
13
13
|
import { Command } from "commander";
|
|
14
14
|
|
|
15
15
|
// src/cli/scan-command.ts
|
|
16
16
|
import * as fs7 from "fs";
|
|
17
|
-
import * as
|
|
17
|
+
import * as path8 from "path";
|
|
18
18
|
import { config as dotenvConfig } from "dotenv";
|
|
19
19
|
import pc4 from "picocolors";
|
|
20
20
|
|
|
@@ -87,7 +87,7 @@ function deepMerge(target, source) {
|
|
|
87
87
|
|
|
88
88
|
// src/scan/scan.ts
|
|
89
89
|
import * as fs6 from "fs";
|
|
90
|
-
import * as
|
|
90
|
+
import * as path7 from "path";
|
|
91
91
|
import { Project as Project2 } from "ts-morph";
|
|
92
92
|
|
|
93
93
|
// src/scan/glob.ts
|
|
@@ -99,13 +99,13 @@ async function discoverFiles(basePath, include, exclude) {
|
|
|
99
99
|
if (typeof fs2.glob === "function") {
|
|
100
100
|
for (const pattern of include) {
|
|
101
101
|
try {
|
|
102
|
-
const matches = await new Promise((
|
|
102
|
+
const matches = await new Promise((resolve7, reject) => {
|
|
103
103
|
fs2.glob(
|
|
104
104
|
pattern,
|
|
105
105
|
{ cwd: absBase },
|
|
106
106
|
(err, files) => {
|
|
107
107
|
if (err) reject(err);
|
|
108
|
-
else
|
|
108
|
+
else resolve7(files);
|
|
109
109
|
}
|
|
110
110
|
);
|
|
111
111
|
});
|
|
@@ -1636,6 +1636,8 @@ function removeElement(file, line) {
|
|
|
1636
1636
|
}
|
|
1637
1637
|
|
|
1638
1638
|
// src/ai/create-provider.ts
|
|
1639
|
+
import { createRequire } from "module";
|
|
1640
|
+
import * as path4 from "path";
|
|
1639
1641
|
var PROVIDER_PACKAGES = {
|
|
1640
1642
|
openai: "@ai-sdk/openai",
|
|
1641
1643
|
anthropic: "@ai-sdk/anthropic",
|
|
@@ -1650,9 +1652,12 @@ var PROVIDER_INSTALL = {
|
|
|
1650
1652
|
};
|
|
1651
1653
|
function createProvider(provider, model) {
|
|
1652
1654
|
const pkg2 = PROVIDER_PACKAGES[provider];
|
|
1655
|
+
const projectRequire = createRequire(
|
|
1656
|
+
path4.resolve(process.cwd(), "package.json")
|
|
1657
|
+
);
|
|
1653
1658
|
let mod;
|
|
1654
1659
|
try {
|
|
1655
|
-
mod =
|
|
1660
|
+
mod = projectRequire(pkg2);
|
|
1656
1661
|
} catch {
|
|
1657
1662
|
throw new Error(
|
|
1658
1663
|
`AI provider "${provider}" requires the "${pkg2}" package.
|
|
@@ -1731,12 +1736,12 @@ async function generate(options) {
|
|
|
1731
1736
|
|
|
1732
1737
|
// src/cache/fs-cache.ts
|
|
1733
1738
|
import * as fs4 from "fs";
|
|
1734
|
-
import * as
|
|
1739
|
+
import * as path5 from "path";
|
|
1735
1740
|
import * as crypto from "crypto";
|
|
1736
1741
|
var FsCache = class {
|
|
1737
1742
|
constructor(cacheDir) {
|
|
1738
1743
|
this.cacheDir = cacheDir;
|
|
1739
|
-
this.cachePath =
|
|
1744
|
+
this.cachePath = path5.join(cacheDir, "cache.json");
|
|
1740
1745
|
this.data = this.load();
|
|
1741
1746
|
}
|
|
1742
1747
|
load() {
|
|
@@ -1878,7 +1883,7 @@ function buildImgAltPrompt(context) {
|
|
|
1878
1883
|
|
|
1879
1884
|
// src/rules/img-alt/img-alt.resolve.ts
|
|
1880
1885
|
import * as fs5 from "fs";
|
|
1881
|
-
import * as
|
|
1886
|
+
import * as path6 from "path";
|
|
1882
1887
|
import * as https from "https";
|
|
1883
1888
|
import * as http from "http";
|
|
1884
1889
|
var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg", ".avif"];
|
|
@@ -1886,7 +1891,7 @@ function isImagePath(p) {
|
|
|
1886
1891
|
return IMAGE_EXTENSIONS.some((ext) => p.endsWith(ext));
|
|
1887
1892
|
}
|
|
1888
1893
|
async function resolveImageSource(src, file, projectRoot) {
|
|
1889
|
-
if (
|
|
1894
|
+
if (path6.isAbsolute(src) && isImagePath(src)) {
|
|
1890
1895
|
try {
|
|
1891
1896
|
const buffer = fs5.readFileSync(src);
|
|
1892
1897
|
return { type: "file", buffer, path: src };
|
|
@@ -1894,7 +1899,7 @@ async function resolveImageSource(src, file, projectRoot) {
|
|
|
1894
1899
|
}
|
|
1895
1900
|
}
|
|
1896
1901
|
if (src.startsWith("/")) {
|
|
1897
|
-
const publicPath =
|
|
1902
|
+
const publicPath = path6.join(projectRoot, "public", src);
|
|
1898
1903
|
try {
|
|
1899
1904
|
const buffer = fs5.readFileSync(publicPath);
|
|
1900
1905
|
return { type: "file", buffer, path: publicPath };
|
|
@@ -1904,7 +1909,7 @@ async function resolveImageSource(src, file, projectRoot) {
|
|
|
1904
1909
|
}
|
|
1905
1910
|
if (src.startsWith(".")) {
|
|
1906
1911
|
const filePath = file.getFilePath();
|
|
1907
|
-
const resolved =
|
|
1912
|
+
const resolved = path6.resolve(path6.dirname(filePath), src);
|
|
1908
1913
|
try {
|
|
1909
1914
|
const buffer = fs5.readFileSync(resolved);
|
|
1910
1915
|
return { type: "file", buffer, path: resolved };
|
|
@@ -1968,7 +1973,7 @@ function resolveModuleToImage(moduleSpecifier, fromFile, projectRoot, namedExpor
|
|
|
1968
1973
|
function resolveModulePath(moduleSpecifier, fromFile, projectRoot, project) {
|
|
1969
1974
|
let resolved;
|
|
1970
1975
|
if (moduleSpecifier.startsWith(".")) {
|
|
1971
|
-
resolved =
|
|
1976
|
+
resolved = path6.resolve(path6.dirname(fromFile), moduleSpecifier);
|
|
1972
1977
|
} else {
|
|
1973
1978
|
const aliasResolved = resolvePathAlias(moduleSpecifier, projectRoot, project);
|
|
1974
1979
|
if (aliasResolved) {
|
|
@@ -1987,7 +1992,7 @@ function resolveModulePath(moduleSpecifier, fromFile, projectRoot, project) {
|
|
|
1987
1992
|
}
|
|
1988
1993
|
const indexFiles = ["index.ts", "index.tsx", "index.js", "index.jsx"];
|
|
1989
1994
|
for (const idx of indexFiles) {
|
|
1990
|
-
const indexPath =
|
|
1995
|
+
const indexPath = path6.join(resolved, idx);
|
|
1991
1996
|
if (fs5.existsSync(indexPath)) return indexPath;
|
|
1992
1997
|
}
|
|
1993
1998
|
return void 0;
|
|
@@ -2002,7 +2007,7 @@ function followReExport(barrelPath, exportName) {
|
|
|
2002
2007
|
if (match) {
|
|
2003
2008
|
const reExportPath = match[1];
|
|
2004
2009
|
if (isImagePath(reExportPath)) {
|
|
2005
|
-
return
|
|
2010
|
+
return path6.resolve(path6.dirname(barrelPath), reExportPath);
|
|
2006
2011
|
}
|
|
2007
2012
|
}
|
|
2008
2013
|
} catch {
|
|
@@ -2022,13 +2027,13 @@ function resolvePathAlias(moduleSpecifier, projectRoot, project) {
|
|
|
2022
2027
|
const rest = moduleSpecifier.slice(prefix.length);
|
|
2023
2028
|
for (const mapping of mappings) {
|
|
2024
2029
|
const mappingBase = mapping.endsWith("/*") ? mapping.slice(0, -1) : mapping;
|
|
2025
|
-
const resolved =
|
|
2030
|
+
const resolved = path6.resolve(baseDir, mappingBase + rest);
|
|
2026
2031
|
return resolved;
|
|
2027
2032
|
}
|
|
2028
2033
|
}
|
|
2029
2034
|
} else if (pattern === moduleSpecifier) {
|
|
2030
2035
|
if (mappings.length > 0) {
|
|
2031
|
-
return
|
|
2036
|
+
return path6.resolve(baseDir, mappings[0]);
|
|
2032
2037
|
}
|
|
2033
2038
|
}
|
|
2034
2039
|
}
|
|
@@ -2038,22 +2043,22 @@ function escapeRegex(str) {
|
|
|
2038
2043
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2039
2044
|
}
|
|
2040
2045
|
function findProjectRootFromFile(filePath) {
|
|
2041
|
-
let dir =
|
|
2042
|
-
while (dir !==
|
|
2043
|
-
if (fs5.existsSync(
|
|
2044
|
-
if (fs5.existsSync(
|
|
2045
|
-
if (fs5.existsSync(
|
|
2046
|
-
if (fs5.existsSync(
|
|
2047
|
-
dir =
|
|
2046
|
+
let dir = path6.dirname(filePath);
|
|
2047
|
+
while (dir !== path6.dirname(dir)) {
|
|
2048
|
+
if (fs5.existsSync(path6.join(dir, "package.json"))) return dir;
|
|
2049
|
+
if (fs5.existsSync(path6.join(dir, "next.config.js"))) return dir;
|
|
2050
|
+
if (fs5.existsSync(path6.join(dir, "next.config.mjs"))) return dir;
|
|
2051
|
+
if (fs5.existsSync(path6.join(dir, "next.config.ts"))) return dir;
|
|
2052
|
+
dir = path6.dirname(dir);
|
|
2048
2053
|
}
|
|
2049
|
-
return
|
|
2054
|
+
return path6.dirname(filePath);
|
|
2050
2055
|
}
|
|
2051
2056
|
function fetchImage(url) {
|
|
2052
|
-
return new Promise((
|
|
2057
|
+
return new Promise((resolve7, reject) => {
|
|
2053
2058
|
const client = url.startsWith("https") ? https : http;
|
|
2054
2059
|
const req = client.get(url, { timeout: 1e4 }, (res) => {
|
|
2055
2060
|
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
2056
|
-
fetchImage(res.headers.location).then(
|
|
2061
|
+
fetchImage(res.headers.location).then(resolve7).catch(reject);
|
|
2057
2062
|
return;
|
|
2058
2063
|
}
|
|
2059
2064
|
const chunks = [];
|
|
@@ -2068,7 +2073,7 @@ function fetchImage(url) {
|
|
|
2068
2073
|
}
|
|
2069
2074
|
chunks.push(chunk);
|
|
2070
2075
|
});
|
|
2071
|
-
res.on("end", () =>
|
|
2076
|
+
res.on("end", () => resolve7(Buffer.concat(chunks)));
|
|
2072
2077
|
res.on("error", reject);
|
|
2073
2078
|
});
|
|
2074
2079
|
req.on("error", reject);
|
|
@@ -2244,28 +2249,28 @@ function findElement(file, line) {
|
|
|
2244
2249
|
return elements.find((el) => el.getStartLineNumber() === line);
|
|
2245
2250
|
}
|
|
2246
2251
|
function findProjectRoot(filePath) {
|
|
2247
|
-
const
|
|
2252
|
+
const path11 = __require("path");
|
|
2248
2253
|
const fs10 = __require("fs");
|
|
2249
|
-
let dir =
|
|
2250
|
-
while (dir !==
|
|
2251
|
-
if (fs10.existsSync(
|
|
2252
|
-
if (fs10.existsSync(
|
|
2253
|
-
if (fs10.existsSync(
|
|
2254
|
-
if (fs10.existsSync(
|
|
2255
|
-
dir =
|
|
2254
|
+
let dir = path11.dirname(filePath);
|
|
2255
|
+
while (dir !== path11.dirname(dir)) {
|
|
2256
|
+
if (fs10.existsSync(path11.join(dir, "package.json"))) return dir;
|
|
2257
|
+
if (fs10.existsSync(path11.join(dir, "next.config.js"))) return dir;
|
|
2258
|
+
if (fs10.existsSync(path11.join(dir, "next.config.mjs"))) return dir;
|
|
2259
|
+
if (fs10.existsSync(path11.join(dir, "next.config.ts"))) return dir;
|
|
2260
|
+
dir = path11.dirname(dir);
|
|
2256
2261
|
}
|
|
2257
|
-
return
|
|
2262
|
+
return path11.dirname(filePath);
|
|
2258
2263
|
}
|
|
2259
2264
|
|
|
2260
2265
|
// src/scan/scan.ts
|
|
2261
2266
|
function resolveTargetPath(targetPath) {
|
|
2262
|
-
const absPath =
|
|
2267
|
+
const absPath = path7.resolve(targetPath);
|
|
2263
2268
|
if (!fs6.existsSync(absPath)) {
|
|
2264
2269
|
throw new Error(`Path does not exist: ${absPath}`);
|
|
2265
2270
|
}
|
|
2266
2271
|
const stat = fs6.statSync(absPath);
|
|
2267
2272
|
if (stat.isFile()) {
|
|
2268
|
-
return
|
|
2273
|
+
return path7.dirname(absPath);
|
|
2269
2274
|
}
|
|
2270
2275
|
return absPath;
|
|
2271
2276
|
}
|
|
@@ -2276,7 +2281,7 @@ async function detect(targetPath, config2) {
|
|
|
2276
2281
|
config2.scanner.include,
|
|
2277
2282
|
config2.scanner.exclude
|
|
2278
2283
|
);
|
|
2279
|
-
const tsconfigPath =
|
|
2284
|
+
const tsconfigPath = path7.join(absPath, "tsconfig.json");
|
|
2280
2285
|
const project = new Project2({
|
|
2281
2286
|
tsConfigFilePath: fs6.existsSync(tsconfigPath) ? tsconfigPath : void 0,
|
|
2282
2287
|
skipAddingFilesFromTsConfig: true,
|
|
@@ -2584,7 +2589,7 @@ async function interactiveReview(violations, onAccept) {
|
|
|
2584
2589
|
return { applied, skipped };
|
|
2585
2590
|
}
|
|
2586
2591
|
function promptAction() {
|
|
2587
|
-
return new Promise((
|
|
2592
|
+
return new Promise((resolve7) => {
|
|
2588
2593
|
const rl = readline.createInterface({
|
|
2589
2594
|
input: process.stdin,
|
|
2590
2595
|
output: process.stdout
|
|
@@ -2595,10 +2600,10 @@ function promptAction() {
|
|
|
2595
2600
|
(answer) => {
|
|
2596
2601
|
rl.close();
|
|
2597
2602
|
const normalized = answer.trim().toLowerCase();
|
|
2598
|
-
if (normalized === "n" || normalized === "no")
|
|
2599
|
-
else if (normalized === "s" || normalized === "skip")
|
|
2600
|
-
else if (normalized === "q" || normalized === "quit")
|
|
2601
|
-
else
|
|
2603
|
+
if (normalized === "n" || normalized === "no") resolve7("no");
|
|
2604
|
+
else if (normalized === "s" || normalized === "skip") resolve7("skip");
|
|
2605
|
+
else if (normalized === "q" || normalized === "quit") resolve7("quit");
|
|
2606
|
+
else resolve7("yes");
|
|
2602
2607
|
}
|
|
2603
2608
|
);
|
|
2604
2609
|
});
|
|
@@ -2608,20 +2613,20 @@ function promptAction() {
|
|
|
2608
2613
|
function registerScanCommand(program2) {
|
|
2609
2614
|
const version = program2.version();
|
|
2610
2615
|
program2.command("scan").description("Scan files for accessibility issues").argument("<path>", "Path to scan").option("--fix", "Auto-fix issues").option("-i, --interactive", "Review each fix interactively").option("--no-ai", "Skip AI-powered fixes").option("--provider <provider>", "Override AI provider").option("--model <model>", "Override AI model").option("--min-score <score>", "Minimum score threshold (exit code 1 if below)", parseInt).action(async (targetPath, options) => {
|
|
2611
|
-
let envDir =
|
|
2616
|
+
let envDir = path8.resolve(targetPath);
|
|
2612
2617
|
if (fs7.existsSync(envDir) && fs7.statSync(envDir).isFile()) {
|
|
2613
|
-
envDir =
|
|
2618
|
+
envDir = path8.dirname(envDir);
|
|
2614
2619
|
}
|
|
2615
2620
|
let searchDir = envDir;
|
|
2616
|
-
while (searchDir !==
|
|
2621
|
+
while (searchDir !== path8.dirname(searchDir)) {
|
|
2617
2622
|
for (const envFile of [".env", ".env.local"]) {
|
|
2618
|
-
const envPath =
|
|
2623
|
+
const envPath = path8.join(searchDir, envFile);
|
|
2619
2624
|
if (fs7.existsSync(envPath)) {
|
|
2620
2625
|
dotenvConfig({ path: envPath, override: false, quiet: true });
|
|
2621
2626
|
}
|
|
2622
2627
|
}
|
|
2623
|
-
if (fs7.existsSync(
|
|
2624
|
-
searchDir =
|
|
2628
|
+
if (fs7.existsSync(path8.join(searchDir, "package.json"))) break;
|
|
2629
|
+
searchDir = path8.dirname(searchDir);
|
|
2625
2630
|
}
|
|
2626
2631
|
const fileConfig = await loadConfigFile(process.cwd());
|
|
2627
2632
|
const config2 = resolveConfig(fileConfig, {
|
|
@@ -2696,7 +2701,7 @@ function registerScanCommand(program2) {
|
|
|
2696
2701
|
|
|
2697
2702
|
// src/cli/init-command.ts
|
|
2698
2703
|
import * as fs8 from "fs";
|
|
2699
|
-
import * as
|
|
2704
|
+
import * as path9 from "path";
|
|
2700
2705
|
import * as readline2 from "readline";
|
|
2701
2706
|
import { execSync } from "child_process";
|
|
2702
2707
|
import pc5 from "picocolors";
|
|
@@ -2709,14 +2714,14 @@ function registerInitCommand(program2) {
|
|
|
2709
2714
|
`));
|
|
2710
2715
|
const options = await promptInitOptions();
|
|
2711
2716
|
const cwd = process.cwd();
|
|
2712
|
-
const hasAppDir = fs8.existsSync(
|
|
2713
|
-
const hasSrcDir = fs8.existsSync(
|
|
2717
|
+
const hasAppDir = fs8.existsSync(path9.join(cwd, "app"));
|
|
2718
|
+
const hasSrcDir = fs8.existsSync(path9.join(cwd, "src"));
|
|
2714
2719
|
const include = [];
|
|
2715
2720
|
if (hasSrcDir) include.push("src/**/*.{tsx,jsx}");
|
|
2716
2721
|
if (hasAppDir) include.push("app/**/*.{tsx,jsx}");
|
|
2717
2722
|
if (include.length === 0) include.push("**/*.{tsx,jsx}");
|
|
2718
2723
|
const configContent = generateConfig(options.provider, include);
|
|
2719
|
-
const configPath =
|
|
2724
|
+
const configPath = path9.join(cwd, "a11y.config.ts");
|
|
2720
2725
|
fs8.writeFileSync(configPath, configContent);
|
|
2721
2726
|
console.log(pc5.green(" Created a11y.config.ts"));
|
|
2722
2727
|
if (options.provider !== "none" && options.installDep) {
|
|
@@ -2741,7 +2746,7 @@ function registerInitCommand(program2) {
|
|
|
2741
2746
|
}
|
|
2742
2747
|
}
|
|
2743
2748
|
if (options.addGitignore) {
|
|
2744
|
-
const gitignorePath =
|
|
2749
|
+
const gitignorePath = path9.join(cwd, ".gitignore");
|
|
2745
2750
|
let content = "";
|
|
2746
2751
|
if (fs8.existsSync(gitignorePath)) {
|
|
2747
2752
|
content = fs8.readFileSync(gitignorePath, "utf-8");
|
|
@@ -2789,7 +2794,7 @@ async function promptInitOptions() {
|
|
|
2789
2794
|
return { provider, installDep, addGitignore };
|
|
2790
2795
|
}
|
|
2791
2796
|
function promptSelect(question, options) {
|
|
2792
|
-
return new Promise((
|
|
2797
|
+
return new Promise((resolve7) => {
|
|
2793
2798
|
const rl = readline2.createInterface({
|
|
2794
2799
|
input: process.stdin,
|
|
2795
2800
|
output: process.stdout
|
|
@@ -2802,15 +2807,15 @@ function promptSelect(question, options) {
|
|
|
2802
2807
|
rl.close();
|
|
2803
2808
|
const idx = parseInt(answer.trim()) - 1;
|
|
2804
2809
|
if (idx >= 0 && idx < options.length) {
|
|
2805
|
-
|
|
2810
|
+
resolve7(options[idx].value);
|
|
2806
2811
|
} else {
|
|
2807
|
-
|
|
2812
|
+
resolve7(options[0].value);
|
|
2808
2813
|
}
|
|
2809
2814
|
});
|
|
2810
2815
|
});
|
|
2811
2816
|
}
|
|
2812
2817
|
function promptYesNo(question) {
|
|
2813
|
-
return new Promise((
|
|
2818
|
+
return new Promise((resolve7) => {
|
|
2814
2819
|
const rl = readline2.createInterface({
|
|
2815
2820
|
input: process.stdin,
|
|
2816
2821
|
output: process.stdout
|
|
@@ -2818,7 +2823,7 @@ function promptYesNo(question) {
|
|
|
2818
2823
|
rl.question(` ${question} ${pc5.dim("[Y/n]")} `, (answer) => {
|
|
2819
2824
|
rl.close();
|
|
2820
2825
|
const normalized = answer.trim().toLowerCase();
|
|
2821
|
-
|
|
2826
|
+
resolve7(normalized !== "n" && normalized !== "no");
|
|
2822
2827
|
});
|
|
2823
2828
|
});
|
|
2824
2829
|
}
|
|
@@ -2896,7 +2901,7 @@ function formatBytes(bytes) {
|
|
|
2896
2901
|
}
|
|
2897
2902
|
|
|
2898
2903
|
// src/cli/index.ts
|
|
2899
|
-
var pkgPath =
|
|
2904
|
+
var pkgPath = path10.resolve(__dirname, "../../package.json");
|
|
2900
2905
|
var pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
|
|
2901
2906
|
config({ path: ".env", override: false, quiet: true });
|
|
2902
2907
|
config({ path: ".env.local", override: true, quiet: true });
|