@hyperfixi/patterns-reference 3.1.1 → 3.2.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.
- package/CHANGELOG.md +145 -0
- package/README.md +47 -36
- package/data/engine-verification.json +40 -38
- package/data/patterns.db +0 -0
- package/data/patterns.db.stamp +1 -0
- package/dist/api/index.d.mts +2 -2
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.js +198 -98
- package/dist/api/index.mjs +197 -100
- package/dist/{index-6GkHj5yJ.d.mts → index-CoDUfq2P.d.mts} +39 -3
- package/dist/{index-6GkHj5yJ.d.ts → index-CoDUfq2P.d.ts} +39 -3
- package/dist/index.d.mts +87 -13
- package/dist/index.d.ts +87 -13
- package/dist/index.js +261 -144
- package/dist/index.mjs +258 -146
- package/dist/{llm-B5nGz8V1.d.mts → llm-CCCSw-yp.d.ts} +21 -10
- package/dist/{llm-rEdJQScF.d.ts → llm-PxnriEZ_.d.mts} +21 -10
- package/dist/sync/index.d.mts +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.js +4 -1
- package/dist/sync/index.mjs +4 -1
- package/package.json +16 -16
- package/src/adapters/llm-adapter.ts +64 -42
- package/src/api/engine-filter.ts +37 -0
- package/src/api/llm.ts +54 -64
- package/src/api/patterns.ts +92 -30
- package/src/api/roles.ts +6 -4
- package/src/api/translations.ts +34 -27
- package/src/database/connection.ts +16 -4
- package/src/html-snippets.ts +39 -10
- package/src/index.ts +12 -2
- package/src/registry/patterns-provider.ts +3 -1
- package/src/sync/db-stamp.ts +7 -4
- package/src/sync/markup-attributes.ts +15 -0
- package/src/sync/verify-parses.ts +42 -0
- package/src/types/better-sqlite3.d.ts +2 -0
- package/src/types/index.ts +44 -2
- package/src/sync/span-mask.ts +0 -166
- package/src/sync/translation-checks.ts +0 -282
package/dist/api/index.mjs
CHANGED
|
@@ -1,9 +1,85 @@
|
|
|
1
|
+
import { dirname, join } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { canParse } from '@lokascript/semantic';
|
|
1
4
|
import Database from 'better-sqlite3';
|
|
2
5
|
import { statSync } from 'fs';
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var init_esm_shims = __esm({
|
|
17
|
+
"../../node_modules/tsup/assets/esm_shims.js"() {
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// src/sync/markup-attributes.ts
|
|
22
|
+
function findHyperscriptAttributes(markup) {
|
|
23
|
+
const spans = [];
|
|
24
|
+
ATTRIBUTE.lastIndex = 0;
|
|
25
|
+
let match;
|
|
26
|
+
while ((match = ATTRIBUTE.exec(markup)) !== null) {
|
|
27
|
+
const body = match[2] ?? match[3];
|
|
28
|
+
const start = match.index + match[0].length - body.length - 1;
|
|
29
|
+
spans.push({ start, end: start + body.length, body });
|
|
30
|
+
}
|
|
31
|
+
return spans;
|
|
32
|
+
}
|
|
33
|
+
function isMarkupRow(code) {
|
|
34
|
+
return /^\s*<[a-zA-Z!]/.test(code);
|
|
35
|
+
}
|
|
36
|
+
function hyperscriptBodies(code) {
|
|
37
|
+
if (!isMarkupRow(code)) return [code];
|
|
38
|
+
const bodies = findHyperscriptAttributes(code).map((span) => span.body);
|
|
39
|
+
for (const match of code.matchAll(HX_LIVE_ATTRIBUTE)) bodies.push(match[2] ?? match[3] ?? "");
|
|
40
|
+
return bodies.filter((body) => body.trim().length > 0);
|
|
41
|
+
}
|
|
42
|
+
var ATTRIBUTE, HX_LIVE_ATTRIBUTE;
|
|
43
|
+
var init_markup_attributes = __esm({
|
|
44
|
+
"src/sync/markup-attributes.ts"() {
|
|
45
|
+
init_esm_shims();
|
|
46
|
+
ATTRIBUTE = /(^|[\s"'])_\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
47
|
+
HX_LIVE_ATTRIBUTE = /(^|[\s"'])hx-live\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// src/sync/verify-parses.ts
|
|
52
|
+
var verify_parses_exports = {};
|
|
53
|
+
__export(verify_parses_exports, {
|
|
54
|
+
verifyParses: () => verifyParses
|
|
55
|
+
});
|
|
56
|
+
function verifyParses(code, language, translatable = true) {
|
|
57
|
+
const bodies = hyperscriptBodies(code);
|
|
58
|
+
if (bodies.length === 0) return false;
|
|
59
|
+
const parseLanguage = translatable ? language : "en";
|
|
60
|
+
return bodies.every((body) => {
|
|
61
|
+
try {
|
|
62
|
+
return canParse(body, parseLanguage);
|
|
63
|
+
} catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
var init_verify_parses = __esm({
|
|
69
|
+
"src/sync/verify-parses.ts"() {
|
|
70
|
+
init_esm_shims();
|
|
71
|
+
init_markup_attributes();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// src/api/index.ts
|
|
76
|
+
init_esm_shims();
|
|
77
|
+
|
|
78
|
+
// src/api/patterns.ts
|
|
79
|
+
init_esm_shims();
|
|
5
80
|
|
|
6
81
|
// src/database/connection.ts
|
|
82
|
+
init_esm_shims();
|
|
7
83
|
var __filename$1 = fileURLToPath(import.meta.url);
|
|
8
84
|
var __dirname$1 = dirname(__filename$1);
|
|
9
85
|
var DEFAULT_DB_PATH = process.env.LSP_DB_PATH || process.env.HYPERSCRIPT_LSP_DB || join(__dirname$1, "../data/patterns.db");
|
|
@@ -11,10 +87,11 @@ var dbInstance = null;
|
|
|
11
87
|
var currentDbPath = null;
|
|
12
88
|
var openFileId = null;
|
|
13
89
|
var lastIdentityCheckAt = 0;
|
|
90
|
+
var openReadonly = false;
|
|
14
91
|
var IDENTITY_TTL_MS = 1e3;
|
|
15
|
-
function fileIdentity(
|
|
92
|
+
function fileIdentity(path2) {
|
|
16
93
|
try {
|
|
17
|
-
const s = statSync(
|
|
94
|
+
const s = statSync(path2);
|
|
18
95
|
return `${s.dev}:${s.ino}:${s.size}:${s.mtimeMs}`;
|
|
19
96
|
} catch {
|
|
20
97
|
return null;
|
|
@@ -22,7 +99,9 @@ function fileIdentity(path) {
|
|
|
22
99
|
}
|
|
23
100
|
function getDatabase(options = {}) {
|
|
24
101
|
const dbPath = options.dbPath ?? DEFAULT_DB_PATH;
|
|
25
|
-
|
|
102
|
+
const readonly = options.readonly ?? false;
|
|
103
|
+
const canServe = !openReadonly || readonly;
|
|
104
|
+
if (dbInstance !== null && currentDbPath === dbPath && canServe) {
|
|
26
105
|
const now = Date.now();
|
|
27
106
|
if (now - lastIdentityCheckAt < IDENTITY_TTL_MS) {
|
|
28
107
|
return dbInstance;
|
|
@@ -38,9 +117,8 @@ function getDatabase(options = {}) {
|
|
|
38
117
|
if (dbInstance !== null) {
|
|
39
118
|
dbInstance.close();
|
|
40
119
|
}
|
|
41
|
-
dbInstance = new Database(dbPath, {
|
|
42
|
-
|
|
43
|
-
});
|
|
120
|
+
dbInstance = new Database(dbPath, { readonly });
|
|
121
|
+
openReadonly = readonly;
|
|
44
122
|
dbInstance.pragma("foreign_keys = ON");
|
|
45
123
|
currentDbPath = dbPath;
|
|
46
124
|
openFileId = fileIdentity(dbPath);
|
|
@@ -48,12 +126,26 @@ function getDatabase(options = {}) {
|
|
|
48
126
|
return dbInstance;
|
|
49
127
|
}
|
|
50
128
|
|
|
129
|
+
// src/api/patterns.ts
|
|
130
|
+
init_markup_attributes();
|
|
131
|
+
|
|
132
|
+
// src/api/engine-filter.ts
|
|
133
|
+
init_esm_shims();
|
|
134
|
+
function runsOn(column, engine) {
|
|
135
|
+
if (engine === null) return { sql: `${column} IS NULL`, params: [] };
|
|
136
|
+
if (engine === "both") return { sql: `${column} = 'both'`, params: [] };
|
|
137
|
+
return { sql: `${column} IN ('both', ?)`, params: [engine] };
|
|
138
|
+
}
|
|
139
|
+
function exampleCondition(column, engine) {
|
|
140
|
+
return engine === void 0 ? { sql: `${column} IS NOT NULL`, params: [] } : runsOn(column, engine);
|
|
141
|
+
}
|
|
142
|
+
|
|
51
143
|
// src/api/patterns.ts
|
|
52
144
|
async function getPatternById(id, options) {
|
|
53
145
|
const db = getDatabase({ ...options, readonly: true });
|
|
54
146
|
const row = db.prepare(
|
|
55
147
|
`
|
|
56
|
-
SELECT id, title, raw_code, description, feature, engine, created_at
|
|
148
|
+
SELECT id, title, raw_code, description, feature, engine, translatable, created_at
|
|
57
149
|
FROM code_examples
|
|
58
150
|
WHERE id = ?
|
|
59
151
|
`
|
|
@@ -64,7 +156,7 @@ async function getPatternsByCategory(category, options) {
|
|
|
64
156
|
const db = getDatabase({ ...options, readonly: true });
|
|
65
157
|
const rows = db.prepare(
|
|
66
158
|
`
|
|
67
|
-
SELECT id, title, raw_code, description, feature, engine, created_at
|
|
159
|
+
SELECT id, title, raw_code, description, feature, engine, translatable, created_at
|
|
68
160
|
FROM code_examples
|
|
69
161
|
WHERE feature = ?
|
|
70
162
|
ORDER BY title
|
|
@@ -76,7 +168,7 @@ async function getPatternsByCommand(command, options) {
|
|
|
76
168
|
const db = getDatabase({ ...options, readonly: true });
|
|
77
169
|
const rows = db.prepare(
|
|
78
170
|
`
|
|
79
|
-
SELECT id, title, raw_code, description, feature, engine, created_at
|
|
171
|
+
SELECT id, title, raw_code, description, feature, engine, translatable, created_at
|
|
80
172
|
FROM code_examples
|
|
81
173
|
WHERE raw_code LIKE ?
|
|
82
174
|
ORDER BY title
|
|
@@ -84,32 +176,45 @@ async function getPatternsByCommand(command, options) {
|
|
|
84
176
|
).all(`%${command}%`);
|
|
85
177
|
return rows.filter((row) => new RegExp(`\\b${command}\\b`, "i").test(row.raw_code)).map(mapRowToPattern);
|
|
86
178
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
179
|
+
function engineFilter(searchOptions) {
|
|
180
|
+
return searchOptions.engine === void 0 ? { sql: "1 = 1", params: [] } : runsOn("engine", searchOptions.engine);
|
|
181
|
+
}
|
|
182
|
+
function usableIn(db, language) {
|
|
90
183
|
const rows = db.prepare(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
ORDER BY title
|
|
96
|
-
LIMIT ? OFFSET ?
|
|
97
|
-
`
|
|
98
|
-
).all(`%${query}%`, `%${query}%`, `%${query}%`, limit, offset);
|
|
99
|
-
return rows.map(mapRowToPattern);
|
|
184
|
+
"SELECT code_example_id AS id FROM pattern_translations WHERE language = ? AND verified_parses = 1"
|
|
185
|
+
).all(language);
|
|
186
|
+
const verified = new Set(rows.map((row) => row.id));
|
|
187
|
+
return (pattern) => verified.has(pattern.id) || hyperscriptBodies(pattern.rawCode).length === 0;
|
|
100
188
|
}
|
|
101
|
-
|
|
189
|
+
function queryPatterns(searchOptions, defaultLimit, connOptions, match = { sql: "1 = 1", params: [] }) {
|
|
102
190
|
const db = getDatabase({ ...connOptions, readonly: true });
|
|
103
|
-
const { limit =
|
|
191
|
+
const { limit = defaultLimit, offset = 0, category, difficulty, language } = searchOptions;
|
|
192
|
+
const runs = engineFilter(searchOptions);
|
|
193
|
+
const inCategory = category === void 0 ? { sql: "1 = 1", params: [] } : { sql: "feature = ?", params: [category] };
|
|
104
194
|
const rows = db.prepare(
|
|
105
195
|
`
|
|
106
|
-
SELECT id, title, raw_code, description, feature, engine, created_at
|
|
196
|
+
SELECT id, title, raw_code, description, feature, engine, translatable, created_at
|
|
107
197
|
FROM code_examples
|
|
198
|
+
WHERE (${match.sql}) AND ${runs.sql} AND ${inCategory.sql}
|
|
108
199
|
ORDER BY title
|
|
109
|
-
LIMIT ? OFFSET ?
|
|
110
200
|
`
|
|
111
|
-
).all(
|
|
112
|
-
|
|
201
|
+
).all(...match.params, ...runs.params, ...inCategory.params);
|
|
202
|
+
const inLanguage = language === void 0 ? null : usableIn(db, language);
|
|
203
|
+
return rows.map(mapRowToPattern).filter((pattern) => difficulty === void 0 || pattern.difficulty === difficulty).filter((pattern) => inLanguage === null || inLanguage(pattern)).slice(offset, offset + limit);
|
|
204
|
+
}
|
|
205
|
+
async function searchPatterns(query, searchOptions = {}, connOptions) {
|
|
206
|
+
const like = `%${query}%`;
|
|
207
|
+
const inTranslation = searchOptions.language === void 0 ? { sql: "", params: [] } : {
|
|
208
|
+
sql: " OR id IN (SELECT code_example_id FROM pattern_translations WHERE language = ? AND hyperscript LIKE ?)",
|
|
209
|
+
params: [searchOptions.language, like]
|
|
210
|
+
};
|
|
211
|
+
return queryPatterns(searchOptions, 50, connOptions, {
|
|
212
|
+
sql: `title LIKE ? OR raw_code LIKE ? OR description LIKE ?${inTranslation.sql}`,
|
|
213
|
+
params: [like, like, like, ...inTranslation.params]
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
async function getAllPatterns(searchOptions = {}, connOptions) {
|
|
217
|
+
return queryPatterns(searchOptions, 1e3, connOptions);
|
|
113
218
|
}
|
|
114
219
|
async function getPatternStats(connOptions) {
|
|
115
220
|
const db = getDatabase({ ...connOptions, readonly: true });
|
|
@@ -164,6 +269,7 @@ function mapRowToPattern(row) {
|
|
|
164
269
|
tags: extractTags(row.raw_code),
|
|
165
270
|
difficulty: inferDifficulty(row.raw_code),
|
|
166
271
|
engine: row.engine || null,
|
|
272
|
+
translatable: row.translatable !== 0,
|
|
167
273
|
createdAt: new Date(row.created_at)
|
|
168
274
|
};
|
|
169
275
|
}
|
|
@@ -188,6 +294,7 @@ function inferDifficulty(code) {
|
|
|
188
294
|
}
|
|
189
295
|
|
|
190
296
|
// src/api/translations.ts
|
|
297
|
+
init_esm_shims();
|
|
191
298
|
async function getTranslation(patternId, language, options) {
|
|
192
299
|
const db = getDatabase({ ...options, readonly: true });
|
|
193
300
|
const row = db.prepare(
|
|
@@ -249,32 +356,35 @@ async function verifyTranslation(translation, options) {
|
|
|
249
356
|
let parseSuccess = false;
|
|
250
357
|
let errorMessage = null;
|
|
251
358
|
let confidence = translation.confidence;
|
|
359
|
+
const db = getDatabase(options);
|
|
360
|
+
const example = db.prepare("SELECT translatable FROM code_examples WHERE id = ?").get(translation.codeExampleId);
|
|
252
361
|
try {
|
|
253
|
-
const {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
362
|
+
const { verifyParses: verifyParses2 } = await Promise.resolve().then(() => (init_verify_parses(), verify_parses_exports));
|
|
363
|
+
parseSuccess = verifyParses2(
|
|
364
|
+
translation.hyperscript,
|
|
365
|
+
translation.language,
|
|
366
|
+
example?.translatable !== 0
|
|
367
|
+
);
|
|
368
|
+
if (!parseSuccess) errorMessage = "the semantic parser rejected it (or it has no hyperscript)";
|
|
260
369
|
} catch (e) {
|
|
261
370
|
errorMessage = e.message;
|
|
262
371
|
}
|
|
263
|
-
|
|
264
|
-
|
|
372
|
+
db.transaction(() => {
|
|
373
|
+
db.prepare(
|
|
374
|
+
`
|
|
375
|
+
UPDATE pattern_translations
|
|
376
|
+
SET verified_parses = ?, updated_at = datetime('now')
|
|
377
|
+
WHERE id = ?
|
|
265
378
|
`
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
379
|
+
).run(parseSuccess ? 1 : 0, translation.id);
|
|
380
|
+
db.prepare(
|
|
381
|
+
`
|
|
382
|
+
INSERT INTO pattern_tests
|
|
383
|
+
(code_example_id, language, test_type, success, error_message, test_date)
|
|
384
|
+
VALUES (?, ?, 'parse', ?, ?, datetime('now'))
|
|
272
385
|
`
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
VALUES (?, ?, datetime('now'), ?, ?)
|
|
276
|
-
`
|
|
277
|
-
).run(translation.codeExampleId, translation.language, parseSuccess ? 1 : 0, errorMessage);
|
|
386
|
+
).run(translation.codeExampleId, translation.language, parseSuccess ? 1 : 0, errorMessage);
|
|
387
|
+
})();
|
|
278
388
|
return {
|
|
279
389
|
translation,
|
|
280
390
|
parseSuccess,
|
|
@@ -344,74 +454,70 @@ function getWordOrder(language) {
|
|
|
344
454
|
}
|
|
345
455
|
|
|
346
456
|
// src/api/llm.ts
|
|
457
|
+
init_esm_shims();
|
|
458
|
+
var EXAMPLES_FROM = `
|
|
459
|
+
SELECT le.*, ce.engine AS engine
|
|
460
|
+
FROM llm_examples le
|
|
461
|
+
JOIN code_examples ce ON ce.id = le.code_example_id`;
|
|
347
462
|
async function getLLMExamples(prompt, language = "en", limit = 5, options) {
|
|
348
463
|
const db = getDatabase({ ...options, readonly: true });
|
|
464
|
+
const runs = exampleCondition("ce.engine", options?.engine);
|
|
349
465
|
const keywords = extractKeywords(prompt);
|
|
350
466
|
if (keywords.length === 0) {
|
|
351
467
|
const rows2 = db.prepare(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
ORDER BY quality_score DESC, usage_count DESC
|
|
468
|
+
`${EXAMPLES_FROM}
|
|
469
|
+
WHERE le.language = ? AND ${runs.sql}
|
|
470
|
+
ORDER BY le.quality_score DESC, le.usage_count DESC
|
|
356
471
|
LIMIT ?
|
|
357
472
|
`
|
|
358
|
-
).all(language, limit);
|
|
359
|
-
trackUsage(
|
|
360
|
-
db,
|
|
361
|
-
rows2.map((r) => r.id)
|
|
362
|
-
);
|
|
473
|
+
).all(language, ...runs.params, limit);
|
|
363
474
|
return rows2.map(mapRowToLLMExample);
|
|
364
475
|
}
|
|
365
|
-
const likeClauses = keywords.map(() => "(prompt LIKE ? OR completion LIKE ?)").join(" OR ");
|
|
476
|
+
const likeClauses = keywords.map(() => "(le.prompt LIKE ? OR le.completion LIKE ?)").join(" OR ");
|
|
366
477
|
const params = keywords.flatMap((k) => [`%${k}%`, `%${k}%`]);
|
|
367
478
|
const rows = db.prepare(
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
ORDER BY quality_score DESC
|
|
479
|
+
`${EXAMPLES_FROM}
|
|
480
|
+
WHERE le.language = ? AND ${runs.sql} AND (${likeClauses})
|
|
481
|
+
ORDER BY le.quality_score DESC
|
|
372
482
|
LIMIT ?
|
|
373
483
|
`
|
|
374
|
-
).all(language, ...params, limit);
|
|
375
|
-
trackUsage(
|
|
376
|
-
db,
|
|
377
|
-
rows.map((r) => r.id)
|
|
378
|
-
);
|
|
484
|
+
).all(language, ...runs.params, ...params, limit);
|
|
379
485
|
return rows.map(mapRowToLLMExample);
|
|
380
486
|
}
|
|
381
487
|
async function getExamplesByCommand(command, language = "en", limit = 5, options) {
|
|
382
488
|
const db = getDatabase({ ...options, readonly: true });
|
|
489
|
+
const runs = exampleCondition("ce.engine", options?.engine);
|
|
383
490
|
const rows = db.prepare(
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
ORDER BY quality_score DESC
|
|
491
|
+
`${EXAMPLES_FROM}
|
|
492
|
+
WHERE le.language = ? AND ${runs.sql} AND le.completion LIKE ?
|
|
493
|
+
ORDER BY le.quality_score DESC
|
|
388
494
|
LIMIT ?
|
|
389
495
|
`
|
|
390
|
-
).all(language, `%${command}%`, limit);
|
|
496
|
+
).all(language, ...runs.params, `%${command}%`, limit);
|
|
391
497
|
return rows.map(mapRowToLLMExample);
|
|
392
498
|
}
|
|
393
499
|
async function getHighQualityExamples(language = "en", minQuality = 0.8, limit = 10, options) {
|
|
394
500
|
const db = getDatabase({ ...options, readonly: true });
|
|
501
|
+
const runs = exampleCondition("ce.engine", options?.engine);
|
|
395
502
|
const rows = db.prepare(
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
ORDER BY quality_score DESC, usage_count DESC
|
|
503
|
+
`${EXAMPLES_FROM}
|
|
504
|
+
WHERE le.language = ? AND ${runs.sql} AND le.quality_score >= ?
|
|
505
|
+
ORDER BY le.quality_score DESC, le.usage_count DESC
|
|
400
506
|
LIMIT ?
|
|
401
507
|
`
|
|
402
|
-
).all(language, minQuality, limit);
|
|
508
|
+
).all(language, ...runs.params, minQuality, limit);
|
|
403
509
|
return rows.map(mapRowToLLMExample);
|
|
404
510
|
}
|
|
405
511
|
async function getMostUsedExamples(language = "en", limit = 10, options) {
|
|
406
512
|
const db = getDatabase({ ...options, readonly: true });
|
|
513
|
+
const runs = exampleCondition("ce.engine", options?.engine);
|
|
407
514
|
const rows = db.prepare(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
ORDER BY usage_count DESC, quality_score DESC
|
|
515
|
+
`${EXAMPLES_FROM}
|
|
516
|
+
WHERE le.language = ? AND ${runs.sql}
|
|
517
|
+
ORDER BY le.usage_count DESC, le.quality_score DESC
|
|
412
518
|
LIMIT ?
|
|
413
519
|
`
|
|
414
|
-
).all(language, limit);
|
|
520
|
+
).all(language, ...runs.params, limit);
|
|
415
521
|
return rows.map(mapRowToLLMExample);
|
|
416
522
|
}
|
|
417
523
|
async function buildFewShotContext(prompt, language = "en", numExamples = 3, options) {
|
|
@@ -509,18 +615,6 @@ function extractKeywords(prompt) {
|
|
|
509
615
|
]);
|
|
510
616
|
return prompt.toLowerCase().split(/\W+/).filter((word) => word.length > 2 && !stopWords.has(word));
|
|
511
617
|
}
|
|
512
|
-
function trackUsage(db, ids) {
|
|
513
|
-
if (ids.length === 0) return;
|
|
514
|
-
try {
|
|
515
|
-
const stmt = db.prepare(`
|
|
516
|
-
UPDATE llm_examples SET usage_count = usage_count + 1 WHERE id = ?
|
|
517
|
-
`);
|
|
518
|
-
for (const id of ids) {
|
|
519
|
-
stmt.run(id);
|
|
520
|
-
}
|
|
521
|
-
} catch {
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
618
|
function mapRowToLLMExample(row) {
|
|
525
619
|
return {
|
|
526
620
|
id: row.id,
|
|
@@ -530,11 +624,13 @@ function mapRowToLLMExample(row) {
|
|
|
530
624
|
completion: row.completion,
|
|
531
625
|
qualityScore: row.quality_score,
|
|
532
626
|
usageCount: row.usage_count,
|
|
533
|
-
createdAt: new Date(row.created_at)
|
|
627
|
+
createdAt: new Date(row.created_at),
|
|
628
|
+
engine: row.engine ?? null
|
|
534
629
|
};
|
|
535
630
|
}
|
|
536
631
|
|
|
537
632
|
// src/api/roles.ts
|
|
633
|
+
init_esm_shims();
|
|
538
634
|
async function getPatternRoles(patternId, options) {
|
|
539
635
|
const db = getDatabase({ ...options, readonly: true });
|
|
540
636
|
const rows = db.prepare(
|
|
@@ -551,7 +647,7 @@ async function getPatternsByRole(role, options) {
|
|
|
551
647
|
const db = getDatabase({ ...options, readonly: true });
|
|
552
648
|
const rows = db.prepare(
|
|
553
649
|
`
|
|
554
|
-
SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
|
|
650
|
+
SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.translatable, ce.created_at
|
|
555
651
|
FROM code_examples ce
|
|
556
652
|
INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
|
|
557
653
|
WHERE pr.role = ?
|
|
@@ -567,7 +663,7 @@ async function getPatternsByRoles(roles, matchMode = "any", options) {
|
|
|
567
663
|
const placeholders = roles.map(() => "?").join(", ");
|
|
568
664
|
const rows = db.prepare(
|
|
569
665
|
`
|
|
570
|
-
SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
|
|
666
|
+
SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.translatable, ce.created_at
|
|
571
667
|
FROM code_examples ce
|
|
572
668
|
INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
|
|
573
669
|
WHERE pr.role IN (${placeholders})
|
|
@@ -579,7 +675,7 @@ async function getPatternsByRoles(roles, matchMode = "any", options) {
|
|
|
579
675
|
const placeholders = roles.map(() => "?").join(", ");
|
|
580
676
|
const rows = db.prepare(
|
|
581
677
|
`
|
|
582
|
-
SELECT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
|
|
678
|
+
SELECT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.translatable, ce.created_at
|
|
583
679
|
FROM code_examples ce
|
|
584
680
|
WHERE (
|
|
585
681
|
SELECT COUNT(DISTINCT pr.role)
|
|
@@ -596,7 +692,7 @@ async function getPatternsByRoleValue(role, value, options) {
|
|
|
596
692
|
const db = getDatabase({ ...options, readonly: true });
|
|
597
693
|
const rows = db.prepare(
|
|
598
694
|
`
|
|
599
|
-
SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
|
|
695
|
+
SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.translatable, ce.created_at
|
|
600
696
|
FROM code_examples ce
|
|
601
697
|
INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
|
|
602
698
|
WHERE pr.role = ? AND pr.role_value LIKE ?
|
|
@@ -729,6 +825,7 @@ function mapRowToPattern2(row) {
|
|
|
729
825
|
tags: extractTags2(row.raw_code),
|
|
730
826
|
difficulty: inferDifficulty2(row.raw_code),
|
|
731
827
|
engine: row.engine || null,
|
|
828
|
+
translatable: row.translatable !== 0,
|
|
732
829
|
createdAt: new Date(row.created_at)
|
|
733
830
|
};
|
|
734
831
|
}
|
|
@@ -24,6 +24,12 @@ interface Pattern {
|
|
|
24
24
|
tags: string[];
|
|
25
25
|
difficulty: 'beginner' | 'intermediate' | 'advanced';
|
|
26
26
|
engine: EngineCompat | null;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the corpus writer translates this row. `false` rows are copied
|
|
29
|
+
* verbatim into every language (markup whose attribute names are resolved by
|
|
30
|
+
* vocab modules, or markup with no hyperscript at all).
|
|
31
|
+
*/
|
|
32
|
+
translatable: boolean;
|
|
27
33
|
createdAt: Date;
|
|
28
34
|
}
|
|
29
35
|
/**
|
|
@@ -48,7 +54,8 @@ type WordOrder = 'SVO' | 'SOV' | 'VSO' | 'V2';
|
|
|
48
54
|
* - `grammar-transform-no-reference`: `best` only — the i18n row because semantic
|
|
49
55
|
* cannot parse the ENGLISH source (a parser-coverage gap, not a render loss).
|
|
50
56
|
* - `keyword-substitute`: word-for-word fallback for a language with no grammar profile.
|
|
51
|
-
* - `original`: the English row; `non-translatable-identity`:
|
|
57
|
+
* - `original`: the English row; `non-translatable-identity`: a non-translatable row copied
|
|
58
|
+
* verbatim (the markup rows, and intercept-cache-strategies).
|
|
52
59
|
*/
|
|
53
60
|
type TranslationMethod = 'semantic-render' | 'grammar-transform' | 'grammar-transform-no-reference' | 'keyword-substitute' | 'original' | 'non-translatable-identity' | 'auto-generated' | 'hand-crafted' | 'verified';
|
|
54
61
|
/**
|
|
@@ -89,8 +96,24 @@ interface LLMExample {
|
|
|
89
96
|
prompt: string;
|
|
90
97
|
completion: string;
|
|
91
98
|
qualityScore: number;
|
|
99
|
+
/** @deprecated 0 unless something calls trackExampleUsage() (see getMostUsedExamples). */
|
|
92
100
|
usageCount: number;
|
|
93
101
|
createdAt: Date;
|
|
102
|
+
/**
|
|
103
|
+
* The engine(s) verified to run this example's pattern
|
|
104
|
+
* (`code_examples.engine`). Never null in results: an example no engine
|
|
105
|
+
* runs is not served.
|
|
106
|
+
*/
|
|
107
|
+
engine: EngineCompat | null;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Options for the LLM-example getters. `engine` narrows to examples whose
|
|
111
|
+
* pattern runs on that engine — 'hyperscript' = both + upstream-only,
|
|
112
|
+
* 'lokascript' = both + hyperfixi-only, 'both' = both. With or without it,
|
|
113
|
+
* an example whose pattern NO engine runs is never returned.
|
|
114
|
+
*/
|
|
115
|
+
interface ExampleOptions extends ConnectionOptions {
|
|
116
|
+
engine?: EngineCompat;
|
|
94
117
|
}
|
|
95
118
|
|
|
96
119
|
/**
|
|
@@ -109,10 +132,22 @@ interface PatternRole {
|
|
|
109
132
|
roleType: RoleType | null;
|
|
110
133
|
required: boolean;
|
|
111
134
|
}
|
|
135
|
+
/** Honoured by searchPatterns and getAllPatterns; the page is taken after every filter. */
|
|
112
136
|
interface SearchOptions {
|
|
137
|
+
/**
|
|
138
|
+
* Patterns usable in this language: a translation there that parses
|
|
139
|
+
* (`verified_parses`), or no hyperscript at all to translate. searchPatterns
|
|
140
|
+
* also matches its query against that translation.
|
|
141
|
+
*/
|
|
113
142
|
language?: string;
|
|
143
|
+
/** The pattern's category (`Pattern.category`). */
|
|
114
144
|
category?: string;
|
|
145
|
+
/** As inferred from the code (`Pattern.difficulty`). */
|
|
115
146
|
difficulty?: 'beginner' | 'intermediate' | 'advanced';
|
|
147
|
+
/**
|
|
148
|
+
* Patterns that run on this engine ('hyperscript' / 'lokascript' include
|
|
149
|
+
* 'both'); `null` = the patterns no engine runs; omitted = no filter.
|
|
150
|
+
*/
|
|
116
151
|
engine?: EngineCompat | null;
|
|
117
152
|
limit?: number;
|
|
118
153
|
offset?: number;
|
|
@@ -302,9 +337,10 @@ interface PatternsReference {
|
|
|
302
337
|
getTranslation(patternId: string, language: string): Promise<Translation | null>;
|
|
303
338
|
getAllTranslations(patternId: string): Promise<Translation[]>;
|
|
304
339
|
verifyTranslation(translation: Translation): Promise<VerificationResult>;
|
|
305
|
-
|
|
340
|
+
/** Never returns an example no engine runs; `engine` narrows further (see ExampleOptions). */
|
|
341
|
+
getLLMExamples(prompt: string, language?: string, limit?: number, engine?: EngineCompat): Promise<LLMExample[]>;
|
|
306
342
|
getStats(): Promise<PatternStats>;
|
|
307
343
|
close(): void;
|
|
308
344
|
}
|
|
309
345
|
|
|
310
|
-
export type { ConnectionOptions as C, DiscoveryResult as D, Expression as E, Feature as F, Keyword as K, LanguageDocsStats as L, PatternRole as P, RoleType as R, SpecialSymbol as S, TestOptions as T, ValidationOptions as V, WordOrder as W, Pattern as a, Command as b, LanguageElementType as c, LanguageElement as d,
|
|
346
|
+
export type { ConnectionOptions as C, DiscoveryResult as D, Expression as E, Feature as F, Keyword as K, LanguageDocsStats as L, PatternRole as P, RoleType as R, SpecialSymbol as S, TestOptions as T, ValidationOptions as V, WordOrder as W, Pattern as a, Command as b, LanguageElementType as c, LanguageElement as d, EngineCompat as e, LLMExample as f, PatternsReference as g, ClassifiedPattern as h, ComplexityLevel as i, ExampleOptions as j, ExpressionOperator as k, PatternStats as l, SearchOptions as m, SyncOptions as n, SyncResult as o, Translation as p, TranslationMethod as q, ValidationResult as r, VerificationResult as s };
|
|
@@ -24,6 +24,12 @@ interface Pattern {
|
|
|
24
24
|
tags: string[];
|
|
25
25
|
difficulty: 'beginner' | 'intermediate' | 'advanced';
|
|
26
26
|
engine: EngineCompat | null;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the corpus writer translates this row. `false` rows are copied
|
|
29
|
+
* verbatim into every language (markup whose attribute names are resolved by
|
|
30
|
+
* vocab modules, or markup with no hyperscript at all).
|
|
31
|
+
*/
|
|
32
|
+
translatable: boolean;
|
|
27
33
|
createdAt: Date;
|
|
28
34
|
}
|
|
29
35
|
/**
|
|
@@ -48,7 +54,8 @@ type WordOrder = 'SVO' | 'SOV' | 'VSO' | 'V2';
|
|
|
48
54
|
* - `grammar-transform-no-reference`: `best` only — the i18n row because semantic
|
|
49
55
|
* cannot parse the ENGLISH source (a parser-coverage gap, not a render loss).
|
|
50
56
|
* - `keyword-substitute`: word-for-word fallback for a language with no grammar profile.
|
|
51
|
-
* - `original`: the English row; `non-translatable-identity`:
|
|
57
|
+
* - `original`: the English row; `non-translatable-identity`: a non-translatable row copied
|
|
58
|
+
* verbatim (the markup rows, and intercept-cache-strategies).
|
|
52
59
|
*/
|
|
53
60
|
type TranslationMethod = 'semantic-render' | 'grammar-transform' | 'grammar-transform-no-reference' | 'keyword-substitute' | 'original' | 'non-translatable-identity' | 'auto-generated' | 'hand-crafted' | 'verified';
|
|
54
61
|
/**
|
|
@@ -89,8 +96,24 @@ interface LLMExample {
|
|
|
89
96
|
prompt: string;
|
|
90
97
|
completion: string;
|
|
91
98
|
qualityScore: number;
|
|
99
|
+
/** @deprecated 0 unless something calls trackExampleUsage() (see getMostUsedExamples). */
|
|
92
100
|
usageCount: number;
|
|
93
101
|
createdAt: Date;
|
|
102
|
+
/**
|
|
103
|
+
* The engine(s) verified to run this example's pattern
|
|
104
|
+
* (`code_examples.engine`). Never null in results: an example no engine
|
|
105
|
+
* runs is not served.
|
|
106
|
+
*/
|
|
107
|
+
engine: EngineCompat | null;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Options for the LLM-example getters. `engine` narrows to examples whose
|
|
111
|
+
* pattern runs on that engine — 'hyperscript' = both + upstream-only,
|
|
112
|
+
* 'lokascript' = both + hyperfixi-only, 'both' = both. With or without it,
|
|
113
|
+
* an example whose pattern NO engine runs is never returned.
|
|
114
|
+
*/
|
|
115
|
+
interface ExampleOptions extends ConnectionOptions {
|
|
116
|
+
engine?: EngineCompat;
|
|
94
117
|
}
|
|
95
118
|
|
|
96
119
|
/**
|
|
@@ -109,10 +132,22 @@ interface PatternRole {
|
|
|
109
132
|
roleType: RoleType | null;
|
|
110
133
|
required: boolean;
|
|
111
134
|
}
|
|
135
|
+
/** Honoured by searchPatterns and getAllPatterns; the page is taken after every filter. */
|
|
112
136
|
interface SearchOptions {
|
|
137
|
+
/**
|
|
138
|
+
* Patterns usable in this language: a translation there that parses
|
|
139
|
+
* (`verified_parses`), or no hyperscript at all to translate. searchPatterns
|
|
140
|
+
* also matches its query against that translation.
|
|
141
|
+
*/
|
|
113
142
|
language?: string;
|
|
143
|
+
/** The pattern's category (`Pattern.category`). */
|
|
114
144
|
category?: string;
|
|
145
|
+
/** As inferred from the code (`Pattern.difficulty`). */
|
|
115
146
|
difficulty?: 'beginner' | 'intermediate' | 'advanced';
|
|
147
|
+
/**
|
|
148
|
+
* Patterns that run on this engine ('hyperscript' / 'lokascript' include
|
|
149
|
+
* 'both'); `null` = the patterns no engine runs; omitted = no filter.
|
|
150
|
+
*/
|
|
116
151
|
engine?: EngineCompat | null;
|
|
117
152
|
limit?: number;
|
|
118
153
|
offset?: number;
|
|
@@ -302,9 +337,10 @@ interface PatternsReference {
|
|
|
302
337
|
getTranslation(patternId: string, language: string): Promise<Translation | null>;
|
|
303
338
|
getAllTranslations(patternId: string): Promise<Translation[]>;
|
|
304
339
|
verifyTranslation(translation: Translation): Promise<VerificationResult>;
|
|
305
|
-
|
|
340
|
+
/** Never returns an example no engine runs; `engine` narrows further (see ExampleOptions). */
|
|
341
|
+
getLLMExamples(prompt: string, language?: string, limit?: number, engine?: EngineCompat): Promise<LLMExample[]>;
|
|
306
342
|
getStats(): Promise<PatternStats>;
|
|
307
343
|
close(): void;
|
|
308
344
|
}
|
|
309
345
|
|
|
310
|
-
export type { ConnectionOptions as C, DiscoveryResult as D, Expression as E, Feature as F, Keyword as K, LanguageDocsStats as L, PatternRole as P, RoleType as R, SpecialSymbol as S, TestOptions as T, ValidationOptions as V, WordOrder as W, Pattern as a, Command as b, LanguageElementType as c, LanguageElement as d,
|
|
346
|
+
export type { ConnectionOptions as C, DiscoveryResult as D, Expression as E, Feature as F, Keyword as K, LanguageDocsStats as L, PatternRole as P, RoleType as R, SpecialSymbol as S, TestOptions as T, ValidationOptions as V, WordOrder as W, Pattern as a, Command as b, LanguageElementType as c, LanguageElement as d, EngineCompat as e, LLMExample as f, PatternsReference as g, ClassifiedPattern as h, ComplexityLevel as i, ExampleOptions as j, ExpressionOperator as k, PatternStats as l, SearchOptions as m, SyncOptions as n, SyncResult as o, Translation as p, TranslationMethod as q, ValidationResult as r, VerificationResult as s };
|