lingo-guardian 0.1.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 (38) hide show
  1. package/README.md +45 -0
  2. package/dist/bin/cli.d.ts +10 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +36 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/commands/lint.d.ts +19 -0
  7. package/dist/commands/lint.d.ts.map +1 -0
  8. package/dist/commands/lint.js +166 -0
  9. package/dist/commands/lint.js.map +1 -0
  10. package/dist/constants.d.ts +110 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/constants.js +41 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/core/auditor.d.ts +62 -0
  15. package/dist/core/auditor.d.ts.map +1 -0
  16. package/dist/core/auditor.js +261 -0
  17. package/dist/core/auditor.js.map +1 -0
  18. package/dist/core/lingo-integration.d.ts +109 -0
  19. package/dist/core/lingo-integration.d.ts.map +1 -0
  20. package/dist/core/lingo-integration.js +243 -0
  21. package/dist/core/lingo-integration.js.map +1 -0
  22. package/dist/index.d.ts +12 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +11 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/reporters/reporter.d.ts +35 -0
  27. package/dist/reporters/reporter.d.ts.map +1 -0
  28. package/dist/reporters/reporter.js +322 -0
  29. package/dist/reporters/reporter.js.map +1 -0
  30. package/dist/transforms/pseudo-locale.d.ts +22 -0
  31. package/dist/transforms/pseudo-locale.d.ts.map +1 -0
  32. package/dist/transforms/pseudo-locale.js +181 -0
  33. package/dist/transforms/pseudo-locale.js.map +1 -0
  34. package/dist/transforms/rtl.d.ts +26 -0
  35. package/dist/transforms/rtl.d.ts.map +1 -0
  36. package/dist/transforms/rtl.js +120 -0
  37. package/dist/transforms/rtl.js.map +1 -0
  38. package/package.json +70 -0
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # 🛡️ Lingo-Guardian CLI
2
+
3
+ > **Detect i18n layout issues before they reach production**
4
+
5
+ Powered by [Lingo.dev](https://lingo.dev)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g lingo-guardian
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Initialize Lingo.dev in your project
17
+ npx lingo.dev@latest init
18
+
19
+ # Run the audit
20
+ lingo-guardian lint http://localhost:3000
21
+ ```
22
+
23
+ ## Features
24
+
25
+ - 🔍 CSS overflow detection (`scrollWidth > offsetWidth`)
26
+ - 🌍 Pseudo-locale text expansion testing
27
+ - ↔️ RTL layout validation
28
+ - 📊 Table, JSON, and HTML reports
29
+ - 🖥️ Cross-platform (Mac, Windows, Linux)
30
+
31
+ ## Usage
32
+
33
+ ```bash
34
+ lingo-guardian lint <url> [options]
35
+
36
+ Options:
37
+ -l, --locale <locales...> Locales to test (default: ["en", "pseudo"])
38
+ -f, --format <format> Output format: table, json, html
39
+ --fail-on-error Exit with error code if issues found
40
+ -v, --verbose Enable verbose logging
41
+ ```
42
+
43
+ ## License
44
+
45
+ MIT
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lingo-Guardian CLI
4
+ * The Automated DevSecOps Firewall for Internationalization
5
+ *
6
+ * Detects UI overflows, RTL layout breaks, and missing i18n keys
7
+ * before they reach production.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AACA;;;;;;GAMG"}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lingo-Guardian CLI
4
+ * The Automated DevSecOps Firewall for Internationalization
5
+ *
6
+ * Detects UI overflows, RTL layout breaks, and missing i18n keys
7
+ * before they reach production.
8
+ */
9
+ import { Command } from 'commander';
10
+ import chalk from 'chalk';
11
+ import { lintCommand } from '../commands/lint.js';
12
+ import { VERSION, BANNER } from '../constants.js';
13
+ const program = new Command();
14
+ // Display banner
15
+ console.log(chalk.cyan(BANNER));
16
+ program
17
+ .name('lingo-guardian')
18
+ .description('The Automated DevSecOps Firewall for Internationalization')
19
+ .version(VERSION, '-v, --version', 'Display version number');
20
+ // Register commands
21
+ program.addCommand(lintCommand);
22
+ // Error handling
23
+ program.exitOverride((err) => {
24
+ if (err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
25
+ process.exit(0);
26
+ }
27
+ console.error(chalk.red(`\n❌ Error: ${err.message}`));
28
+ process.exit(1);
29
+ });
30
+ // Parse arguments
31
+ program.parse(process.argv);
32
+ // Show help if no command provided
33
+ if (!process.argv.slice(2).length) {
34
+ program.outputHelp();
35
+ }
36
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,iBAAiB;AACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAEhC,OAAO;KACF,IAAI,CAAC,gBAAgB,CAAC;KACtB,WAAW,CAAC,2DAA2D,CAAC;KACxE,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAAC;AAEjE,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAEhC,iBAAiB;AACjB,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE;IACzB,IAAI,GAAG,CAAC,IAAI,KAAK,yBAAyB,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC;AAEH,kBAAkB;AAClB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,mCAAmC;AACnC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAChC,OAAO,CAAC,UAAU,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Lint Command
3
+ *
4
+ * Main command for auditing i18n layout issues.
5
+ *
6
+ * NEW: Now integrates with Lingo.dev CLI to generate translations!
7
+ *
8
+ * Usage: lingo-guardian lint <url> [options]
9
+ */
10
+ import { Command } from 'commander';
11
+ import { LintOptions } from '../constants.js';
12
+ export interface ExtendedLintOptions extends LintOptions {
13
+ /** Project directory containing i18n.json */
14
+ project: string;
15
+ /** Run Lingo.dev CLI to generate translations before audit */
16
+ useLingo: boolean;
17
+ }
18
+ export declare const lintCommand: Command;
19
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,OAAO,EAAwB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEpE,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACpD,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,SA0ClB,CAAC"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Lint Command
3
+ *
4
+ * Main command for auditing i18n layout issues.
5
+ *
6
+ * NEW: Now integrates with Lingo.dev CLI to generate translations!
7
+ *
8
+ * Usage: lingo-guardian lint <url> [options]
9
+ */
10
+ import { Command } from 'commander';
11
+ import chalk from 'chalk';
12
+ import ora from 'ora';
13
+ import path from 'path';
14
+ import { Auditor } from '../core/auditor.js';
15
+ import { LingoIntegration } from '../core/lingo-integration.js';
16
+ import { Reporter } from '../reporters/reporter.js';
17
+ import { DEFAULTS, EXIT_CODES } from '../constants.js';
18
+ export const lintCommand = new Command('lint')
19
+ .description('Audit a URL for i18n layout issues using Lingo.dev for translations')
20
+ .argument('<url>', 'URL to audit (e.g., http://localhost:3000)')
21
+ .option('-p, --project <path>', 'Path to project directory containing i18n.json', process.cwd())
22
+ .option('--use-lingo', 'Run Lingo.dev CLI to generate translations before audit', true)
23
+ .option('-l, --locale <locales...>', 'Locales to test (e.g., en pseudo ar de)', ['en', 'pseudo'])
24
+ .option('-f, --format <format>', 'Output format: table, json, html', 'table')
25
+ .option('-s, --screenshot', 'Capture screenshots of issues', false)
26
+ .option('-o, --output <dir>', 'Output directory for reports', './lingo-guardian-reports')
27
+ .option('--fail-on-error', 'Exit with error code if issues found', false)
28
+ .option('-w, --width <pixels>', 'Viewport width', String(DEFAULTS.VIEWPORT_WIDTH))
29
+ .option('--height <pixels>', 'Viewport height', String(DEFAULTS.VIEWPORT_HEIGHT))
30
+ .option('-t, --timeout <ms>', 'Page load timeout in milliseconds', String(DEFAULTS.TIMEOUT))
31
+ .option('-v, --verbose', 'Enable verbose logging', false)
32
+ .action(async (url, options) => {
33
+ const lintOptions = {
34
+ project: options.project,
35
+ useLingo: options.useLingo,
36
+ locale: options.locale,
37
+ format: options.format,
38
+ screenshot: options.screenshot,
39
+ output: options.output,
40
+ failOnError: options.failOnError,
41
+ width: parseInt(options.width, 10),
42
+ height: parseInt(options.height, 10),
43
+ timeout: parseInt(options.timeout, 10),
44
+ verbose: options.verbose,
45
+ };
46
+ await runLintAudit(url, lintOptions);
47
+ });
48
+ /**
49
+ * Execute the lint audit with Lingo.dev integration
50
+ */
51
+ async function runLintAudit(url, options) {
52
+ const spinner = ora({
53
+ text: 'Initializing Lingo-Guardian...',
54
+ color: 'cyan',
55
+ }).start();
56
+ const projectPath = path.resolve(options.project);
57
+ const lingo = new LingoIntegration(projectPath, options.verbose);
58
+ const auditor = new Auditor({
59
+ width: options.width,
60
+ height: options.height,
61
+ timeout: options.timeout,
62
+ screenshots: options.screenshot,
63
+ outputDir: options.output,
64
+ verbose: options.verbose,
65
+ });
66
+ const reporter = new Reporter(options.format);
67
+ try {
68
+ // STEP 1: Detect Lingo.dev configuration
69
+ spinner.text = 'Detecting Lingo.dev configuration...';
70
+ const hasConfig = await lingo.detectConfig();
71
+ if (options.useLingo) {
72
+ if (!hasConfig) {
73
+ spinner.warn('No Lingo.dev config (i18n.json) found. Use --no-use-lingo to skip.');
74
+ console.log(chalk.yellow('\n💡 To initialize Lingo.dev, run:'));
75
+ console.log(chalk.cyan(` cd ${projectPath} && npx lingo.dev@latest init\n`));
76
+ }
77
+ else {
78
+ // Show detected config
79
+ const config = lingo.getConfig();
80
+ if (config) {
81
+ spinner.info(`Lingo.dev config: source=${config.locale.source}, targets=${config.locale.targets.join(', ')}`);
82
+ spinner.start();
83
+ }
84
+ // STEP 2: Ensure pseudo-locale is enabled for testing
85
+ if (options.locale.includes('pseudo')) {
86
+ spinner.text = 'Ensuring pseudo-locale is enabled...';
87
+ await lingo.enablePseudoLocale();
88
+ }
89
+ // STEP 3: Run Lingo.dev CLI to generate translations
90
+ spinner.text = chalk.magenta('🌍 Running Lingo.dev CLI to generate translations...');
91
+ const lingoResult = await lingo.runTranslation({ force: false });
92
+ if (lingoResult.success) {
93
+ spinner.succeed(chalk.green(`Lingo.dev generated ${lingoResult.localesGenerated.length} locale(s)`));
94
+ }
95
+ else {
96
+ spinner.warn('Lingo.dev CLI completed with warnings');
97
+ if (options.verbose && lingoResult.error) {
98
+ console.log(chalk.yellow(lingoResult.error));
99
+ }
100
+ }
101
+ spinner.start();
102
+ }
103
+ }
104
+ // STEP 4: Initialize browser for overflow detection
105
+ spinner.text = 'Launching headless browser...';
106
+ await auditor.init();
107
+ const results = [];
108
+ // STEP 5: Audit each locale
109
+ for (const locale of options.locale) {
110
+ // Build URL with locale query param for Lingo SDK integration
111
+ const localeUrl = buildLocaleUrl(url, locale);
112
+ spinner.text = `Auditing with locale: ${chalk.cyan(locale.toUpperCase())}...`;
113
+ if (options.verbose) {
114
+ console.log(chalk.gray(` URL: ${localeUrl}`));
115
+ }
116
+ const result = await auditor.audit(localeUrl, locale);
117
+ results.push(result);
118
+ if (options.verbose) {
119
+ spinner.info(`${locale}: Found ${result.issueCount} issues (${result.duration}ms)`);
120
+ spinner.start();
121
+ }
122
+ }
123
+ // Close browser
124
+ await auditor.close();
125
+ spinner.succeed('Audit complete!');
126
+ // Print results
127
+ reporter.print(results);
128
+ // Print Lingo.dev integration note
129
+ console.log(chalk.gray('\n📦 Powered by Lingo.dev - https://lingo.dev\n'));
130
+ // Save report if output format is json or html
131
+ if (options.format === 'json' || options.format === 'html') {
132
+ await reporter.save(results, options.output);
133
+ }
134
+ // Exit with error if issues found and failOnError is set
135
+ const hasErrors = results.some((r) => r.issues.some((i) => i.severity === 'error'));
136
+ if (options.failOnError && hasErrors) {
137
+ console.log(chalk.red('\n💥 Exiting with error due to --fail-on-error flag'));
138
+ process.exit(EXIT_CODES.LINT_ISSUES_FOUND);
139
+ }
140
+ }
141
+ catch (error) {
142
+ spinner.fail('Audit failed');
143
+ if (error instanceof Error) {
144
+ console.error(chalk.red(`\n❌ Error: ${error.message}`));
145
+ if (options.verbose && error.stack) {
146
+ console.error(chalk.gray(error.stack));
147
+ }
148
+ }
149
+ await auditor.close();
150
+ process.exit(EXIT_CODES.GENERAL_ERROR);
151
+ }
152
+ }
153
+ /**
154
+ * Build URL with locale query parameter for Lingo.dev SDK
155
+ *
156
+ * The Lingo.dev SDK can detect locale from URL params:
157
+ * - ?lang=es
158
+ * - ?locale=es
159
+ */
160
+ function buildLocaleUrl(baseUrl, locale) {
161
+ const url = new URL(baseUrl);
162
+ // Add locale query param for Lingo SDK
163
+ url.searchParams.set('lang', locale);
164
+ return url.toString();
165
+ }
166
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Constants and configuration for Lingo-Guardian CLI
3
+ */
4
+ export declare const VERSION = "0.1.0";
5
+ export declare const BANNER = "\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551 \u2551\n\u2551 \uD83D\uDEE1\uFE0F LINGO-GUARDIAN \u2551\n\u2551 The Automated i18n Firewall for React \u2551\n\u2551 \u2551\n\u2551 Powered by Lingo.dev \u2551\n\u2551 \u2551\n\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n";
6
+ /**
7
+ * Default configuration values
8
+ */
9
+ export declare const DEFAULTS: {
10
+ /** Default timeout for page load in milliseconds */
11
+ readonly TIMEOUT: 30000;
12
+ /** Default viewport width */
13
+ readonly VIEWPORT_WIDTH: 1280;
14
+ /** Default viewport height */
15
+ readonly VIEWPORT_HEIGHT: 720;
16
+ /** Default locales to test */
17
+ readonly LOCALES: readonly ["en", "pseudo", "ar", "de"];
18
+ /** Selectors to exclude from scanning */
19
+ readonly EXCLUDED_SELECTORS: readonly ["script", "style", "noscript", "svg", "path"];
20
+ /** Text expansion factor for pseudo-locale */
21
+ readonly PSEUDO_EXPANSION_FACTOR: 0.35;
22
+ };
23
+ /**
24
+ * Exit codes following standard conventions
25
+ */
26
+ export declare const EXIT_CODES: {
27
+ readonly SUCCESS: 0;
28
+ readonly GENERAL_ERROR: 1;
29
+ readonly LINT_ISSUES_FOUND: 2;
30
+ readonly INVALID_ARGUMENTS: 3;
31
+ };
32
+ /**
33
+ * Issue severity levels
34
+ */
35
+ export type Severity = 'error' | 'warning' | 'info';
36
+ /**
37
+ * Overflow issue detected by the auditor
38
+ */
39
+ export interface OverflowIssue {
40
+ /** CSS selector path to the element */
41
+ selector: string;
42
+ /** HTML tag name */
43
+ tagName: string;
44
+ /** Text content (truncated) */
45
+ textContent: string;
46
+ /** Element's offset width */
47
+ offsetWidth: number;
48
+ /** Element's scroll width */
49
+ scrollWidth: number;
50
+ /** Element's offset height */
51
+ offsetHeight: number;
52
+ /** Element's scroll height */
53
+ scrollHeight: number;
54
+ /** Overflow direction */
55
+ overflowDirection: 'horizontal' | 'vertical' | 'both';
56
+ /** Severity of the issue */
57
+ severity: Severity;
58
+ /** Locale where issue was detected */
59
+ locale: string;
60
+ /** Bounding rect for screenshot */
61
+ boundingRect: {
62
+ x: number;
63
+ y: number;
64
+ width: number;
65
+ height: number;
66
+ };
67
+ }
68
+ /**
69
+ * Audit result for a single page
70
+ */
71
+ export interface AuditResult {
72
+ /** URL that was audited */
73
+ url: string;
74
+ /** Locale tested */
75
+ locale: string;
76
+ /** Timestamp of audit */
77
+ timestamp: string;
78
+ /** Total issues found */
79
+ issueCount: number;
80
+ /** List of overflow issues */
81
+ issues: OverflowIssue[];
82
+ /** Duration of audit in ms */
83
+ duration: number;
84
+ /** Screenshot path if captured */
85
+ screenshotPath?: string;
86
+ }
87
+ /**
88
+ * CLI options for lint command
89
+ */
90
+ export interface LintOptions {
91
+ /** Locales to test */
92
+ locale: string[];
93
+ /** Output format */
94
+ format: 'table' | 'json' | 'html';
95
+ /** Take screenshots */
96
+ screenshot: boolean;
97
+ /** Output directory for reports */
98
+ output: string;
99
+ /** Fail on errors */
100
+ failOnError: boolean;
101
+ /** Custom viewport width */
102
+ width: number;
103
+ /** Custom viewport height */
104
+ height: number;
105
+ /** Timeout in ms */
106
+ timeout: number;
107
+ /** Verbose logging */
108
+ verbose: boolean;
109
+ }
110
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,eAAO,MAAM,MAAM,6qCASlB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ;IACjB,oDAAoD;;IAEpD,6BAA6B;;IAE7B,8BAA8B;;IAE9B,8BAA8B;;IAE9B,yCAAyC;;IAEzC,8CAA8C;;CAExC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,iBAAiB,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC;IACtD,4BAA4B;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,YAAY,EAAE;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAClB,CAAC;CACL;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,sBAAsB;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oBAAoB;IACpB,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,uBAAuB;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,OAAO,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Constants and configuration for Lingo-Guardian CLI
3
+ */
4
+ export const VERSION = '0.1.0';
5
+ export const BANNER = `
6
+ ╔═══════════════════════════════════════════════════════════╗
7
+ ║ ║
8
+ ║ 🛡️ LINGO-GUARDIAN ║
9
+ ║ The Automated i18n Firewall for React ║
10
+ ║ ║
11
+ ║ Powered by Lingo.dev ║
12
+ ║ ║
13
+ ╚═══════════════════════════════════════════════════════════╝
14
+ `;
15
+ /**
16
+ * Default configuration values
17
+ */
18
+ export const DEFAULTS = {
19
+ /** Default timeout for page load in milliseconds */
20
+ TIMEOUT: 30000,
21
+ /** Default viewport width */
22
+ VIEWPORT_WIDTH: 1280,
23
+ /** Default viewport height */
24
+ VIEWPORT_HEIGHT: 720,
25
+ /** Default locales to test */
26
+ LOCALES: ['en', 'pseudo', 'ar', 'de'],
27
+ /** Selectors to exclude from scanning */
28
+ EXCLUDED_SELECTORS: ['script', 'style', 'noscript', 'svg', 'path'],
29
+ /** Text expansion factor for pseudo-locale */
30
+ PSEUDO_EXPANSION_FACTOR: 0.35,
31
+ };
32
+ /**
33
+ * Exit codes following standard conventions
34
+ */
35
+ export const EXIT_CODES = {
36
+ SUCCESS: 0,
37
+ GENERAL_ERROR: 1,
38
+ LINT_ISSUES_FOUND: 2,
39
+ INVALID_ARGUMENTS: 3,
40
+ };
41
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;CASrB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACpB,oDAAoD;IACpD,OAAO,EAAE,KAAK;IACd,6BAA6B;IAC7B,cAAc,EAAE,IAAI;IACpB,8BAA8B;IAC9B,eAAe,EAAE,GAAG;IACpB,8BAA8B;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAU;IAC9C,yCAAyC;IACzC,kBAAkB,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC;IAClE,8CAA8C;IAC9C,uBAAuB,EAAE,IAAI;CACvB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACtB,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,iBAAiB,EAAE,CAAC;IACpB,iBAAiB,EAAE,CAAC;CACd,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Auditor - Core engine for detecting i18n layout issues
3
+ *
4
+ * Uses Playwright (cross-platform: Mac, Windows, Linux) to analyze pages for:
5
+ * - Text overflow (scrollWidth > offsetWidth)
6
+ * - Text truncation (text-overflow: ellipsis detection)
7
+ * - Layout breaks in RTL mode
8
+ */
9
+ import type { AuditResult } from '../constants.js';
10
+ export interface AuditorOptions {
11
+ /** Viewport width */
12
+ width?: number;
13
+ /** Viewport height */
14
+ height?: number;
15
+ /** Page load timeout in ms */
16
+ timeout?: number;
17
+ /** Take screenshots of issues */
18
+ screenshots?: boolean;
19
+ /** Output directory for screenshots */
20
+ outputDir?: string;
21
+ /** Verbose logging */
22
+ verbose?: boolean;
23
+ }
24
+ /**
25
+ * Core Auditor class for detecting i18n layout issues
26
+ *
27
+ * Uses Playwright for cross-platform browser automation (Mac, Windows, Linux)
28
+ */
29
+ export declare class Auditor {
30
+ private browser;
31
+ private context;
32
+ private options;
33
+ constructor(options?: AuditorOptions);
34
+ /**
35
+ * Initialize the browser instance
36
+ * Playwright handles cross-platform browser binaries automatically
37
+ */
38
+ init(): Promise<void>;
39
+ /**
40
+ * Close the browser instance
41
+ */
42
+ close(): Promise<void>;
43
+ /**
44
+ * Audit a URL for i18n layout issues
45
+ */
46
+ audit(url: string, locale?: string): Promise<AuditResult>;
47
+ /**
48
+ * Apply locale-specific transformations to the page
49
+ * These are fallback transforms when Lingo.dev integration is not used
50
+ */
51
+ private applyLocaleTransform;
52
+ /**
53
+ * Detect elements with overflow issues
54
+ * Core detection logic: element.scrollWidth > element.offsetWidth
55
+ */
56
+ private detectOverflows;
57
+ /**
58
+ * Log message if verbose mode is enabled
59
+ */
60
+ private log;
61
+ }
62
+ //# sourceMappingURL=auditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditor.d.ts","sourceRoot":"","sources":["../../src/core/auditor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAiB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKlE,MAAM,WAAW,cAAc;IAC3B,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAkBD;;;;GAIG;AACH,qBAAa,OAAO;IAChB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,GAAE,cAAmB;IAWxC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B;;OAEG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAa,GAAG,OAAO,CAAC,WAAW,CAAC;IAyCrE;;;OAGG;YACW,oBAAoB;IAmClC;;;OAGG;YACW,eAAe;IAkI7B;;OAEG;IACH,OAAO,CAAC,GAAG;CAKd"}