wcag-scanner 1.2.65 → 1.2.67

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.
@@ -21,8 +21,6 @@ exports.default = {
21
21
  checkImageElements(document, results);
22
22
  // Check <svg> elements
23
23
  checkSvgElements(document, results);
24
- // Check background images
25
- checkBackgroundImages(document, window, results);
26
24
  // Check image maps
27
25
  checkImageMaps(document, results);
28
26
  return results;
@@ -187,54 +185,6 @@ function checkSvgElements(document, results) {
187
185
  }
188
186
  });
189
187
  }
190
- /**
191
- * Check background images for accessibility issues
192
- * @param document DOM document
193
- * @param window Window object
194
- * @param results Scan results
195
- */
196
- function checkBackgroundImages(document, window, results) {
197
- // Find elements with background image
198
- const allElements = document.querySelectorAll('*');
199
- allElements.forEach(element => {
200
- var _a, _b, _c;
201
- const style = window.getComputedStyle(element);
202
- const backgroundImage = style.backgroundImage;
203
- // Skip if no background image or if it's "none"
204
- if (!backgroundImage || backgroundImage === 'none') {
205
- return;
206
- }
207
- // Skip if the element is hidden/decorative
208
- if (isElementHidden(element) || element.getAttribute('aria-hidden') === 'true') {
209
- return;
210
- }
211
- const info = {
212
- tagName: element.tagName.toLowerCase(),
213
- id: element.id || null,
214
- className: ((_a = element.className) === null || _a === void 0 ? void 0 : _a.toString()) || null,
215
- textContent: ((_b = element.textContent) === null || _b === void 0 ? void 0 : _b.substring(0, 50)) || null
216
- };
217
- // Check if meaningful background image has text alternative
218
- const hasTextContent = ((_c = element.textContent) === null || _c === void 0 ? void 0 : _c.trim()) !== '';
219
- const hasAriaLabel = element.hasAttribute('aria-label');
220
- const hasAriaLabelledby = element.hasAttribute('aria-labelledby');
221
- const hasTitle = element.hasAttribute('title');
222
- if (!hasTextContent && !hasAriaLabel && !hasAriaLabelledby && !hasTitle) {
223
- // Only warn if the background image looks like content (not decoration)
224
- if (backgroundImage.includes('url(') && !isBackgroundLikelyDecorative(element)) {
225
- results.warnings.push({
226
- rule: 'background-image',
227
- element: info,
228
- impact: 'moderate',
229
- description: 'Element with background image may need text alternative',
230
- snippet: element.outerHTML.slice(0, 150) + (element.outerHTML.length > 150 ? '...' : ''),
231
- wcag: ['1.1.1'],
232
- help: 'If the background image conveys meaning, add text alternative via aria-label or text content'
233
- });
234
- }
235
- }
236
- });
237
- }
238
188
  /**
239
189
  * Check image maps for accessibility
240
190
  * @param document DOM document
@@ -293,47 +243,6 @@ function checkImageMaps(document, results) {
293
243
  });
294
244
  });
295
245
  }
296
- /**
297
- * Check if an element is hidden
298
- * @param element Element to check
299
- */
300
- function isElementHidden(element) {
301
- // This is a simplified check - a real implementation would be more comprehensive
302
- if (element.hasAttribute('hidden') || element.getAttribute('aria-hidden') === 'true') {
303
- return true;
304
- }
305
- // Check computed style if available
306
- try {
307
- const style = getComputedStyle(element);
308
- return style.display === 'none' || style.visibility === 'hidden';
309
- }
310
- catch (e) {
311
- return false;
312
- }
313
- }
314
- /**
315
- * Check if a background image is likely decorative
316
- * @param element Element to check
317
- */
318
- function isBackgroundLikelyDecorative(element) {
319
- var _a, _b;
320
- // Common decorative pattern elements
321
- const decorativeElements = ['header', 'footer', 'section', 'article', 'div'];
322
- const tagName = ((_a = element.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
323
- if (decorativeElements.includes(tagName)) {
324
- // Check for certain classes that might indicate decorative backgrounds
325
- const className = ((_b = element.className) === null || _b === void 0 ? void 0 : _b.toString()) || '';
326
- if (className.includes('background') ||
327
- className.includes('banner') ||
328
- className.includes('hero') ||
329
- className.includes('container') ||
330
- className.includes('wrapper') ||
331
- className.includes('section')) {
332
- return true;
333
- }
334
- }
335
- return false;
336
- }
337
246
  /**
338
247
  * Determine if an image is likely decorative
339
248
  * @param img Image to check
@@ -0,0 +1,8 @@
1
+ import { ScannerOptions } from '../types';
2
+ export declare const FAST_RULES: readonly ["images", "contrast", "forms", "aria", "structure", "keyboard"];
3
+ export declare const FULL_RULES: readonly ["images", "contrast", "forms", "aria", "structure", "keyboard", "backgroundImages"];
4
+ export declare const RULE_PRESETS: {
5
+ readonly fast: readonly ["images", "contrast", "forms", "aria", "structure", "keyboard"];
6
+ readonly full: readonly ["images", "contrast", "forms", "aria", "structure", "keyboard", "backgroundImages"];
7
+ };
8
+ export declare function resolveRuleNames(options: ScannerOptions, fallback?: readonly string[]): string[];
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RULE_PRESETS = exports.FULL_RULES = exports.FAST_RULES = void 0;
4
+ exports.resolveRuleNames = resolveRuleNames;
5
+ exports.FAST_RULES = ['images', 'contrast', 'forms', 'aria', 'structure', 'keyboard'];
6
+ exports.FULL_RULES = [...exports.FAST_RULES, 'backgroundImages'];
7
+ exports.RULE_PRESETS = {
8
+ fast: [...exports.FAST_RULES],
9
+ full: [...exports.FULL_RULES],
10
+ };
11
+ function resolveRuleNames(options, fallback = exports.FAST_RULES) {
12
+ if (options.rules && options.rules.length > 0) {
13
+ return options.rules;
14
+ }
15
+ if (options.preset === 'full') {
16
+ return [...exports.FULL_RULES];
17
+ }
18
+ return [...fallback];
19
+ }
package/dist/scanner.js CHANGED
@@ -7,6 +7,7 @@ exports.WCAGScanner = void 0;
7
7
  const jsdom_1 = require("jsdom");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
+ const presets_1 = require("./rules/presets");
10
11
  /**
11
12
  * Main WCAG Scanner class
12
13
  */
@@ -18,7 +19,7 @@ class WCAGScanner {
18
19
  constructor(options = {}) {
19
20
  this.rules = new Map();
20
21
  this.options = {
21
- rules: ['images', 'headings', 'contrast', 'forms', 'aria'],
22
+ preset: 'fast',
22
23
  level: 'AA',
23
24
  ai: true,
24
25
  ...options
@@ -36,18 +37,15 @@ class WCAGScanner {
36
37
  * @returns Promise<boolean> True if loaded successfully
37
38
  */
38
39
  async loadHTML(html, baseUrl = 'https://example.org') {
40
+ var _a;
39
41
  try {
42
+ (_a = this.dom) === null || _a === void 0 ? void 0 : _a.window.close();
40
43
  // Create virtual DOM with robust error handling
41
44
  this.dom = new jsdom_1.JSDOM(html, {
42
45
  url: baseUrl,
43
- resources: 'usable',
44
- runScripts: 'dangerously',
46
+ runScripts: 'outside-only',
47
+ pretendToBeVisual: true,
45
48
  beforeParse(window) {
46
- // Silence script errors
47
- window.addEventListener('error', (event) => {
48
- console.log(`Ignored script error: ${event.message}`);
49
- event.preventDefault();
50
- });
51
49
  // Mock modern browser APIs that may be missing in JSDOM
52
50
  if (!window.ReadableStream) {
53
51
  window.ReadableStream = class MockReadableStream {
@@ -67,8 +65,6 @@ class WCAGScanner {
67
65
  });
68
66
  this.document = this.dom.window.document;
69
67
  this.window = this.dom.window;
70
- // Wait for resources to load
71
- await new Promise(resolve => setTimeout(resolve, 100));
72
68
  return true;
73
69
  }
74
70
  catch (error) {
@@ -103,6 +99,8 @@ class WCAGScanner {
103
99
  .filter(file => {
104
100
  if (file.endsWith('.d.ts') || file.endsWith('.d.js'))
105
101
  return false;
102
+ if (path_1.default.basename(file, path_1.default.extname(file)) === 'presets')
103
+ return false;
106
104
  return file.endsWith('.js') || file.endsWith('.ts');
107
105
  });
108
106
  for (const file of ruleFiles) {
@@ -147,7 +145,7 @@ class WCAGScanner {
147
145
  await this.loadRules();
148
146
  }
149
147
  // Run each enabled rule
150
- const enabledRules = this.options.rules || [];
148
+ const enabledRules = (0, presets_1.resolveRuleNames)(this.options, presets_1.FAST_RULES);
151
149
  for (const ruleName of enabledRules) {
152
150
  const rule = this.rules.get(ruleName);
153
151
  if (rule) {
@@ -170,7 +168,11 @@ class WCAGScanner {
170
168
  * @returns ScanResults Current scan results
171
169
  */
172
170
  getResults() {
173
- return this.results;
171
+ return {
172
+ passes: [...this.results.passes],
173
+ violations: [...this.results.violations],
174
+ warnings: [...this.results.warnings]
175
+ };
174
176
  }
175
177
  /**
176
178
  * Update scanner options
@@ -1,9 +1,12 @@
1
+ export type RulePreset = 'fast' | 'full';
1
2
  /**
2
3
  * Scanner configuration options
3
4
  */
4
5
  export interface ScannerOptions {
5
6
  /** WCAG level to check against (A, AA or AAA) */
6
7
  level?: 'A' | 'AA' | 'AAA';
8
+ /** Built-in rule preset */
9
+ preset?: RulePreset;
7
10
  /** Specific rules to check */
8
11
  rules?: string[];
9
12
  /** Enable AI-powered suggestions */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wcag-scanner",
3
- "version": "1.2.65",
3
+ "version": "1.2.67",
4
4
  "description": "Scan HTML for WCAG accessibility violations with AI-powered fix suggestions",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,24 +10,22 @@
10
10
  },
11
11
  "files": [
12
12
  "dist",
13
- "scrapper/pkg",
14
13
  "README.md",
15
14
  "LICENSE"
16
15
  ],
17
16
  "engines": {
18
17
  "node": ">=16.0.0"
19
18
  },
20
- "bin": {
21
- "wcag-scanner": "dist/cli/index.js"
22
- },
23
19
  "scripts": {
24
20
  "test": "jest",
25
21
  "test:coverage": "jest --coverage",
26
- "build:wasm": "wasm-pack build scrapper --target nodejs",
27
- "build": "npm run build:wasm && rimraf dist && tsc",
22
+ "build": "rimraf dist && tsc",
23
+ "profile:aria": "npm run build && node scripts/profile-aria.js",
24
+ "profile:contrast": "npm run build && node scripts/profile-contrast.js",
25
+ "profile:forms": "npm run build && node scripts/profile-forms.js",
26
+ "profile:images": "npm run build && node scripts/profile-images.js",
28
27
  "prepublishOnly": "npm run build",
29
- "lint": "eslint src/**/*.ts",
30
- "codecov": "codecov"
28
+ "lint": "eslint src/**/*.ts"
31
29
  },
32
30
  "repository": {
33
31
  "type": "git",
@@ -51,10 +49,15 @@
51
49
  "react-dom": ">=17.0.0"
52
50
  },
53
51
  "peerDependenciesMeta": {
54
- "react": { "optional": true },
55
- "react-dom": { "optional": true }
52
+ "react": {
53
+ "optional": true
54
+ },
55
+ "react-dom": {
56
+ "optional": true
57
+ }
56
58
  },
57
59
  "devDependencies": {
60
+ "@testing-library/react": "^16.3.2",
58
61
  "@types/express": "^5.0.0",
59
62
  "@types/jest": "^29.5.14",
60
63
  "@types/jsdom": "^21.1.7",
@@ -63,19 +66,17 @@
63
66
  "@types/react-dom": "^18.3.7",
64
67
  "@typescript-eslint/eslint-plugin": "^8.24.0",
65
68
  "@typescript-eslint/parser": "^8.24.0",
66
- "codecov": "^3.6.2",
67
69
  "eslint": "^9.21.0",
68
70
  "jest": "^29.7.0",
71
+ "react": "^19.2.4",
72
+ "react-dom": "^19.2.4",
69
73
  "rimraf": "^6.0.1",
70
74
  "ts-jest": "^29.2.6",
71
75
  "typescript": "^5.7.2"
72
76
  },
73
77
  "dependencies": {
74
- "@google/generative-ai": "^0.23.0",
75
78
  "color-diff": "^1.4.0",
76
- "commander": "^13.1.0",
77
79
  "crypto": "^1.0.1",
78
- "dotenv": "^16.4.7",
79
80
  "express": "^4.21.2",
80
81
  "jsdom": "^26.0.0"
81
82
  }
@@ -1,11 +0,0 @@
1
- import { Violation, FixSuggestion } from "../types";
2
- /**
3
- * Generate fix suggestions for accessibility violations
4
- * @param violation WCAG violation to fix
5
- * @returns Promise<FixSuggestion> Suggested fix
6
- */
7
- export declare function generateFixSuggestion(violation: Violation): Promise<FixSuggestion>;
8
- declare const _default: {
9
- generateFixSuggestion: typeof generateFixSuggestion;
10
- };
11
- export default _default;
@@ -1,103 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateFixSuggestion = generateFixSuggestion;
7
- const generative_ai_1 = require("@google/generative-ai");
8
- const dotenv_1 = __importDefault(require("dotenv"));
9
- /**
10
- * @TODO working on AI-powered suggestions, it's still working in progress.
11
- */
12
- // Load environment variables from .env file
13
- dotenv_1.default.config();
14
- // Get API key from environment
15
- const apiKey = process.env.GEMINI_API_KEY;
16
- // Initialize Gemini if API key is available
17
- let genAI = null;
18
- let model = null;
19
- if (apiKey) {
20
- try {
21
- genAI = new generative_ai_1.GoogleGenerativeAI(apiKey);
22
- model = genAI.getGenerativeModel({ model: 'gemini-1.0-pro' });
23
- console.log('Gemini AI initialized');
24
- }
25
- catch (error) {
26
- console.error('Error initializing Gemini AI:', error);
27
- }
28
- }
29
- /**
30
- * Generate fix suggestions for accessibility violations
31
- * @param violation WCAG violation to fix
32
- * @returns Promise<FixSuggestion> Suggested fix
33
- */
34
- async function generateFixSuggestion(violation) {
35
- // Ig Gemini is not available, use rule-based suggestion
36
- if (!model) {
37
- console.log('Gemini AI not available, using rule-based suggestion');
38
- return generateRuleBasedSuggestion(violation);
39
- }
40
- try {
41
- // Create prompt for Gemini
42
- const prompt = `
43
- As a web accessibility expert, I need a fix for this WCAG issue:
44
- Rule: ${violation.rule || ''}
45
- Description: ${violation.description || ''}
46
-
47
- HTML code with issue:
48
- ${violation.snippet || ''}
49
-
50
- Please provide a corrected version of the code and a brief explanation.
51
- `;
52
- // Generate content with Gemini
53
- const result = await model.generateContent(prompt);
54
- const response = result.response.text();
55
- // Extract code and explanation from response
56
- const codeMatch = response.match(/```(?:html)?\s*([\s\S]*?)\s*```/);
57
- const code = codeMatch ? codeMatch[1].trim() : '';
58
- // Remove code block for clean explanation
59
- const explanation = response
60
- .replace(/```(?:html)?\s*[\s\S]*?\s*```/g, '')
61
- .trim();
62
- return {
63
- code: code || 'Unable to generate specific code fix',
64
- description: 'AI-suggested fix',
65
- explanation: explanation || 'Fix the accessibility issue as suggested by the AI'
66
- };
67
- }
68
- catch (error) {
69
- console.error('Error generating fix suggestion with Gemini AI:', error);
70
- return generateRuleBasedSuggestion(violation);
71
- }
72
- }
73
- /**
74
- * Generate basic rule-based suggestion as fallback
75
- * @param violation WCAG violation
76
- * @returns FixSuggestion
77
- */
78
- function generateRuleBasedSuggestion(violation) {
79
- var _a;
80
- const rule = violation.rule || '';
81
- if (rule.includes('img-alt')) {
82
- return {
83
- code: ((_a = violation.snippet) === null || _a === void 0 ? void 0 : _a.replace(/<img/i, '<img alt="Descriptive text"')) || '',
84
- description: 'Add alt text to image',
85
- explanation: 'Images need alternative text for screen readers'
86
- };
87
- }
88
- if (rule.includes('contrast')) {
89
- return {
90
- code: '/* Increase color contrast to at least 4.5:1 ratio */',
91
- description: 'Increase color contrast',
92
- explanation: 'Text needs sufficient contrast with its background'
93
- };
94
- }
95
- return {
96
- code: '',
97
- description: 'Fix needed',
98
- explanation: violation.help || 'Fix this issue to improve accessibility'
99
- };
100
- }
101
- exports.default = {
102
- generateFixSuggestion
103
- };
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/cli/index.js DELETED
@@ -1,160 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const commander_1 = require("commander");
8
- const __1 = require("..");
9
- const fs_1 = __importDefault(require("fs"));
10
- const path_1 = __importDefault(require("path"));
11
- const __2 = require("..");
12
- // Try to load package.json for version information
13
- let version = '0.1.0';
14
- try {
15
- const packagePath = path_1.default.join(__dirname, '../../package.json');
16
- const packageJson = JSON.parse(fs_1.default.readFileSync(packagePath, 'utf8'));
17
- version = packageJson.version;
18
- }
19
- catch (e) {
20
- // Ignore package.json load error
21
- }
22
- commander_1.program
23
- .name('wcag-scanner')
24
- .description('Scan HTML files and websites for WCAG accessibility violations')
25
- .version(version);
26
- // Command to scan HTML file
27
- commander_1.program
28
- .command('scan <filePath>')
29
- .description('Scan a local HTML file for accessibility violations')
30
- .option('-l, --level <level>', 'WCAG level (A, AA, AAA)', 'AA')
31
- .option('-f, --format <format>', 'Output format (json, console, html)', 'console')
32
- .option('-o, --output <file>', 'Save results to file')
33
- .option('-v, --verbose', 'Show verbose output')
34
- .option('-r, --rules <rules>', 'Comma-separated list of rules to check')
35
- .action(async (filePath, options) => {
36
- try {
37
- console.log(`Scanning file: ${filePath}`);
38
- const scannerOptions = {
39
- level: options.level,
40
- verbose: options.verbose || false,
41
- rules: options.rules ? options.rules.split(',') : undefined
42
- };
43
- const results = await (0, __1.scanFile)(filePath, scannerOptions);
44
- // Generate report
45
- const report = (0, __1.formatReport)(results, options.format, scannerOptions);
46
- // Output to console if not html format
47
- if (options.format !== 'html') {
48
- console.log(report);
49
- }
50
- // Save to file if specified
51
- if (options.output) {
52
- console.log(`Saving report to: ${options.output}`);
53
- (0, __1.saveReport)(report, options.output);
54
- }
55
- // Exit with appropriate code based on violations
56
- process.exit(results.violations.length > 0 ? 1 : 0);
57
- }
58
- catch (error) {
59
- console.error('Error scanning file:', error);
60
- process.exit(1);
61
- }
62
- });
63
- // Command to scan URL
64
- commander_1.program
65
- .command('url <url>')
66
- .description('Scan a website URL for accessibility issues')
67
- .option('-l, --level <level>', 'WCAG level (A, AA, AAA)', 'AA')
68
- .option('-f, --format <format>', 'Output format (json, console, html)', 'console')
69
- .option('-o, --output <file>', 'Save results to file')
70
- .option('-v, --verbose', 'Show verbose output')
71
- .option('-r, --rules <rules>', 'Comma-separated list of rules to check')
72
- .option('--ai', 'Enable AI-powered fix suggestions')
73
- .action(async (urlString, options) => {
74
- try {
75
- // Add protocol if missing
76
- if (!urlString.startsWith('http://') && !urlString.startsWith('https://')) {
77
- urlString = 'https://' + urlString;
78
- console.log(`Added protocol to URL: ${urlString}`);
79
- }
80
- console.log(`Scanning URL: ${urlString}`);
81
- // Create scanner options
82
- const scannerOptions = {
83
- level: options.level,
84
- verbose: options.verbose || false,
85
- baseUrl: urlString,
86
- rules: options.rules ? options.rules.split(',') : undefined,
87
- ai: options.ai || false,
88
- ignoreScriptErrors: true
89
- };
90
- // Use the scanUrl function that uses WASM internally
91
- const results = await (0, __2.scanUrl)(urlString, scannerOptions);
92
- // Generate report
93
- const report = (0, __1.formatReport)(results, options.format, scannerOptions);
94
- // Output to console if not html format
95
- if (options.format !== 'html') {
96
- console.log(report);
97
- }
98
- // Save to file if specified
99
- if (options.output) {
100
- console.log(`Saving report to: ${options.output}`);
101
- (0, __1.saveReport)(report, options.output);
102
- }
103
- // Exit with appropriate code based on violations
104
- process.exit(results.violations.length > 0 ? 1 : 0);
105
- }
106
- catch (error) {
107
- console.error('Error scanning URL:', error);
108
- process.exit(1);
109
- }
110
- });
111
- // Command to scan HTML from stdin
112
- commander_1.program
113
- .command('stdin')
114
- .description('Scan HTML input from stdin')
115
- .option('-l, --level <level>', 'WCAG level (A, AA, AAA)', 'AA')
116
- .option('-f, --format <format>', 'Output format (json, console, html)', 'console')
117
- .option('-o, --output <file>', 'Save results to file')
118
- .option('-v, --verbose', 'Show verbose output')
119
- .option('-r, --rules <rules>', 'Comma-separated list of rules to check')
120
- .action(async (options) => {
121
- try {
122
- console.log('Reading HTML from stdin...');
123
- let html = '';
124
- process.stdin.on('data', (chunk) => {
125
- html += chunk;
126
- });
127
- process.stdin.on('end', async () => {
128
- console.log(`Received ${html.length} bytes of HTML`);
129
- const scannerOptions = {
130
- level: options.level,
131
- verbose: options.verbose || false,
132
- rules: options.rules ? options.rules.split(',') : undefined
133
- };
134
- const results = await (0, __1.scanHtml)(html, scannerOptions);
135
- // Generate report
136
- const report = (0, __1.formatReport)(results, options.format, scannerOptions);
137
- // Output to console if not html format
138
- if (options.format !== 'html') {
139
- console.log(report);
140
- }
141
- // Save to file if specified
142
- if (options.output) {
143
- console.log(`Saving report to: ${options.output}`);
144
- (0, __1.saveReport)(report, options.output);
145
- }
146
- // Exit with appropriate code based on violations
147
- process.exit(results.violations.length > 0 ? 1 : 0);
148
- });
149
- }
150
- catch (error) {
151
- console.error('Error scanning HTML:', error);
152
- process.exit(1);
153
- }
154
- });
155
- // If no arguments provided, show help
156
- if (process.argv.length <= 2) {
157
- commander_1.program.help();
158
- }
159
- // Parse command line arguments
160
- commander_1.program.parse(process.argv);
@@ -1,19 +0,0 @@
1
- /**
2
- * WASM based URL scraper using Rust
3
- */
4
- export declare class WsamScraper {
5
- private wasmModule;
6
- private initialized;
7
- /**
8
- * Initialize the WASM scraper
9
- */
10
- initialize(): Promise<void>;
11
- /**
12
- * Scrape a URL using Rust/WASM
13
- * @param url URL to scrape
14
- * @returns Promise<string> HTML content
15
- */
16
- scrapeUrl(url: string): Promise<string>;
17
- }
18
- declare const _default: WsamScraper;
19
- export default _default;
@@ -1,53 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WsamScraper = void 0;
4
- /**
5
- * WASM based URL scraper using Rust
6
- */
7
- class WsamScraper {
8
- constructor() {
9
- this.initialized = false;
10
- }
11
- /**
12
- * Initialize the WASM scraper
13
- */
14
- async initialize() {
15
- if (this.initialized)
16
- return;
17
- try {
18
- // scrapper/pkg is generated by `npm run build:wasm` (wasm-pack build)
19
- this.wasmModule = require('../../scrapper/pkg/scrapper');
20
- this.wasmModule.init_panic_hook();
21
- this.initialized = true;
22
- console.log("WASM scraper initialized successfully");
23
- }
24
- catch (error) {
25
- console.error("Failed to initialize WASM scraper:", error);
26
- throw error;
27
- }
28
- }
29
- /**
30
- * Scrape a URL using Rust/WASM
31
- * @param url URL to scrape
32
- * @returns Promise<string> HTML content
33
- */
34
- async scrapeUrl(url) {
35
- if (!this.initialized) {
36
- await this.initialize();
37
- }
38
- console.log(`Scraping URL using Rust/WASM: ${url}`);
39
- try {
40
- const uint8Array = await this.wasmModule.scrape_url(url);
41
- const decoder = new TextDecoder('utf-8');
42
- const html = decoder.decode(uint8Array);
43
- console.log(`Successfully scraped ${html.length} bytes of HTML content`);
44
- return html;
45
- }
46
- catch (error) {
47
- console.error("Error in WASM scraper:", error);
48
- throw error;
49
- }
50
- }
51
- }
52
- exports.WsamScraper = WsamScraper;
53
- exports.default = new WsamScraper;