@functional-systems/srcx 0.1.0-dev.20 → 0.1.0-dev.22
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 +11 -0
- package/DESIGN.md +28 -3
- package/README.md +69 -9
- package/VALIDATION.md +56 -0
- package/dist/build.d.ts +21 -17
- package/dist/build.js +38 -14
- package/dist/build.js.map +1 -1
- package/dist/chunk.d.ts +2 -1
- package/dist/chunk.js +313 -4
- package/dist/chunk.js.map +1 -1
- package/dist/cli.js +7 -3
- package/dist/cli.js.map +1 -1
- package/dist/publish.js +4 -15
- package/dist/publish.js.map +1 -1
- package/package.json +3 -2
- package/runtime/grammars/README.md +26 -0
- package/runtime/grammars/tree-sitter-sql.LICENSE +21 -0
- package/runtime/grammars/tree-sitter-sql.wasm +0 -0
- package/runtime/grammars/tree-sitter-wasm.LICENSE +21 -0
- package/src/build.ts +48 -17
- package/src/chunk.ts +327 -4
- package/src/cli.ts +21 -2
- package/src/publish.ts +4 -14
package/src/chunk.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
1
2
|
import { createRequire } from "node:module";
|
|
2
3
|
import { Parser, Language, type Node } from "web-tree-sitter";
|
|
3
4
|
import { getEncoding } from "js-tiktoken";
|
|
@@ -8,9 +9,11 @@ export function tokens(text: string): number {
|
|
|
8
9
|
return encoding.encode(text, [], []).length;
|
|
9
10
|
}
|
|
10
11
|
export const CHUNKER = {
|
|
11
|
-
version:
|
|
12
|
+
version: 2,
|
|
12
13
|
parser: "web-tree-sitter@0.25.10",
|
|
13
14
|
grammars: "tree-sitter-wasms@0.1.13",
|
|
15
|
+
sqlGrammar:
|
|
16
|
+
"tree-sitter-wasm@2.0.2/sql/b77530893b1dd6d1d4814eacf34d25bcbe4a12ec9a25a8c45b320d447265f42b",
|
|
14
17
|
tokenizer: "js-tiktoken@1.0.21/cl100k_base",
|
|
15
18
|
targetTokens: 800,
|
|
16
19
|
maxTokens: 1500,
|
|
@@ -46,17 +49,42 @@ async function language(name: string): Promise<Language> {
|
|
|
46
49
|
let l = languages.get(name);
|
|
47
50
|
if (!l) {
|
|
48
51
|
l = await Language.load(
|
|
49
|
-
|
|
52
|
+
name === "sql"
|
|
53
|
+
? fileURLToPath(
|
|
54
|
+
new URL(
|
|
55
|
+
"../runtime/grammars/tree-sitter-sql.wasm",
|
|
56
|
+
import.meta.url,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
: require.resolve(
|
|
60
|
+
`tree-sitter-wasms/out/tree-sitter-${name === "shell" ? "bash" : name}.wasm`,
|
|
61
|
+
),
|
|
50
62
|
);
|
|
51
63
|
languages.set(name, l);
|
|
52
64
|
}
|
|
53
65
|
return l;
|
|
54
66
|
}
|
|
55
67
|
export function detectLanguage(path: string): string {
|
|
68
|
+
if (path.endsWith(".C")) return "cpp";
|
|
56
69
|
const ext = path.split(".").at(-1)?.toLowerCase();
|
|
57
70
|
return (
|
|
58
71
|
(
|
|
59
72
|
{
|
|
73
|
+
py: "python",
|
|
74
|
+
pyi: "python",
|
|
75
|
+
go: "go",
|
|
76
|
+
rs: "rust",
|
|
77
|
+
c: "c",
|
|
78
|
+
h: "c",
|
|
79
|
+
cc: "cpp",
|
|
80
|
+
cpp: "cpp",
|
|
81
|
+
cxx: "cpp",
|
|
82
|
+
hh: "cpp",
|
|
83
|
+
hpp: "cpp",
|
|
84
|
+
hxx: "cpp",
|
|
85
|
+
sh: "shell",
|
|
86
|
+
bash: "shell",
|
|
87
|
+
sql: "sql",
|
|
60
88
|
java: "java",
|
|
61
89
|
ts: "typescript",
|
|
62
90
|
tsx: "tsx",
|
|
@@ -102,6 +130,278 @@ function scopeName(n: Node): string | undefined {
|
|
|
102
130
|
}
|
|
103
131
|
return names.length ? names.join(".") : undefined;
|
|
104
132
|
}
|
|
133
|
+
|
|
134
|
+
/** Keep complete functions (including decorators) before token-bound splitting. */
|
|
135
|
+
function pythonUnits(root: Node): Unit[] {
|
|
136
|
+
const units: Unit[] = [];
|
|
137
|
+
function visit(n: Node, scope?: string): void {
|
|
138
|
+
const definition = n.childForFieldName("definition") ?? n;
|
|
139
|
+
const body = definition.childForFieldName("body");
|
|
140
|
+
const symbol = definition.childForFieldName("name")?.text.slice(0, 200);
|
|
141
|
+
const unit: Unit = {
|
|
142
|
+
start: n.startIndex,
|
|
143
|
+
end: n.endIndex,
|
|
144
|
+
kind: classify(definition.type),
|
|
145
|
+
scope,
|
|
146
|
+
symbol,
|
|
147
|
+
};
|
|
148
|
+
if (definition.type === "class_definition" && body) {
|
|
149
|
+
units.push({ ...unit, end: body.startIndex });
|
|
150
|
+
const nested = [scope, symbol].filter(Boolean).join(".");
|
|
151
|
+
for (const child of body.namedChildren) if (child) visit(child, nested);
|
|
152
|
+
} else {
|
|
153
|
+
if (definition.type === "function_definition" && body)
|
|
154
|
+
unit.signature = definition.text
|
|
155
|
+
.slice(0, body.startIndex - definition.startIndex)
|
|
156
|
+
.trim()
|
|
157
|
+
.slice(0, 240);
|
|
158
|
+
if (
|
|
159
|
+
definition.type === "expression_statement" &&
|
|
160
|
+
definition.firstNamedChild?.type === "string"
|
|
161
|
+
)
|
|
162
|
+
unit.kind = "documentation";
|
|
163
|
+
units.push(unit);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const n of root.namedChildren) if (n) visit(n);
|
|
167
|
+
return units;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function goUnits(root: Node): Unit[] {
|
|
171
|
+
const units: Unit[] = [];
|
|
172
|
+
for (const n of root.namedChildren) {
|
|
173
|
+
if (!n) continue;
|
|
174
|
+
if (n.type === "type_declaration") {
|
|
175
|
+
// Include the type keyword and grouped declaration delimiters in coverage.
|
|
176
|
+
const specs = n.namedChildren.filter(
|
|
177
|
+
(node): node is Node => node !== null,
|
|
178
|
+
);
|
|
179
|
+
for (const [i, spec] of specs.entries())
|
|
180
|
+
units.push({
|
|
181
|
+
start: i === 0 ? n.startIndex : spec.startIndex,
|
|
182
|
+
end: i === specs.length - 1 ? n.endIndex : spec.endIndex,
|
|
183
|
+
kind: classify(spec.type),
|
|
184
|
+
symbol: spec.childForFieldName("name")?.text.slice(0, 200),
|
|
185
|
+
});
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const unit: Unit = {
|
|
189
|
+
start: n.startIndex,
|
|
190
|
+
end: n.endIndex,
|
|
191
|
+
kind: classify(n.type),
|
|
192
|
+
symbol: n.childForFieldName("name")?.text.slice(0, 200),
|
|
193
|
+
};
|
|
194
|
+
let receiver = n
|
|
195
|
+
.childForFieldName("receiver")
|
|
196
|
+
?.firstNamedChild?.childForFieldName("type");
|
|
197
|
+
if (receiver?.type === "pointer_type") receiver = receiver.firstNamedChild;
|
|
198
|
+
if (receiver?.type === "generic_type")
|
|
199
|
+
receiver = receiver.childForFieldName("type");
|
|
200
|
+
if (receiver) unit.scope = receiver.text.slice(0, 160);
|
|
201
|
+
const body = n.childForFieldName("body");
|
|
202
|
+
if (unit.kind === "function")
|
|
203
|
+
unit.signature = n.text
|
|
204
|
+
.slice(0, body ? body.startIndex - n.startIndex : undefined)
|
|
205
|
+
.trim()
|
|
206
|
+
.slice(0, 240);
|
|
207
|
+
units.push(unit);
|
|
208
|
+
}
|
|
209
|
+
return units;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Walk declarators rather than parameter/type names (including pointer returns). */
|
|
213
|
+
function declaratorName(n: Node | null): string | undefined {
|
|
214
|
+
if (!n) return undefined;
|
|
215
|
+
if (
|
|
216
|
+
/^(identifier|field_identifier|type_identifier|qualified_identifier|destructor_name|operator_name)$/.test(
|
|
217
|
+
n.type,
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
return n.text;
|
|
221
|
+
return declaratorName(
|
|
222
|
+
n.childForFieldName("declarator") ??
|
|
223
|
+
(n.type === "parenthesized_declarator" ? n.firstNamedChild : null),
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function cUnits(root: Node): Unit[] {
|
|
228
|
+
const units: Unit[] = [];
|
|
229
|
+
function visit(n: Node, scope?: string, start = n.startIndex): void {
|
|
230
|
+
if (n.type === "template_declaration") {
|
|
231
|
+
const declaration = n.namedChildren
|
|
232
|
+
.filter((c): c is Node => !!c && c.type !== "template_parameter_list")
|
|
233
|
+
.at(-1);
|
|
234
|
+
if (declaration) {
|
|
235
|
+
visit(declaration, scope, start);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const body = n.childForFieldName("body");
|
|
240
|
+
const symbol =
|
|
241
|
+
n.childForFieldName("name")?.text ??
|
|
242
|
+
declaratorName(n.childForFieldName("declarator"));
|
|
243
|
+
const unit: Unit = {
|
|
244
|
+
start,
|
|
245
|
+
end: n.endIndex,
|
|
246
|
+
kind: n.type === "preproc_include" ? "imports" : classify(n.type),
|
|
247
|
+
scope,
|
|
248
|
+
symbol: symbol?.slice(0, 200),
|
|
249
|
+
};
|
|
250
|
+
if (body && /^(declaration_list|field_declaration_list)$/.test(body.type)) {
|
|
251
|
+
const nested = [scope, symbol].filter(Boolean).join("::") || undefined;
|
|
252
|
+
units.push({ ...unit, end: body.startIndex + 1 });
|
|
253
|
+
for (const child of body.namedChildren) if (child) visit(child, nested);
|
|
254
|
+
units.push({
|
|
255
|
+
start: body.endIndex - 1,
|
|
256
|
+
end: n.endIndex,
|
|
257
|
+
kind: "structural",
|
|
258
|
+
scope: nested,
|
|
259
|
+
});
|
|
260
|
+
} else if (/^preproc_(if|ifdef|elif|else|elifdef)$/.test(n.type)) {
|
|
261
|
+
// Preserve directives and both branches without evaluating the build configuration.
|
|
262
|
+
const condition =
|
|
263
|
+
n.childForFieldName("condition") ?? n.childForFieldName("name");
|
|
264
|
+
const children = n.namedChildren.filter(
|
|
265
|
+
(c): c is Node => !!c && c.id !== condition?.id,
|
|
266
|
+
);
|
|
267
|
+
if (!children.length) {
|
|
268
|
+
units.push(unit);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
units.push({ ...unit, end: children[0]!.startIndex });
|
|
272
|
+
for (const child of children) visit(child, scope);
|
|
273
|
+
const end = children.at(-1)!.endIndex;
|
|
274
|
+
if (end < n.endIndex)
|
|
275
|
+
units.push({ start: end, end: n.endIndex, kind: "structural", scope });
|
|
276
|
+
} else {
|
|
277
|
+
if (n.type === "function_definition")
|
|
278
|
+
unit.signature = n.text
|
|
279
|
+
.slice(0, body ? body.startIndex - n.startIndex : undefined)
|
|
280
|
+
.trim()
|
|
281
|
+
.slice(0, 240);
|
|
282
|
+
units.push(unit);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (const n of root.namedChildren) if (n) visit(n);
|
|
286
|
+
return units;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function shellUnits(root: Node): Unit[] {
|
|
290
|
+
return root.namedChildren
|
|
291
|
+
.filter((n): n is Node => !!n)
|
|
292
|
+
.map((n) => {
|
|
293
|
+
const body = n.childForFieldName("body");
|
|
294
|
+
return {
|
|
295
|
+
start: n.startIndex,
|
|
296
|
+
end: n.endIndex,
|
|
297
|
+
kind: classify(n.type),
|
|
298
|
+
symbol:
|
|
299
|
+
n.type === "function_definition"
|
|
300
|
+
? n.childForFieldName("name")?.text.slice(0, 200)
|
|
301
|
+
: undefined,
|
|
302
|
+
signature:
|
|
303
|
+
n.type === "function_definition"
|
|
304
|
+
? n.text
|
|
305
|
+
.slice(0, body ? body.startIndex - n.startIndex : undefined)
|
|
306
|
+
.trim()
|
|
307
|
+
.slice(0, 240)
|
|
308
|
+
: undefined,
|
|
309
|
+
};
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function sqlUnits(root: Node): Unit[] {
|
|
314
|
+
return root.namedChildren
|
|
315
|
+
.filter((n): n is Node => !!n)
|
|
316
|
+
.map((n) => {
|
|
317
|
+
const declaration = n.firstNamedChild;
|
|
318
|
+
// Object names describe DDL declarations, not every table referenced by a query.
|
|
319
|
+
const object = declaration?.type.startsWith("create_")
|
|
320
|
+
? declaration.namedChildren.find((c) => c?.type === "object_reference")
|
|
321
|
+
: undefined;
|
|
322
|
+
return {
|
|
323
|
+
start: n.startIndex,
|
|
324
|
+
end: n.nextSibling?.type === ";" ? n.nextSibling.endIndex : n.endIndex,
|
|
325
|
+
kind: n.type === "comment" ? "documentation" : "statement",
|
|
326
|
+
symbol: object?.childForFieldName("name")?.text.slice(0, 200),
|
|
327
|
+
scope: object?.childForFieldName("schema")?.text.slice(0, 160),
|
|
328
|
+
};
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function rustUnits(root: Node): Unit[] {
|
|
333
|
+
const units: Unit[] = [];
|
|
334
|
+
function visit(container: Node, scope?: string): void {
|
|
335
|
+
let prefix: number | undefined;
|
|
336
|
+
for (const n of container.namedChildren) {
|
|
337
|
+
if (!n) continue;
|
|
338
|
+
// Outer attributes/doc comments belong to the following item, not a chunk
|
|
339
|
+
// containing only cfg/derive metadata. Inner module docs remain separate.
|
|
340
|
+
if (
|
|
341
|
+
n.type === "attribute_item" ||
|
|
342
|
+
/^(\/\/\/(?!\/)|\/\*\*(?!\*))/.test(n.text)
|
|
343
|
+
) {
|
|
344
|
+
prefix ??= n.startIndex;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (prefix !== undefined && n.type.endsWith("comment")) continue;
|
|
348
|
+
const body = n.childForFieldName("body");
|
|
349
|
+
const name = n.childForFieldName("name")?.text;
|
|
350
|
+
const type = n.childForFieldName("type")?.text;
|
|
351
|
+
const trait = n.childForFieldName("trait")?.text;
|
|
352
|
+
const unit: Unit = {
|
|
353
|
+
start: prefix ?? n.startIndex,
|
|
354
|
+
end: n.endIndex,
|
|
355
|
+
kind:
|
|
356
|
+
n.type === "use_declaration" || n.type === "extern_crate_declaration"
|
|
357
|
+
? "imports"
|
|
358
|
+
: classify(n.type),
|
|
359
|
+
scope,
|
|
360
|
+
symbol: (
|
|
361
|
+
name ??
|
|
362
|
+
(n.type === "impl_item" ? type : n.childForFieldName("macro")?.text)
|
|
363
|
+
)?.slice(0, 200),
|
|
364
|
+
};
|
|
365
|
+
prefix = undefined;
|
|
366
|
+
if (body?.type === "declaration_list") {
|
|
367
|
+
const owner =
|
|
368
|
+
n.type === "impl_item"
|
|
369
|
+
? [type, trait].filter(Boolean).join(" as ")
|
|
370
|
+
: name;
|
|
371
|
+
const nested =
|
|
372
|
+
[scope, owner].filter(Boolean).join("::").slice(0, 160) || undefined;
|
|
373
|
+
units.push({ ...unit, end: body.startIndex + 1 });
|
|
374
|
+
visit(body, nested);
|
|
375
|
+
// Keep closing delimiters with their container, including empty bodies.
|
|
376
|
+
units.push({
|
|
377
|
+
start: body.endIndex - 1,
|
|
378
|
+
end: n.endIndex,
|
|
379
|
+
kind: "structural",
|
|
380
|
+
scope: nested,
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
if (unit.kind === "function")
|
|
384
|
+
unit.signature = n.text
|
|
385
|
+
.slice(0, body ? body.startIndex - n.startIndex : undefined)
|
|
386
|
+
.trim()
|
|
387
|
+
.slice(0, 240);
|
|
388
|
+
units.push(unit);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (prefix !== undefined)
|
|
392
|
+
units.push({
|
|
393
|
+
start: prefix,
|
|
394
|
+
end:
|
|
395
|
+
container.type === "declaration_list"
|
|
396
|
+
? container.endIndex - 1
|
|
397
|
+
: container.endIndex,
|
|
398
|
+
kind: "documentation",
|
|
399
|
+
scope,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
visit(root);
|
|
403
|
+
return units;
|
|
404
|
+
}
|
|
105
405
|
/** Bound strings without slicing a surrogate pair; prefer line ends where possible. */
|
|
106
406
|
function splitUnit(
|
|
107
407
|
source: string,
|
|
@@ -198,7 +498,21 @@ export async function chunk(
|
|
|
198
498
|
if (mode === "window") {
|
|
199
499
|
status = "window-baseline";
|
|
200
500
|
units = [{ start: 0, end: source.length, kind: "fallback" }];
|
|
201
|
-
} else if (
|
|
501
|
+
} else if (
|
|
502
|
+
[
|
|
503
|
+
"java",
|
|
504
|
+
"typescript",
|
|
505
|
+
"tsx",
|
|
506
|
+
"javascript",
|
|
507
|
+
"python",
|
|
508
|
+
"go",
|
|
509
|
+
"rust",
|
|
510
|
+
"c",
|
|
511
|
+
"cpp",
|
|
512
|
+
"shell",
|
|
513
|
+
"sql",
|
|
514
|
+
].includes(lang)
|
|
515
|
+
) {
|
|
202
516
|
const grammar = await language(lang);
|
|
203
517
|
const parser = new Parser();
|
|
204
518
|
let tree: ReturnType<Parser["parse"]> = null;
|
|
@@ -233,7 +547,13 @@ export async function chunk(
|
|
|
233
547
|
for (const child of n.namedChildren) if (child) visit(child);
|
|
234
548
|
} else if (n.endIndex > n.startIndex) units.push(u);
|
|
235
549
|
}
|
|
236
|
-
|
|
550
|
+
if (lang === "python") units = pythonUnits(tree.rootNode);
|
|
551
|
+
else if (lang === "go") units = goUnits(tree.rootNode);
|
|
552
|
+
else if (lang === "rust") units = rustUnits(tree.rootNode);
|
|
553
|
+
else if (lang === "c" || lang === "cpp") units = cUnits(tree.rootNode);
|
|
554
|
+
else if (lang === "shell") units = shellUnits(tree.rootNode);
|
|
555
|
+
else if (lang === "sql") units = sqlUnits(tree.rootNode);
|
|
556
|
+
else visit(tree.rootNode);
|
|
237
557
|
// Attach every gap (punctuation, BOM, comments, whitespace) without altering source bytes.
|
|
238
558
|
let cursor = 0;
|
|
239
559
|
const covered: Unit[] = [];
|
|
@@ -272,6 +592,9 @@ export async function chunk(
|
|
|
272
592
|
const prev = merged.at(-1);
|
|
273
593
|
if (
|
|
274
594
|
prev &&
|
|
595
|
+
lang !== "sql" &&
|
|
596
|
+
(!["python", "go", "rust", "c", "cpp", "shell"].includes(lang) ||
|
|
597
|
+
(!prev.symbol && !u.symbol)) &&
|
|
275
598
|
prev.kind !== "function" &&
|
|
276
599
|
u.kind === prev.kind &&
|
|
277
600
|
u.scope === prev.scope &&
|
package/src/cli.ts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
type Preset,
|
|
15
15
|
PRESET,
|
|
16
16
|
presetFor,
|
|
17
|
+
normalizeAnalyzers,
|
|
18
|
+
ANALYZERS,
|
|
17
19
|
} from "./build.js";
|
|
18
20
|
import { invariant, optionalJson } from "./common.js";
|
|
19
21
|
import { LambdaRemote } from "./remote.js";
|
|
@@ -54,6 +56,13 @@ const integer = (value: string) => {
|
|
|
54
56
|
throw new InvalidArgumentError("Integer is too large.");
|
|
55
57
|
return n;
|
|
56
58
|
};
|
|
59
|
+
const analyzerOption = (description: string) =>
|
|
60
|
+
new Option(
|
|
61
|
+
"--analyzers <names>",
|
|
62
|
+
description + ` (${ANALYZERS.join(", ")}; default: standard)`,
|
|
63
|
+
).argParser((value) =>
|
|
64
|
+
normalizeAnalyzers(value.split(",").map((name) => name.trim())),
|
|
65
|
+
);
|
|
57
66
|
async function connected() {
|
|
58
67
|
const settings = await loadSettings();
|
|
59
68
|
return { settings, remote: new LambdaRemote(settings) };
|
|
@@ -96,6 +105,7 @@ repo
|
|
|
96
105
|
.option("--remote <name>")
|
|
97
106
|
.option("--description <text>")
|
|
98
107
|
.option("--tag <key=value>", "One optional Collection metadata tag")
|
|
108
|
+
.addOption(analyzerOption("Comma-separated text analyzers"))
|
|
99
109
|
.addOption(
|
|
100
110
|
new Option(
|
|
101
111
|
"--embedding <model>",
|
|
@@ -118,7 +128,7 @@ repo
|
|
|
118
128
|
remote: o.remote,
|
|
119
129
|
description: o.description,
|
|
120
130
|
labels,
|
|
121
|
-
preset: presetFor(o.embedding),
|
|
131
|
+
preset: presetFor(o.embedding, o.analyzers),
|
|
122
132
|
}),
|
|
123
133
|
);
|
|
124
134
|
});
|
|
@@ -152,6 +162,11 @@ cli
|
|
|
152
162
|
"Preset for --dry-run --path; connected imports use the repository preset",
|
|
153
163
|
).choices(["none", "text-embedding-3-small", "text-embedding-3-large"]),
|
|
154
164
|
)
|
|
165
|
+
.addOption(
|
|
166
|
+
analyzerOption(
|
|
167
|
+
"Text analyzers for --dry-run --path; connected imports use the repository preset",
|
|
168
|
+
),
|
|
169
|
+
)
|
|
155
170
|
.option("--output <directory>", "New artifact directory")
|
|
156
171
|
.option(
|
|
157
172
|
"--previous <directory>",
|
|
@@ -168,6 +183,10 @@ cli
|
|
|
168
183
|
!o.embedding || (o.dryRun && o.path),
|
|
169
184
|
"--embedding is only accepted with --dry-run --path; connected imports use the repository preset.",
|
|
170
185
|
);
|
|
186
|
+
invariant(
|
|
187
|
+
!o.analyzers || (o.dryRun && o.path),
|
|
188
|
+
"--analyzers is only accepted with --dry-run --path; connected imports use the repository preset.",
|
|
189
|
+
);
|
|
171
190
|
invariant(!(o.path && o.repo), "Choose --path or --repo.");
|
|
172
191
|
invariant(
|
|
173
192
|
!o.previous || o.dryRun,
|
|
@@ -217,7 +236,7 @@ cli
|
|
|
217
236
|
await validateBuild(b);
|
|
218
237
|
} else {
|
|
219
238
|
let source;
|
|
220
|
-
let preset = presetFor(o.embedding);
|
|
239
|
+
let preset = presetFor(o.embedding, o.analyzers);
|
|
221
240
|
if (o.path) source = await identity(o.path, o.remote);
|
|
222
241
|
else {
|
|
223
242
|
invariant(o.repo, "Use --path for a credential-free dry run.");
|
package/src/publish.ts
CHANGED
|
@@ -175,10 +175,8 @@ export async function validateCandidate(
|
|
|
175
175
|
};
|
|
176
176
|
for await (const d of records(b.directory)) {
|
|
177
177
|
if (d.kind !== "chunk") continue;
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
const term = String(d.symbol ?? d.searchText).match(/\S+/u)?.[0];
|
|
181
|
-
if (!term) continue;
|
|
178
|
+
// Probe an indexed chunk ID: a valid source may contain only stop words
|
|
179
|
+
// or punctuation, so text-query matches cannot establish readiness.
|
|
182
180
|
query = {
|
|
183
181
|
bool: [
|
|
184
182
|
{
|
|
@@ -191,16 +189,8 @@ export async function validateCandidate(
|
|
|
191
189
|
},
|
|
192
190
|
{
|
|
193
191
|
queryString: {
|
|
194
|
-
query: d.
|
|
195
|
-
defaultField: "
|
|
196
|
-
skipSyntax: true,
|
|
197
|
-
},
|
|
198
|
-
occur: "filter",
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
queryString: {
|
|
202
|
-
query: term,
|
|
203
|
-
defaultField: "searchText",
|
|
192
|
+
query: d.id,
|
|
193
|
+
defaultField: "id",
|
|
204
194
|
skipSyntax: true,
|
|
205
195
|
},
|
|
206
196
|
occur: "must",
|