@hyperfixi/testing-framework 2.0.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 (37) hide show
  1. package/dist/assertions-BImuwZsB.d.mts +458 -0
  2. package/dist/assertions-BImuwZsB.d.ts +458 -0
  3. package/dist/assertions.d.mts +1 -0
  4. package/dist/assertions.d.ts +1 -0
  5. package/dist/assertions.js +625 -0
  6. package/dist/assertions.js.map +1 -0
  7. package/dist/assertions.mjs +621 -0
  8. package/dist/assertions.mjs.map +1 -0
  9. package/dist/index.d.mts +246 -0
  10. package/dist/index.d.ts +246 -0
  11. package/dist/index.js +1465 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/index.mjs +1435 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/package.json +121 -0
  16. package/src/assertions.test.ts +490 -0
  17. package/src/assertions.ts +779 -0
  18. package/src/index.test.ts +490 -0
  19. package/src/index.ts +601 -0
  20. package/src/jsdom.d.ts +7 -0
  21. package/src/multilingual/README.md +295 -0
  22. package/src/multilingual/bundle-builder.ts +345 -0
  23. package/src/multilingual/cli.ts +224 -0
  24. package/src/multilingual/index.ts +68 -0
  25. package/src/multilingual/orchestrator.ts +275 -0
  26. package/src/multilingual/pattern-loader.ts +176 -0
  27. package/src/multilingual/reporters/console-reporter.ts +294 -0
  28. package/src/multilingual/reporters/json-reporter.ts +99 -0
  29. package/src/multilingual/reporters/regression-reporter.ts +263 -0
  30. package/src/multilingual/tools/analyze-failures.ts +326 -0
  31. package/src/multilingual/types.ts +268 -0
  32. package/src/multilingual/validators/parse-diagnostics.ts +337 -0
  33. package/src/multilingual/validators/parse-validator.ts +193 -0
  34. package/src/multilingual/validators/size-validator.ts +187 -0
  35. package/src/runner.test.ts +813 -0
  36. package/src/runner.ts +639 -0
  37. package/src/types.ts +505 -0
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Core types for multilingual testing framework
3
+ */
4
+
5
+ /**
6
+ * Supported languages
7
+ */
8
+ export type LanguageCode =
9
+ | 'ar' // Arabic (VSO)
10
+ | 'bn' // Bengali (SOV)
11
+ | 'de' // German (V2)
12
+ | 'en' // English (SVO)
13
+ | 'es' // Spanish (SVO)
14
+ | 'fr' // French (SVO)
15
+ | 'hi' // Hindi (SOV)
16
+ | 'id' // Indonesian (SVO)
17
+ | 'it' // Italian (SVO)
18
+ | 'ja' // Japanese (SOV)
19
+ | 'ko' // Korean (SOV)
20
+ | 'ms' // Malay (SVO)
21
+ | 'pl' // Polish (SVO)
22
+ | 'pt' // Portuguese (SVO)
23
+ | 'qu' // Quechua (SOV)
24
+ | 'ru' // Russian (SVO)
25
+ | 'sw' // Swahili (SVO)
26
+ | 'th' // Thai (SVO)
27
+ | 'tl' // Tagalog (VSO)
28
+ | 'tr' // Turkish (SOV)
29
+ | 'uk' // Ukrainian (SVO)
30
+ | 'vi' // Vietnamese (SVO)
31
+ | 'zh'; // Chinese (SVO)
32
+
33
+ /**
34
+ * Word order types
35
+ */
36
+ export type WordOrder = 'SVO' | 'SOV' | 'VSO' | 'V2';
37
+
38
+ /**
39
+ * Pattern from the patterns-reference database
40
+ */
41
+ export interface Pattern {
42
+ id: string;
43
+ title: string;
44
+ raw_code: string;
45
+ description: string;
46
+ feature: string;
47
+ source_url?: string;
48
+ created_at: Date;
49
+ }
50
+
51
+ /**
52
+ * Pattern translation
53
+ */
54
+ export interface PatternTranslation {
55
+ codeExampleId: string;
56
+ language: LanguageCode;
57
+ hyperscript: string;
58
+ wordOrder: WordOrder;
59
+ confidence: number;
60
+ verifiedParses: boolean;
61
+ roleAlignmentScore: number;
62
+ }
63
+
64
+ /**
65
+ * Test configuration
66
+ */
67
+ export interface TestConfig {
68
+ /** Languages to test (undefined = all) */
69
+ languages?: LanguageCode[];
70
+
71
+ /** Bundle to use (if undefined, will build/select automatically) */
72
+ bundle?: string;
73
+
74
+ /** Whether to build bundle before testing */
75
+ build?: boolean;
76
+
77
+ /** Test mode */
78
+ mode: 'quick' | 'full';
79
+
80
+ /** Enable verbose logging */
81
+ verbose?: boolean;
82
+
83
+ /** Enable regression comparison */
84
+ regression?: boolean;
85
+
86
+ /** Minimum confidence threshold for semantic parsing */
87
+ confidenceThreshold?: number;
88
+
89
+ /** Only test patterns that have verifiedParses = true */
90
+ verifiedOnly?: boolean;
91
+
92
+ /** Pattern categories to test */
93
+ categories?: string[];
94
+
95
+ /** Number of patterns per language in quick mode */
96
+ quickModeLimit?: number;
97
+ }
98
+
99
+ /**
100
+ * Parse validation result
101
+ */
102
+ export interface ParseResult {
103
+ pattern: PatternTranslation;
104
+ success: boolean;
105
+ command?: string;
106
+ roles?: Record<string, unknown>;
107
+ confidence?: number;
108
+ parser?: 'semantic' | 'traditional';
109
+ error?: string;
110
+ duration: number; // ms
111
+ }
112
+
113
+ /**
114
+ * Size validation result
115
+ */
116
+ export interface SizeResult {
117
+ bundlePath: string;
118
+ size: number; // bytes
119
+ gzipSize: number | undefined; // bytes
120
+ exceedsThreshold: boolean;
121
+ threshold: number | undefined;
122
+ }
123
+
124
+ /**
125
+ * Language test results
126
+ */
127
+ export interface LanguageResults {
128
+ language: LanguageCode;
129
+ bundle: string;
130
+ bundleSize?: number;
131
+
132
+ /** Parse validation results */
133
+ parseResults: ParseResult[];
134
+ parseSuccess: number;
135
+ parseFailure: number;
136
+ parseRate: number;
137
+ avgConfidence: number;
138
+
139
+ /** Duration in ms */
140
+ duration: number;
141
+
142
+ /** Overall status */
143
+ status: 'pass' | 'fail' | 'warning';
144
+ }
145
+
146
+ /**
147
+ * Complete test run results
148
+ */
149
+ export interface TestResults {
150
+ timestamp: string;
151
+ commit: string | undefined;
152
+ config: TestConfig;
153
+
154
+ /** Results by language */
155
+ languageResults: LanguageResults[];
156
+
157
+ /** Bundle size information */
158
+ bundles: Record<
159
+ string,
160
+ {
161
+ size: number;
162
+ languages: LanguageCode[];
163
+ gzipSize?: number;
164
+ }
165
+ >;
166
+
167
+ /** Summary statistics */
168
+ summary: {
169
+ totalPatterns: number;
170
+ totalSuccess: number;
171
+ totalFailure: number;
172
+ totalDuration: number;
173
+ overallStatus: 'pass' | 'fail' | 'warning';
174
+ };
175
+ }
176
+
177
+ /**
178
+ * Baseline data for regression testing
179
+ */
180
+ export interface Baseline {
181
+ timestamp: string;
182
+ commit: string;
183
+ languages: Partial<
184
+ Record<
185
+ LanguageCode,
186
+ {
187
+ parseSuccess: number;
188
+ parseFailure: number;
189
+ parseRate: number;
190
+ avgConfidence: number;
191
+ bundleSize: number | undefined;
192
+ /** Pattern-level results for detailed tracking */
193
+ patterns: Record<string, { success: boolean; confidence: number | undefined }> | undefined;
194
+ }
195
+ >
196
+ >;
197
+ bundles: Record<
198
+ string,
199
+ {
200
+ size: number;
201
+ languages: LanguageCode[];
202
+ gzipSize: number | undefined;
203
+ }
204
+ >;
205
+ }
206
+
207
+ /**
208
+ * Regression comparison result
209
+ */
210
+ export interface RegressionResult {
211
+ language: LanguageCode;
212
+ parseRateDelta: number; // % change
213
+ avgConfidenceDelta: number; // absolute change
214
+ bundleSizeDelta: number | undefined; // % change
215
+ newFailures: string[]; // pattern IDs
216
+ newSuccesses: string[]; // pattern IDs
217
+ status: 'improved' | 'regressed' | 'unchanged';
218
+ }
219
+
220
+ /**
221
+ * Bundle build options
222
+ */
223
+ export interface BundleBuildOptions {
224
+ languages: LanguageCode[];
225
+ outputPath: string | undefined;
226
+ groupName: string | undefined; // e.g., 'western', 'east-asian'
227
+ updateConfig: boolean | undefined; // Update tsup.config.ts
228
+ }
229
+
230
+ /**
231
+ * Bundle information
232
+ */
233
+ export interface BundleInfo {
234
+ name: string;
235
+ path: string;
236
+ languages: LanguageCode[];
237
+ size: number;
238
+ exists: boolean;
239
+ }
240
+
241
+ /**
242
+ * Reporter interface
243
+ */
244
+ export interface Reporter {
245
+ reportStart(config: TestConfig): void;
246
+ reportLanguageStart(language: LanguageCode, bundle: string): void;
247
+ reportLanguageComplete(results: LanguageResults): void;
248
+ reportComplete(results: TestResults): void;
249
+ reportRegression?(results: RegressionResult[]): void;
250
+ reportError(error: Error): void;
251
+ }
252
+
253
+ /**
254
+ * Validator interface
255
+ */
256
+ export interface Validator<T> {
257
+ validate(input: unknown): Promise<T>;
258
+ getName(): string;
259
+ }
260
+
261
+ /**
262
+ * Sampling strategy for pattern selection
263
+ */
264
+ export type SamplingStrategy =
265
+ | { type: 'all' }
266
+ | { type: 'first'; count: number }
267
+ | { type: 'random'; count: number }
268
+ | { type: 'stratified'; perCategory: number };
@@ -0,0 +1,337 @@
1
+ /**
2
+ * Parse Diagnostics - Enhanced debugging for multilingual parsing failures
3
+ */
4
+
5
+ import type { PatternTranslation, LanguageCode, ParseResult } from '../types';
6
+
7
+ export interface ParseTrace {
8
+ stage: string;
9
+ timestamp: number;
10
+ data: unknown;
11
+ error: string | undefined;
12
+ }
13
+
14
+ export interface DiagnosticResult {
15
+ pattern: PatternTranslation;
16
+ traces: ParseTrace[];
17
+ parseResult: ParseResult | undefined;
18
+ analysisNotes: string[];
19
+ }
20
+
21
+ export interface FailurePattern {
22
+ type: string;
23
+ count: number;
24
+ examples: string[];
25
+ affectedLanguages: LanguageCode[];
26
+ }
27
+
28
+ /**
29
+ * Parse Diagnostics Collector
30
+ *
31
+ * Captures detailed trace information during parsing for debugging
32
+ */
33
+ export class ParseDiagnostics {
34
+ private traces: Map<string, ParseTrace[]> = new Map();
35
+ private enabled: boolean;
36
+
37
+ constructor(enabled: boolean = false) {
38
+ this.enabled = enabled;
39
+ }
40
+
41
+ /**
42
+ * Enable/disable diagnostics collection
43
+ */
44
+ setEnabled(enabled: boolean): void {
45
+ this.enabled = enabled;
46
+ }
47
+
48
+ /**
49
+ * Record a trace event
50
+ */
51
+ trace(patternId: string, stage: string, data?: unknown, error?: string): void {
52
+ if (!this.enabled) return;
53
+
54
+ const traces = this.traces.get(patternId) || [];
55
+ traces.push({
56
+ stage,
57
+ timestamp: performance.now(),
58
+ data,
59
+ error,
60
+ });
61
+ this.traces.set(patternId, traces);
62
+ }
63
+
64
+ /**
65
+ * Get traces for a pattern
66
+ */
67
+ getTraces(patternId: string): ParseTrace[] {
68
+ return this.traces.get(patternId) || [];
69
+ }
70
+
71
+ /**
72
+ * Clear all traces
73
+ */
74
+ clear(): void {
75
+ this.traces.clear();
76
+ }
77
+
78
+ /**
79
+ * Export all traces
80
+ */
81
+ exportTraces(): Map<string, ParseTrace[]> {
82
+ return new Map(this.traces);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Failure Pattern Analyzer
88
+ *
89
+ * Analyzes parse failures to identify common patterns and issues
90
+ */
91
+ export class FailureAnalyzer {
92
+ /**
93
+ * Analyze failures and group by common patterns
94
+ */
95
+ analyzeFailures(results: ParseResult[]): FailurePattern[] {
96
+ const failures = results.filter(r => !r.success);
97
+ const patterns: Map<string, FailurePattern> = new Map();
98
+
99
+ for (const failure of failures) {
100
+ // Categorize by error message
101
+ const errorType = this.categorizeError(failure.error || 'Unknown error');
102
+
103
+ if (!patterns.has(errorType)) {
104
+ patterns.set(errorType, {
105
+ type: errorType,
106
+ count: 0,
107
+ examples: [],
108
+ affectedLanguages: [],
109
+ });
110
+ }
111
+
112
+ const pattern = patterns.get(errorType)!;
113
+ pattern.count++;
114
+
115
+ if (pattern.examples.length < 5) {
116
+ pattern.examples.push(failure.pattern.hyperscript);
117
+ }
118
+
119
+ if (!pattern.affectedLanguages.includes(failure.pattern.language)) {
120
+ pattern.affectedLanguages.push(failure.pattern.language);
121
+ }
122
+ }
123
+
124
+ return Array.from(patterns.values()).sort((a, b) => b.count - a.count);
125
+ }
126
+
127
+ /**
128
+ * Categorize error by type
129
+ */
130
+ private categorizeError(error: string): string {
131
+ if (error.includes('null or undefined')) {
132
+ return 'Parse returned null';
133
+ }
134
+ if (error.includes('timeout')) {
135
+ return 'Parse timeout';
136
+ }
137
+ if (error.includes('token')) {
138
+ return 'Tokenization error';
139
+ }
140
+ if (error.includes('syntax')) {
141
+ return 'Syntax error';
142
+ }
143
+ if (error.includes('semantic')) {
144
+ return 'Semantic error';
145
+ }
146
+ return 'Other error';
147
+ }
148
+
149
+ /**
150
+ * Analyze language-specific issues
151
+ */
152
+ analyzeByLanguage(results: ParseResult[]): Record<
153
+ LanguageCode,
154
+ {
155
+ totalPatterns: number;
156
+ failures: number;
157
+ commonErrors: string[];
158
+ problematicPatterns: string[];
159
+ }
160
+ > {
161
+ const byLanguage: Record<string, any> = {};
162
+
163
+ for (const result of results) {
164
+ const lang = result.pattern.language;
165
+
166
+ if (!byLanguage[lang]) {
167
+ byLanguage[lang] = {
168
+ totalPatterns: 0,
169
+ failures: 0,
170
+ commonErrors: [] as string[],
171
+ problematicPatterns: [] as string[],
172
+ };
173
+ }
174
+
175
+ byLanguage[lang].totalPatterns++;
176
+
177
+ if (!result.success) {
178
+ byLanguage[lang].failures++;
179
+
180
+ const error = result.error || 'Unknown';
181
+ if (!byLanguage[lang].commonErrors.includes(error)) {
182
+ byLanguage[lang].commonErrors.push(error);
183
+ }
184
+
185
+ if (byLanguage[lang].problematicPatterns.length < 10) {
186
+ byLanguage[lang].problematicPatterns.push(result.pattern.hyperscript);
187
+ }
188
+ }
189
+ }
190
+
191
+ return byLanguage as Record<LanguageCode, any>;
192
+ }
193
+
194
+ /**
195
+ * Identify patterns in failed hyperscript
196
+ */
197
+ identifyFailurePatterns(failures: ParseResult[]): {
198
+ multiClause: number;
199
+ eventModifiers: number;
200
+ styleProperties: number;
201
+ conditionals: number;
202
+ windowEvents: number;
203
+ complexSelectors: number;
204
+ } {
205
+ const patterns = {
206
+ multiClause: 0,
207
+ eventModifiers: 0,
208
+ styleProperties: 0,
209
+ conditionals: 0,
210
+ windowEvents: 0,
211
+ complexSelectors: 0,
212
+ };
213
+
214
+ for (const failure of failures) {
215
+ const code = failure.pattern.hyperscript;
216
+
217
+ // Multi-clause (それから, ثم, then)
218
+ if (
219
+ code.includes('それから') ||
220
+ code.includes('ثم') ||
221
+ code.includes('then') ||
222
+ code.includes('그러면') ||
223
+ code.includes('그리고')
224
+ ) {
225
+ patterns.multiClause++;
226
+ }
227
+
228
+ // Event modifiers
229
+ if (code.includes('[') || code.includes('debounced') || code.includes('throttled')) {
230
+ patterns.eventModifiers++;
231
+ }
232
+
233
+ // Style properties (*background, *opacity, etc.)
234
+ if (code.includes('*')) {
235
+ patterns.styleProperties++;
236
+ }
237
+
238
+ // Conditionals (if, もし, إذا, etc.)
239
+ if (
240
+ code.includes('if ') ||
241
+ code.includes('もし') ||
242
+ code.includes('إذا') ||
243
+ code.includes('一致する') ||
244
+ code.includes('match')
245
+ ) {
246
+ patterns.conditionals++;
247
+ }
248
+
249
+ // Window events
250
+ if (
251
+ code.includes('ウィンドウ') ||
252
+ code.includes('window') ||
253
+ code.includes('النافذة') ||
254
+ code.includes('창')
255
+ ) {
256
+ patterns.windowEvents++;
257
+ }
258
+
259
+ // Complex selectors
260
+ if (
261
+ code.includes('closest') ||
262
+ code.includes('最も近い') ||
263
+ code.includes('<') ||
264
+ code.includes('first') ||
265
+ code.includes('最初')
266
+ ) {
267
+ patterns.complexSelectors++;
268
+ }
269
+ }
270
+
271
+ return patterns;
272
+ }
273
+
274
+ /**
275
+ * Generate diagnostic report
276
+ */
277
+ generateReport(results: ParseResult[]): string {
278
+ const failures = results.filter(r => !r.success);
279
+ const failurePatterns = this.analyzeFailures(results);
280
+ const byLanguage = this.analyzeByLanguage(results);
281
+ const codePatterns = this.identifyFailurePatterns(failures);
282
+
283
+ let report = '# Parse Failure Analysis Report\n\n';
284
+
285
+ report += `## Summary\n`;
286
+ report += `- Total patterns: ${results.length}\n`;
287
+ report += `- Failures: ${failures.length} (${((failures.length / results.length) * 100).toFixed(1)}%)\n`;
288
+ report += `- Success rate: ${(((results.length - failures.length) / results.length) * 100).toFixed(1)}%\n\n`;
289
+
290
+ report += `## Common Failure Types\n\n`;
291
+ for (const pattern of failurePatterns.slice(0, 5)) {
292
+ report += `### ${pattern.type} (${pattern.count} occurrences)\n`;
293
+ report += `- Affected languages: ${pattern.affectedLanguages.join(', ')}\n`;
294
+ report += `- Examples:\n`;
295
+ pattern.examples.forEach(ex => {
296
+ report += ` - "${ex}"\n`;
297
+ });
298
+ report += '\n';
299
+ }
300
+
301
+ report += `## Failure Patterns in Code\n\n`;
302
+ report += `- Multi-clause patterns: ${codePatterns.multiClause}\n`;
303
+ report += `- Event modifiers: ${codePatterns.eventModifiers}\n`;
304
+ report += `- Style properties: ${codePatterns.styleProperties}\n`;
305
+ report += `- Conditionals: ${codePatterns.conditionals}\n`;
306
+ report += `- Window events: ${codePatterns.windowEvents}\n`;
307
+ report += `- Complex selectors: ${codePatterns.complexSelectors}\n\n`;
308
+
309
+ report += `## By Language\n\n`;
310
+ const sortedLangs = Object.entries(byLanguage).sort(([, a], [, b]) => b.failures - a.failures);
311
+
312
+ for (const [lang, data] of sortedLangs.slice(0, 10)) {
313
+ const failRate = ((data.failures / data.totalPatterns) * 100).toFixed(1);
314
+ report += `### ${lang.toUpperCase()} - ${data.failures}/${data.totalPatterns} failures (${failRate}%)\n`;
315
+ report += `Common errors:\n`;
316
+ data.commonErrors.slice(0, 3).forEach((err: string) => {
317
+ report += `- ${err}\n`;
318
+ });
319
+ report += '\n';
320
+ }
321
+
322
+ return report;
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Create a diagnostic session
328
+ */
329
+ export function createDiagnosticSession(enabled: boolean = true): {
330
+ diagnostics: ParseDiagnostics;
331
+ analyzer: FailureAnalyzer;
332
+ } {
333
+ return {
334
+ diagnostics: new ParseDiagnostics(enabled),
335
+ analyzer: new FailureAnalyzer(),
336
+ };
337
+ }