@hyperfixi/patterns-reference 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.
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Pattern Roles API
3
+ *
4
+ * Provides functions to query semantic roles extracted from patterns.
5
+ */
6
+
7
+ import { getDatabase } from '../database/connection';
8
+ import type {
9
+ PatternRole,
10
+ SemanticRole,
11
+ RoleType,
12
+ ConnectionOptions,
13
+ Pattern,
14
+ EngineCompat,
15
+ } from '../types';
16
+
17
+ // =============================================================================
18
+ // Database Row Types
19
+ // =============================================================================
20
+
21
+ interface PatternRoleRow {
22
+ id: number;
23
+ code_example_id: string;
24
+ command_index: number;
25
+ role: string;
26
+ role_value: string | null;
27
+ role_type: string | null;
28
+ required: number;
29
+ }
30
+
31
+ interface CodeExampleRow {
32
+ id: string;
33
+ title: string;
34
+ raw_code: string;
35
+ description: string | null;
36
+ feature: string | null;
37
+ engine: string | null;
38
+ created_at: string;
39
+ }
40
+
41
+ // =============================================================================
42
+ // Role Queries
43
+ // =============================================================================
44
+
45
+ /**
46
+ * Get all semantic roles for a pattern.
47
+ */
48
+ export async function getPatternRoles(
49
+ patternId: string,
50
+ options?: ConnectionOptions
51
+ ): Promise<PatternRole[]> {
52
+ const db = getDatabase({ ...options, readonly: true });
53
+ const rows = db
54
+ .prepare(
55
+ `
56
+ SELECT id, code_example_id, command_index, role, role_value, role_type, required
57
+ FROM pattern_roles
58
+ WHERE code_example_id = ?
59
+ ORDER BY command_index, role
60
+ `
61
+ )
62
+ .all(patternId) as PatternRoleRow[];
63
+
64
+ return rows.map(mapRowToPatternRole);
65
+ }
66
+
67
+ /**
68
+ * Get all patterns that contain a specific semantic role.
69
+ */
70
+ export async function getPatternsByRole(
71
+ role: SemanticRole,
72
+ options?: ConnectionOptions
73
+ ): Promise<Pattern[]> {
74
+ const db = getDatabase({ ...options, readonly: true });
75
+ const rows = db
76
+ .prepare(
77
+ `
78
+ SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
79
+ FROM code_examples ce
80
+ INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
81
+ WHERE pr.role = ?
82
+ ORDER BY ce.title
83
+ `
84
+ )
85
+ .all(role) as CodeExampleRow[];
86
+
87
+ return rows.map(mapRowToPattern);
88
+ }
89
+
90
+ /**
91
+ * Get patterns that contain all specified roles.
92
+ */
93
+ export async function getPatternsByRoles(
94
+ roles: SemanticRole[],
95
+ matchMode: 'all' | 'any' = 'any',
96
+ options?: ConnectionOptions
97
+ ): Promise<Pattern[]> {
98
+ if (roles.length === 0) return [];
99
+
100
+ const db = getDatabase({ ...options, readonly: true });
101
+
102
+ if (matchMode === 'any') {
103
+ // Match patterns with ANY of the specified roles
104
+ const placeholders = roles.map(() => '?').join(', ');
105
+ const rows = db
106
+ .prepare(
107
+ `
108
+ SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
109
+ FROM code_examples ce
110
+ INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
111
+ WHERE pr.role IN (${placeholders})
112
+ ORDER BY ce.title
113
+ `
114
+ )
115
+ .all(...roles) as CodeExampleRow[];
116
+
117
+ return rows.map(mapRowToPattern);
118
+ } else {
119
+ // Match patterns with ALL of the specified roles
120
+ const placeholders = roles.map(() => '?').join(', ');
121
+ const rows = db
122
+ .prepare(
123
+ `
124
+ SELECT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
125
+ FROM code_examples ce
126
+ WHERE (
127
+ SELECT COUNT(DISTINCT pr.role)
128
+ FROM pattern_roles pr
129
+ WHERE pr.code_example_id = ce.id AND pr.role IN (${placeholders})
130
+ ) = ?
131
+ ORDER BY ce.title
132
+ `
133
+ )
134
+ .all(...roles, roles.length) as CodeExampleRow[];
135
+
136
+ return rows.map(mapRowToPattern);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Get patterns by role value (e.g., all patterns that target ".active").
142
+ */
143
+ export async function getPatternsByRoleValue(
144
+ role: SemanticRole,
145
+ value: string,
146
+ options?: ConnectionOptions
147
+ ): Promise<Pattern[]> {
148
+ const db = getDatabase({ ...options, readonly: true });
149
+ const rows = db
150
+ .prepare(
151
+ `
152
+ SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
153
+ FROM code_examples ce
154
+ INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
155
+ WHERE pr.role = ? AND pr.role_value LIKE ?
156
+ ORDER BY ce.title
157
+ `
158
+ )
159
+ .all(role, `%${value}%`) as CodeExampleRow[];
160
+
161
+ return rows.map(mapRowToPattern);
162
+ }
163
+
164
+ // =============================================================================
165
+ // Role Statistics
166
+ // =============================================================================
167
+
168
+ /**
169
+ * Get statistics about role usage across all patterns.
170
+ */
171
+ export async function getRoleStats(options?: ConnectionOptions): Promise<{
172
+ totalRoles: number;
173
+ byRole: Record<SemanticRole, number>;
174
+ byRoleType: Record<RoleType, number>;
175
+ topRoleValues: Array<{ role: SemanticRole; value: string; count: number }>;
176
+ patternsWithRoles: number;
177
+ patternsWithoutRoles: number;
178
+ }> {
179
+ const db = getDatabase({ ...options, readonly: true });
180
+
181
+ // Total roles
182
+ const totalRow = db.prepare('SELECT COUNT(*) as count FROM pattern_roles').get() as {
183
+ count: number;
184
+ };
185
+
186
+ // Count by role
187
+ const roleRows = db
188
+ .prepare(
189
+ `
190
+ SELECT role, COUNT(*) as count
191
+ FROM pattern_roles
192
+ GROUP BY role
193
+ ORDER BY count DESC
194
+ `
195
+ )
196
+ .all() as { role: string; count: number }[];
197
+
198
+ const byRole: Record<string, number> = {};
199
+ for (const row of roleRows) {
200
+ byRole[row.role] = row.count;
201
+ }
202
+
203
+ // Count by role type
204
+ const typeRows = db
205
+ .prepare(
206
+ `
207
+ SELECT role_type, COUNT(*) as count
208
+ FROM pattern_roles
209
+ WHERE role_type IS NOT NULL
210
+ GROUP BY role_type
211
+ `
212
+ )
213
+ .all() as { role_type: string; count: number }[];
214
+
215
+ const byRoleType: Record<string, number> = {};
216
+ for (const row of typeRows) {
217
+ byRoleType[row.role_type] = row.count;
218
+ }
219
+
220
+ // Top role values
221
+ const valueRows = db
222
+ .prepare(
223
+ `
224
+ SELECT role, role_value, COUNT(*) as count
225
+ FROM pattern_roles
226
+ WHERE role_value IS NOT NULL
227
+ GROUP BY role, role_value
228
+ ORDER BY count DESC
229
+ LIMIT 20
230
+ `
231
+ )
232
+ .all() as { role: string; role_value: string; count: number }[];
233
+
234
+ const topRoleValues = valueRows.map(row => ({
235
+ role: row.role as SemanticRole,
236
+ value: row.role_value,
237
+ count: row.count,
238
+ }));
239
+
240
+ // Patterns with/without roles
241
+ const withRolesRow = db
242
+ .prepare(
243
+ `
244
+ SELECT COUNT(DISTINCT code_example_id) as count
245
+ FROM pattern_roles
246
+ `
247
+ )
248
+ .get() as { count: number };
249
+
250
+ const totalPatternsRow = db.prepare('SELECT COUNT(*) as count FROM code_examples').get() as {
251
+ count: number;
252
+ };
253
+
254
+ return {
255
+ totalRoles: totalRow.count,
256
+ byRole: byRole as Record<SemanticRole, number>,
257
+ byRoleType: byRoleType as Record<RoleType, number>,
258
+ topRoleValues,
259
+ patternsWithRoles: withRolesRow.count,
260
+ patternsWithoutRoles: totalPatternsRow.count - withRolesRow.count,
261
+ };
262
+ }
263
+
264
+ /**
265
+ * Get role distribution for a specific command.
266
+ */
267
+ export async function getRolesByCommand(
268
+ command: string,
269
+ options?: ConnectionOptions
270
+ ): Promise<Record<SemanticRole, number>> {
271
+ const db = getDatabase({ ...options, readonly: true });
272
+
273
+ const rows = db
274
+ .prepare(
275
+ `
276
+ SELECT pr.role, COUNT(*) as count
277
+ FROM pattern_roles pr
278
+ INNER JOIN code_examples ce ON pr.code_example_id = ce.id
279
+ WHERE ce.raw_code LIKE ?
280
+ GROUP BY pr.role
281
+ `
282
+ )
283
+ .all(`%${command}%`) as { role: string; count: number }[];
284
+
285
+ const result: Record<string, number> = {};
286
+ for (const row of rows) {
287
+ result[row.role] = row.count;
288
+ }
289
+ return result as Record<SemanticRole, number>;
290
+ }
291
+
292
+ // =============================================================================
293
+ // Role Write Operations
294
+ // =============================================================================
295
+
296
+ /**
297
+ * Insert a pattern role into the database.
298
+ */
299
+ export async function insertPatternRole(
300
+ role: Omit<PatternRole, 'id'>,
301
+ options?: ConnectionOptions
302
+ ): Promise<number> {
303
+ const db = getDatabase(options);
304
+ const result = db
305
+ .prepare(
306
+ `
307
+ INSERT INTO pattern_roles (code_example_id, command_index, role, role_value, role_type, required)
308
+ VALUES (?, ?, ?, ?, ?, ?)
309
+ `
310
+ )
311
+ .run(
312
+ role.codeExampleId,
313
+ role.commandIndex,
314
+ role.role,
315
+ role.roleValue,
316
+ role.roleType,
317
+ role.required ? 1 : 0
318
+ );
319
+
320
+ return result.lastInsertRowid as number;
321
+ }
322
+
323
+ /**
324
+ * Delete all roles for a pattern.
325
+ */
326
+ export async function deletePatternRoles(
327
+ patternId: string,
328
+ options?: ConnectionOptions
329
+ ): Promise<number> {
330
+ const db = getDatabase(options);
331
+ const result = db.prepare('DELETE FROM pattern_roles WHERE code_example_id = ?').run(patternId);
332
+ return result.changes;
333
+ }
334
+
335
+ /**
336
+ * Delete all roles from the database.
337
+ */
338
+ export async function clearAllRoles(options?: ConnectionOptions): Promise<number> {
339
+ const db = getDatabase(options);
340
+ const result = db.prepare('DELETE FROM pattern_roles').run();
341
+ return result.changes;
342
+ }
343
+
344
+ // =============================================================================
345
+ // Helper Functions
346
+ // =============================================================================
347
+
348
+ /**
349
+ * Map database row to PatternRole type.
350
+ */
351
+ function mapRowToPatternRole(row: PatternRoleRow): PatternRole {
352
+ return {
353
+ id: row.id,
354
+ codeExampleId: row.code_example_id,
355
+ commandIndex: row.command_index,
356
+ role: row.role as SemanticRole,
357
+ roleValue: row.role_value,
358
+ roleType: row.role_type as RoleType | null,
359
+ required: Boolean(row.required),
360
+ };
361
+ }
362
+
363
+ /**
364
+ * Map database row to Pattern type.
365
+ */
366
+ function mapRowToPattern(row: CodeExampleRow): Pattern {
367
+ return {
368
+ id: row.id,
369
+ title: row.title,
370
+ description: row.description,
371
+ rawCode: row.raw_code,
372
+ category: row.feature,
373
+ primaryCommand: extractPrimaryCommand(row.raw_code),
374
+ tags: extractTags(row.raw_code),
375
+ difficulty: inferDifficulty(row.raw_code),
376
+ engine: (row.engine as EngineCompat) || null,
377
+ createdAt: new Date(row.created_at),
378
+ };
379
+ }
380
+
381
+ function extractPrimaryCommand(code: string): string | null {
382
+ const match = code.match(/^(on|toggle|put|set|add|remove|show|hide|wait|log|send|fetch|call)\b/i);
383
+ return match ? match[1].toLowerCase() : null;
384
+ }
385
+
386
+ function extractTags(code: string): string[] {
387
+ const tags: string[] = [];
388
+ if (code.includes('.')) tags.push('class');
389
+ if (code.includes('#')) tags.push('id');
390
+ if (code.includes('on ')) tags.push('event');
391
+ if (code.includes('fetch')) tags.push('async');
392
+ if (code.includes('wait')) tags.push('timing');
393
+ return tags;
394
+ }
395
+
396
+ function inferDifficulty(code: string): 'beginner' | 'intermediate' | 'advanced' {
397
+ const lines = code.split('\n').filter(l => l.trim()).length;
398
+ if (lines === 1 && !code.includes('then')) return 'beginner';
399
+ if (lines <= 3) return 'intermediate';
400
+ return 'advanced';
401
+ }
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Translation Operations API
3
+ *
4
+ * Provides functions to query and manage translations.
5
+ */
6
+
7
+ import { getDatabase } from '../database/connection';
8
+ import type {
9
+ Translation,
10
+ VerificationResult,
11
+ WordOrder,
12
+ TranslationMethod,
13
+ ConnectionOptions,
14
+ } from '../types';
15
+
16
+ // =============================================================================
17
+ // Database Row Types
18
+ // =============================================================================
19
+
20
+ interface PatternTranslationRow {
21
+ id: number;
22
+ code_example_id: string;
23
+ language: string;
24
+ hyperscript: string;
25
+ word_order: string;
26
+ translation_method: string;
27
+ confidence: number;
28
+ verified_parses: number;
29
+ verified_executes: number;
30
+ role_alignment_score: number | null;
31
+ created_at: string;
32
+ updated_at: string;
33
+ }
34
+
35
+ // =============================================================================
36
+ // Query Functions
37
+ // =============================================================================
38
+
39
+ /**
40
+ * Get a translation for a pattern in a specific language.
41
+ */
42
+ export async function getTranslation(
43
+ patternId: string,
44
+ language: string,
45
+ options?: ConnectionOptions
46
+ ): Promise<Translation | null> {
47
+ const db = getDatabase({ ...options, readonly: true });
48
+ const row = db
49
+ .prepare(
50
+ `
51
+ SELECT * FROM pattern_translations
52
+ WHERE code_example_id = ? AND language = ?
53
+ `
54
+ )
55
+ .get(patternId, language) as PatternTranslationRow | undefined;
56
+
57
+ return row ? mapRowToTranslation(row) : null;
58
+ }
59
+
60
+ /**
61
+ * Get all translations for a pattern.
62
+ */
63
+ export async function getAllTranslations(
64
+ patternId: string,
65
+ options?: ConnectionOptions
66
+ ): Promise<Translation[]> {
67
+ const db = getDatabase({ ...options, readonly: true });
68
+ const rows = db
69
+ .prepare(
70
+ `
71
+ SELECT * FROM pattern_translations
72
+ WHERE code_example_id = ?
73
+ ORDER BY language
74
+ `
75
+ )
76
+ .all(patternId) as PatternTranslationRow[];
77
+
78
+ return rows.map(mapRowToTranslation);
79
+ }
80
+
81
+ /**
82
+ * Get translations by language.
83
+ */
84
+ export async function getTranslationsByLanguage(
85
+ language: string,
86
+ limit: number = 100,
87
+ options?: ConnectionOptions
88
+ ): Promise<Translation[]> {
89
+ const db = getDatabase({ ...options, readonly: true });
90
+ const rows = db
91
+ .prepare(
92
+ `
93
+ SELECT * FROM pattern_translations
94
+ WHERE language = ?
95
+ ORDER BY confidence DESC
96
+ LIMIT ?
97
+ `
98
+ )
99
+ .all(language, limit) as PatternTranslationRow[];
100
+
101
+ return rows.map(mapRowToTranslation);
102
+ }
103
+
104
+ /**
105
+ * Get verified translations (successfully parsed).
106
+ */
107
+ export async function getVerifiedTranslations(
108
+ language: string,
109
+ limit: number = 100,
110
+ options?: ConnectionOptions
111
+ ): Promise<Translation[]> {
112
+ const db = getDatabase({ ...options, readonly: true });
113
+ const rows = db
114
+ .prepare(
115
+ `
116
+ SELECT * FROM pattern_translations
117
+ WHERE language = ? AND verified_parses = 1
118
+ ORDER BY confidence DESC
119
+ LIMIT ?
120
+ `
121
+ )
122
+ .all(language, limit) as PatternTranslationRow[];
123
+
124
+ return rows.map(mapRowToTranslation);
125
+ }
126
+
127
+ /**
128
+ * Get high-confidence translations.
129
+ */
130
+ export async function getHighConfidenceTranslations(
131
+ minConfidence: number = 0.8,
132
+ limit: number = 100,
133
+ options?: ConnectionOptions
134
+ ): Promise<Translation[]> {
135
+ const db = getDatabase({ ...options, readonly: true });
136
+ const rows = db
137
+ .prepare(
138
+ `
139
+ SELECT * FROM pattern_translations
140
+ WHERE confidence >= ? AND verified_parses = 1
141
+ ORDER BY confidence DESC
142
+ LIMIT ?
143
+ `
144
+ )
145
+ .all(minConfidence, limit) as PatternTranslationRow[];
146
+
147
+ return rows.map(mapRowToTranslation);
148
+ }
149
+
150
+ /**
151
+ * Verify a translation parses correctly.
152
+ * Note: This requires @lokascript/semantic to be available.
153
+ */
154
+ export async function verifyTranslation(
155
+ translation: Translation,
156
+ options?: ConnectionOptions
157
+ ): Promise<VerificationResult> {
158
+ let parseSuccess = false;
159
+ let errorMessage: string | null = null;
160
+ let confidence = translation.confidence;
161
+
162
+ try {
163
+ // Dynamic import to avoid bundling issues
164
+ const { canParse, parse } = await import('@lokascript/semantic');
165
+
166
+ if (canParse(translation.hyperscript, translation.language)) {
167
+ parse(translation.hyperscript, translation.language);
168
+ parseSuccess = true;
169
+ } else {
170
+ errorMessage = 'canParse returned false';
171
+ }
172
+ } catch (e) {
173
+ errorMessage = (e as Error).message;
174
+ }
175
+
176
+ // Update database
177
+ const db = getDatabase(options);
178
+ db.prepare(
179
+ `
180
+ UPDATE pattern_translations
181
+ SET verified_parses = ?, updated_at = datetime('now')
182
+ WHERE id = ?
183
+ `
184
+ ).run(parseSuccess ? 1 : 0, translation.id);
185
+
186
+ // Record test result
187
+ db.prepare(
188
+ `
189
+ INSERT INTO pattern_tests
190
+ (code_example_id, language, test_date, parse_success, error_message)
191
+ VALUES (?, ?, datetime('now'), ?, ?)
192
+ `
193
+ ).run(translation.codeExampleId, translation.language, parseSuccess ? 1 : 0, errorMessage);
194
+
195
+ return {
196
+ translation,
197
+ parseSuccess,
198
+ executeSuccess: false, // Not implemented yet
199
+ errorMessage,
200
+ confidence,
201
+ testedAt: new Date(),
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Get translation statistics by language.
207
+ */
208
+ export async function getTranslationStats(
209
+ options?: ConnectionOptions
210
+ ): Promise<Record<string, { total: number; verified: number; avgConfidence: number }>> {
211
+ const db = getDatabase({ ...options, readonly: true });
212
+
213
+ const rows = db
214
+ .prepare(
215
+ `
216
+ SELECT
217
+ language,
218
+ COUNT(*) as total,
219
+ SUM(verified_parses) as verified,
220
+ AVG(confidence) as avg_confidence
221
+ FROM pattern_translations
222
+ GROUP BY language
223
+ `
224
+ )
225
+ .all() as { language: string; total: number; verified: number; avg_confidence: number }[];
226
+
227
+ const stats: Record<string, { total: number; verified: number; avgConfidence: number }> = {};
228
+ for (const row of rows) {
229
+ stats[row.language] = {
230
+ total: row.total,
231
+ verified: row.verified,
232
+ avgConfidence: row.avg_confidence || 0,
233
+ };
234
+ }
235
+
236
+ return stats;
237
+ }
238
+
239
+ // =============================================================================
240
+ // Helper Functions
241
+ // =============================================================================
242
+
243
+ /**
244
+ * Map database row to Translation type.
245
+ */
246
+ function mapRowToTranslation(row: PatternTranslationRow): Translation {
247
+ return {
248
+ id: row.id,
249
+ codeExampleId: row.code_example_id,
250
+ language: row.language,
251
+ hyperscript: row.hyperscript,
252
+ wordOrder: row.word_order as WordOrder,
253
+ translationMethod: row.translation_method as TranslationMethod,
254
+ confidence: row.confidence,
255
+ verifiedParses: row.verified_parses === 1,
256
+ verifiedExecutes: row.verified_executes === 1,
257
+ roleAlignmentScore: row.role_alignment_score ?? null,
258
+ createdAt: new Date(row.created_at),
259
+ updatedAt: new Date(row.updated_at),
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Get word order for a language.
265
+ */
266
+ export function getWordOrder(language: string): WordOrder {
267
+ const wordOrders: Record<string, WordOrder> = {
268
+ en: 'SVO',
269
+ es: 'SVO',
270
+ fr: 'SVO',
271
+ pt: 'SVO',
272
+ id: 'SVO',
273
+ sw: 'SVO',
274
+ zh: 'SVO',
275
+ ja: 'SOV',
276
+ ko: 'SOV',
277
+ tr: 'SOV',
278
+ qu: 'SOV',
279
+ ar: 'VSO',
280
+ de: 'V2',
281
+ };
282
+ return wordOrders[language] || 'SVO';
283
+ }