sensemaking 0.15.3 → 0.16.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/README.md +33 -5
- package/dist/cjs/cli/download.js +15 -19
- package/dist/cjs/cli/download.js.map +1 -1
- package/dist/cjs/cli/index.d.cts +1 -1
- package/dist/cjs/cli/index.d.ts +1 -1
- package/dist/cjs/cli/index.js +9 -20
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/init.js +31 -5
- package/dist/cjs/cli/init.js.map +1 -1
- package/dist/cjs/cli/map.js +1 -3
- package/dist/cjs/cli/map.js.map +1 -1
- package/dist/cjs/cli/named.js +3 -8
- package/dist/cjs/cli/named.js.map +1 -1
- package/dist/cjs/cli/path.js +4 -7
- package/dist/cjs/cli/path.js.map +1 -1
- package/dist/cjs/cli/peek.js +2 -4
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/related.js +14 -20
- package/dist/cjs/cli/related.js.map +1 -1
- package/dist/cjs/cli/search.js +12 -17
- package/dist/cjs/cli/search.js.map +1 -1
- package/dist/cjs/cli/shared.js +17 -21
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/sql.js +7 -8
- package/dist/cjs/cli/sql.js.map +1 -1
- package/dist/cjs/cli/status.js +344 -102
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/cli/watch.js +3 -8
- package/dist/cjs/cli/watch.js.map +1 -1
- package/dist/cjs/cli.js +22 -34
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/column-hint.js +4 -2
- package/dist/cjs/column-hint.js.map +1 -1
- package/dist/cjs/commands/peek.js +5 -3
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.js +31 -28
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.js +4 -2
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.js +36 -108
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +18 -0
- package/dist/cjs/commands/signals.d.ts +18 -0
- package/dist/cjs/commands/signals.js +299 -0
- package/dist/cjs/commands/signals.js.map +1 -0
- package/dist/cjs/commands/status.d.cts +2 -2
- package/dist/cjs/commands/status.d.ts +2 -2
- package/dist/cjs/commands/status.js +1 -1
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/config/access.d.cts +5 -2
- package/dist/cjs/config/access.d.ts +5 -2
- package/dist/cjs/config/access.js +34 -14
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.d.cts +4 -1
- package/dist/cjs/config/index.d.ts +4 -1
- package/dist/cjs/config/index.js +12 -2
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.d.cts +6 -1
- package/dist/cjs/config/load.d.ts +6 -1
- package/dist/cjs/config/load.js +87 -15
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/resolve.js +1 -1
- package/dist/cjs/config/resolve.js.map +1 -1
- package/dist/cjs/config/signals.d.cts +4 -0
- package/dist/cjs/config/signals.d.ts +4 -0
- package/dist/cjs/config/signals.js +30 -0
- package/dist/cjs/config/signals.js.map +1 -0
- package/dist/cjs/config/types.d.cts +6 -4
- package/dist/cjs/config/types.d.ts +6 -4
- package/dist/cjs/config/types.js +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js +121 -12
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/db/open.d.cts +1 -1
- package/dist/cjs/db/open.d.ts +1 -1
- package/dist/cjs/db/open.js +10 -3
- package/dist/cjs/db/open.js.map +1 -1
- package/dist/cjs/db/reconcile.d.cts +1 -0
- package/dist/cjs/db/reconcile.d.ts +1 -0
- package/dist/cjs/db/reconcile.js +20 -3
- package/dist/cjs/db/reconcile.js.map +1 -1
- package/dist/cjs/embed/cohere.d.cts +2 -0
- package/dist/cjs/embed/cohere.d.ts +2 -0
- package/dist/cjs/embed/cohere.js +238 -0
- package/dist/cjs/embed/cohere.js.map +1 -0
- package/dist/cjs/embed/http.d.cts +2 -0
- package/dist/cjs/embed/http.d.ts +2 -0
- package/dist/cjs/embed/http.js +258 -0
- package/dist/cjs/embed/http.js.map +1 -0
- package/dist/cjs/embed/identity.d.cts +13 -0
- package/dist/cjs/embed/identity.d.ts +13 -0
- package/dist/cjs/embed/identity.js +194 -0
- package/dist/cjs/embed/identity.js.map +1 -0
- package/dist/cjs/embed/langfit.d.cts +6 -0
- package/dist/cjs/embed/langfit.d.ts +6 -0
- package/dist/cjs/embed/langfit.js +326 -0
- package/dist/cjs/embed/langfit.js.map +1 -0
- package/dist/cjs/embed/languages.d.cts +3 -0
- package/dist/cjs/embed/languages.d.ts +3 -0
- package/dist/cjs/embed/languages.js +98 -0
- package/dist/cjs/embed/languages.js.map +1 -0
- package/dist/cjs/embed/openai.d.cts +2 -0
- package/dist/cjs/embed/openai.d.ts +2 -0
- package/dist/cjs/embed/openai.js +268 -0
- package/dist/cjs/embed/openai.js.map +1 -0
- package/dist/cjs/embed/query.d.cts +21 -0
- package/dist/cjs/embed/query.d.ts +21 -0
- package/dist/cjs/embed/query.js +610 -0
- package/dist/cjs/embed/query.js.map +1 -0
- package/dist/cjs/embed/registry.d.cts +3 -0
- package/dist/cjs/embed/registry.d.ts +3 -0
- package/dist/cjs/embed/registry.js +114 -0
- package/dist/cjs/embed/registry.js.map +1 -0
- package/dist/cjs/embed/static.d.cts +2 -0
- package/dist/cjs/embed/static.d.ts +2 -0
- package/dist/cjs/embed/static.js +367 -0
- package/dist/cjs/embed/static.js.map +1 -0
- package/dist/cjs/embed/store.d.cts +8 -0
- package/dist/cjs/embed/store.d.ts +8 -0
- package/dist/cjs/embed/store.js +498 -0
- package/dist/cjs/embed/store.js.map +1 -0
- package/dist/cjs/embed/types.d.cts +8 -0
- package/dist/cjs/embed/types.d.ts +8 -0
- package/dist/cjs/embed/types.js +7 -0
- package/dist/cjs/embed/types.js.map +1 -0
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js +15 -24
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/embed.d.cts +4 -27
- package/dist/cjs/features/embed.d.ts +4 -27
- package/dist/cjs/features/embed.js +6 -978
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/features/links.js +4 -2
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/rank.js +1 -1
- package/dist/cjs/features/tags.js +4 -2
- package/dist/cjs/features/tags.js.map +1 -1
- package/dist/cjs/fences.js.map +1 -1
- package/dist/cjs/graph.js +5 -3
- package/dist/cjs/graph.js.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/output.d.cts +2 -2
- package/dist/cjs/output.d.ts +2 -2
- package/dist/cjs/output.js +15 -8
- package/dist/cjs/output.js.map +1 -1
- package/dist/cjs/scan.js +13 -8
- package/dist/cjs/scan.js.map +1 -1
- package/dist/cjs/segment.js +67 -14
- package/dist/cjs/segment.js.map +1 -1
- package/dist/cjs/traverse.js +4 -2
- package/dist/cjs/traverse.js.map +1 -1
- package/dist/cjs/watch.js +2 -5
- package/dist/cjs/watch.js.map +1 -1
- package/dist/esm/cli/download.js +9 -8
- package/dist/esm/cli/download.js.map +1 -1
- package/dist/esm/cli/index.d.ts +1 -1
- package/dist/esm/cli/index.js +1 -1
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/init.js +32 -6
- package/dist/esm/cli/init.js.map +1 -1
- package/dist/esm/cli/status.js +36 -8
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/related.js +14 -10
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/search.js +27 -78
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +18 -0
- package/dist/esm/commands/signals.js +78 -0
- package/dist/esm/commands/signals.js.map +1 -0
- package/dist/esm/commands/status.d.ts +2 -2
- package/dist/esm/commands/status.js +2 -2
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/config/access.d.ts +5 -2
- package/dist/esm/config/access.js +31 -12
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.d.ts +4 -1
- package/dist/esm/config/index.js +2 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.d.ts +6 -1
- package/dist/esm/config/load.js +67 -9
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/resolve.js +2 -2
- package/dist/esm/config/resolve.js.map +1 -1
- package/dist/esm/config/signals.d.ts +4 -0
- package/dist/esm/config/signals.js +14 -0
- package/dist/esm/config/signals.js.map +1 -0
- package/dist/esm/config/types.d.ts +6 -4
- package/dist/esm/config/types.js +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js +58 -11
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/db/open.d.ts +1 -1
- package/dist/esm/db/open.js +7 -2
- package/dist/esm/db/open.js.map +1 -1
- package/dist/esm/db/reconcile.d.ts +1 -0
- package/dist/esm/db/reconcile.js +10 -0
- package/dist/esm/db/reconcile.js.map +1 -1
- package/dist/esm/embed/cohere.d.ts +2 -0
- package/dist/esm/embed/cohere.js +46 -0
- package/dist/esm/embed/cohere.js.map +1 -0
- package/dist/esm/embed/http.d.ts +2 -0
- package/dist/esm/embed/http.js +33 -0
- package/dist/esm/embed/http.js.map +1 -0
- package/dist/esm/embed/identity.d.ts +13 -0
- package/dist/esm/embed/identity.js +92 -0
- package/dist/esm/embed/identity.js.map +1 -0
- package/dist/esm/embed/langfit.d.ts +6 -0
- package/dist/esm/embed/langfit.js +44 -0
- package/dist/esm/embed/langfit.js.map +1 -0
- package/dist/esm/embed/languages.d.ts +3 -0
- package/dist/esm/embed/languages.js +80 -0
- package/dist/esm/embed/languages.js.map +1 -0
- package/dist/esm/embed/openai.d.ts +2 -0
- package/dist/esm/embed/openai.js +49 -0
- package/dist/esm/embed/openai.js.map +1 -0
- package/dist/esm/embed/query.d.ts +21 -0
- package/dist/esm/embed/query.js +181 -0
- package/dist/esm/embed/query.js.map +1 -0
- package/dist/esm/embed/registry.d.ts +3 -0
- package/dist/esm/embed/registry.js +45 -0
- package/dist/esm/embed/registry.js.map +1 -0
- package/dist/esm/embed/static.d.ts +2 -0
- package/dist/esm/embed/static.js +72 -0
- package/dist/esm/embed/static.js.map +1 -0
- package/dist/esm/embed/store.d.ts +8 -0
- package/dist/esm/embed/store.js +123 -0
- package/dist/esm/embed/store.js.map +1 -0
- package/dist/esm/embed/types.d.ts +8 -0
- package/dist/esm/embed/types.js +3 -0
- package/dist/esm/embed/types.js.map +1 -0
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.d.ts +4 -27
- package/dist/esm/features/embed.js +0 -346
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/fences.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/output.d.ts +2 -2
- package/dist/esm/output.js +6 -2
- package/dist/esm/output.js.map +1 -1
- package/dist/esm/scan.js +7 -4
- package/dist/esm/scan.js.map +1 -1
- package/dist/esm/segment.js +49 -19
- package/dist/esm/segment.js.map +1 -1
- package/package.json +9 -1
- package/schema.json +14 -7
- package/skills/sense/SKILL.md +21 -5
- package/skills/sense-setup/EXAMPLES.md +6 -6
- package/skills/sense-setup/SKILL.md +6 -4
package/dist/cjs/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output.ts"],"sourcesContent":["// rows -> table (default) | json | csv\n\nexport type Row = Record<string, unknown>;\n\n// map/peek/status/path render structures rather than a row set, so csv has nothing to mean\n// there; the commands that emit rows take RowFormat.\nexport type Format = 'table' | 'json';\nexport type RowFormat = Format | 'csv';\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output is left alone.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\n// RFC 4180, and deliberately not cell(): csv is the format for redirecting a result to a\n// file, so it keeps every character, embedded newlines included. What it cannot carry is\n// NULL vs empty string, or a value's type -- that is what json is for.\nfunction csvField(value: unknown): string {\n const text = value === null || value === undefined ? '' : String(value);\n return /[\"\\r\\n,]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nfunction csvLine(values: unknown[]): string {\n return values.map(csvField).join(',');\n}\n\nfunction warnOversize(bytes: number, rowCount: number): void {\n if (bytes <= OVERSIZE_BYTES) return;\n console.warn(`warning: result is ${Math.round(bytes / 1000)} KB across ${rowCount} row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file`);\n}\n\n// Header names come from a row wherever there is one: a statement's column list keeps\n// duplicates that the row object has already collapsed, so `SELECT a AS x, b AS x` would print\n// b's value under both headers. `columns` is the fallback that labels a 0-row result, and with\n// no rows and no statement (a bounded command that found nothing) csv writes nothing at all --\n// a bare newline would read to a csv parser as one empty record.\nexport function printRows(rows: Row[], format: RowFormat, columns?: string[]): void {\n if (format === 'csv') {\n // Collapsed the same way a row object collapses them, so a statement naming a column\n // twice describes itself identically whether it matched anything or not.\n const names = rows.length > 0 ? Object.keys(rows[0]) : [...new Set(columns ?? [])];\n if (names.length === 0) return;\n const rendered = [csvLine(names), ...rows.map((row) => csvLine(names.map((name) => row[name])))].join('\\n');\n console.log(rendered);\n // Bytes, not code units -- CJK is 3 bytes per character.\n warnOversize(Buffer.byteLength(rendered), rows.length);\n return;\n }\n const rendered = renderRows(rows, format);\n console.log(rendered);\n warnOversize(Buffer.byteLength(rendered), rows.length);\n}\n\n// Streaming counterpart for the one unbounded caller, `sense sql`: rows arrive from an\n// iterator, so a large result is never held here as rows and again as a rendered string.\n// Table buffers by necessity (a column is as wide as its widest cell, which the last row can\n// change); json and csv write row by row. The writes are synchronous, so when stdout is a pipe\n// Node buffers what the reader has not taken yet -- the saving is this module's copies, not\n// the operating system's.\nexport function printRowStream(rows: Iterable<Row>, format: RowFormat, columns: string[]): void {\n const iterator = rows[Symbol.iterator]();\n // One step before any write. FTS5 parses a MATCH expression at step time rather than at\n // prepare time, so a bad search string throws here, with stdout still clean for the error.\n const first = iterator.next();\n const rest: Iterable<Row> = { [Symbol.iterator]: () => iterator };\n\n if (format === 'table') {\n printRows(first.done ? [] : [first.value, ...rest], format, columns);\n return;\n }\n\n let bytes = 0;\n let rowCount = 0;\n const write = (text: string): void => {\n // Bytes, not code units -- CJK is 3 bytes per character.\n bytes += Buffer.byteLength(text);\n process.stdout.write(text);\n };\n\n if (format === 'json') {\n // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one\n // level, comma-joined, inside the array brackets written here.\n // JSON.stringify throws on BigInt, so a row with an int64 past 2^53 (setReadBigInts) is\n // converted via the replacer: a value that fits a safe integer stays a number, a larger one\n // becomes its decimal string, since a JSON number cannot carry it losslessly.\n const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\n const bigintSafe = (_key: string, value: unknown) => (typeof value === 'bigint' ? (value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString()) : value);\n const indent = (row: Row) =>\n JSON.stringify(row, bigintSafe, 2)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n if (first.done) {\n write('[]\\n');\n } else {\n write('[\\n');\n write(indent(first.value));\n rowCount = 1;\n for (const row of rest) {\n write(',\\n');\n write(indent(row));\n rowCount++;\n }\n write('\\n]\\n');\n }\n } else if (first.done) {\n const names = [...new Set(columns)];\n if (names.length > 0) write(`${csvLine(names)}\\n`);\n } else {\n const names = Object.keys(first.value);\n write(`${csvLine(names)}\\n`);\n write(`${csvLine(names.map((name) => first.value[name]))}\\n`);\n rowCount = 1;\n for (const row of rest) {\n write(`${csvLine(names.map((name) => row[name]))}\\n`);\n rowCount++;\n }\n }\n warnOversize(bytes, rowCount);\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\nfunction renderRows(rows: Row[], format: Format, width = process.stdout.columns): string {\n if (format === 'json') return JSON.stringify(rows, null, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const cells = rows.map((row) => columns.map((col) => cell(row[col])));\n const natural = columns.map((col, i) => Math.max(col.length, ...cells.map((row) => row[i].length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...cells.map(formatRow)].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a semantic-off preset says which.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.semantic === false ? ' (semantic: false)' : ''}`)];\n}\n\nexport function renderMap(result: { docs: { count: number; bytes: number }; fields: Row[]; fieldsTotal: number; features: { on: string[]; off: string[] }; presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>; hubs: Row[]; recent: Row[]; recentCaveat: string | null }): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:');\n if (result.recentCaveat) parts.push(result.recentCaveat);\n parts.push(renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: { path: string; tokens: number; frontmatter: Row; parseError?: string | null; sections: Row[]; outbound: string[]; backlinks: string[]; unresolved: string[]; sectionsTotal: number; outboundTotal: number; backlinksTotal: number; unresolvedTotal: number; off: string[] }): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level as number)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRowStream","printRows","renderMap","renderPeek","OVERSIZE_BYTES","cell","value","String","replace","csvField","text","undefined","test","csvLine","values","map","join","warnOversize","bytes","rowCount","console","warn","Math","round","rows","format","columns","names","length","Object","keys","Set","rendered","row","name","log","Buffer","byteLength","renderRows","iterator","Symbol","first","next","rest","done","write","process","stdout","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","bigintSafe","_key","toString","indent","JSON","stringify","split","line","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","width","cells","col","natural","i","clip","w","padEnd","slice","formatRow","trimEnd","repeat","features","off","on","presets","p","files","embedded","semantic","result","parts","docs","count","fields","fieldsTotal","push","hubs","includes","recentCaveat","recent","lines","path","tokens","parseError","entries","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output.ts"],"sourcesContent":["// rows -> table (default) | json | csv\n\nexport type Row = Record<string, unknown>;\n\n// map/peek/status/path render structures rather than a row set, so csv has nothing to mean\n// there; the commands that emit rows take RowFormat.\nexport type Format = 'table' | 'json';\nexport type RowFormat = Format | 'csv';\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output is left alone.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\n// RFC 4180, and deliberately not cell(): csv is the format for redirecting a result to a\n// file, so it keeps every character, embedded newlines included. What it cannot carry is\n// NULL vs empty string, or a value's type -- that is what json is for.\nfunction csvField(value: unknown): string {\n const text = value === null || value === undefined ? '' : String(value);\n return /[\"\\r\\n,]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nfunction csvLine(values: unknown[]): string {\n return values.map(csvField).join(',');\n}\n\nfunction warnOversize(bytes: number, rowCount: number): void {\n if (bytes <= OVERSIZE_BYTES) return;\n console.warn(`warning: result is ${Math.round(bytes / 1000)} KB across ${rowCount} row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file`);\n}\n\n// Header names come from a row wherever there is one: a statement's column list keeps\n// duplicates that the row object has already collapsed, so `SELECT a AS x, b AS x` would print\n// b's value under both headers. `columns` is the fallback that labels a 0-row result, and with\n// no rows and no statement (a bounded command that found nothing) csv writes nothing at all --\n// a bare newline would read to a csv parser as one empty record.\nexport function printRows(rows: Row[], format: RowFormat, columns?: string[]): void {\n if (format === 'csv') {\n // Collapsed the same way a row object collapses them, so a statement naming a column\n // twice describes itself identically whether it matched anything or not.\n const names = rows.length > 0 ? Object.keys(rows[0]) : [...new Set(columns ?? [])];\n if (names.length === 0) return;\n const rendered = [csvLine(names), ...rows.map((row) => csvLine(names.map((name) => row[name])))].join('\\n');\n console.log(rendered);\n // Bytes, not code units -- CJK is 3 bytes per character.\n warnOversize(Buffer.byteLength(rendered), rows.length);\n return;\n }\n const rendered = renderRows(rows, format);\n console.log(rendered);\n warnOversize(Buffer.byteLength(rendered), rows.length);\n}\n\n// Streaming counterpart for the one unbounded caller, `sense sql`: rows arrive from an\n// iterator, so a large result is never held here as rows and again as a rendered string.\n// Table buffers by necessity (a column is as wide as its widest cell, which the last row can\n// change); json and csv write row by row. The writes are synchronous, so when stdout is a pipe\n// Node buffers what the reader has not taken yet -- the saving is this module's copies, not\n// the operating system's.\nexport function printRowStream(rows: Iterable<Row>, format: RowFormat, columns: string[]): void {\n const iterator = rows[Symbol.iterator]();\n // One step before any write. FTS5 parses a MATCH expression at step time rather than at\n // prepare time, so a bad search string throws here, with stdout still clean for the error.\n const first = iterator.next();\n const rest: Iterable<Row> = { [Symbol.iterator]: () => iterator };\n\n if (format === 'table') {\n printRows(first.done ? [] : [first.value, ...rest], format, columns);\n return;\n }\n\n let bytes = 0;\n let rowCount = 0;\n const write = (text: string): void => {\n // Bytes, not code units -- CJK is 3 bytes per character.\n bytes += Buffer.byteLength(text);\n process.stdout.write(text);\n };\n\n if (format === 'json') {\n // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one\n // level, comma-joined, inside the array brackets written here.\n // JSON.stringify throws on BigInt, so a row with an int64 past 2^53 (setReadBigInts) is\n // converted via the replacer: a value that fits a safe integer stays a number, a larger one\n // becomes its decimal string, since a JSON number cannot carry it losslessly.\n const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\n const bigintSafe = (_key: string, value: unknown) => (typeof value === 'bigint' ? (value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString()) : value);\n const indent = (row: Row) =>\n JSON.stringify(row, bigintSafe, 2)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n if (first.done) {\n write('[]\\n');\n } else {\n write('[\\n');\n write(indent(first.value));\n rowCount = 1;\n for (const row of rest) {\n write(',\\n');\n write(indent(row));\n rowCount++;\n }\n write('\\n]\\n');\n }\n } else if (first.done) {\n const names = [...new Set(columns)];\n if (names.length > 0) write(`${csvLine(names)}\\n`);\n } else {\n const names = Object.keys(first.value);\n write(`${csvLine(names)}\\n`);\n write(`${csvLine(names.map((name) => first.value[name]))}\\n`);\n rowCount = 1;\n for (const row of rest) {\n write(`${csvLine(names.map((name) => row[name]))}\\n`);\n rowCount++;\n }\n }\n warnOversize(bytes, rowCount);\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\nfunction renderRows(rows: Row[], format: Format, width = process.stdout.columns): string {\n if (format === 'json') return JSON.stringify(rows, null, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const cells = rows.map((row) => columns.map((col) => cell(row[col])));\n const natural = columns.map((col, i) => Math.max(col.length, ...cells.map((row) => row[i].length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...cells.map(formatRow)].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\n// name, or name:weight when the weight is not the default 1.\nfunction signalLabels(signals: Record<string, number>): string {\n return Object.entries(signals)\n .map(([name, weight]) => (weight === 1 ? name : `${name}:${weight}`))\n .join(', ');\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; signals: Record<string, number> }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a preset without the vectors signal says what it uses instead.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.signals.vectors !== undefined ? '' : ` (signals: ${signalLabels(p.signals)})`}`)];\n}\n\nexport function renderMap(result: {\n docs: { count: number; bytes: number };\n fields: Row[];\n fieldsTotal: number;\n features: { on: string[]; off: string[] };\n presets: Array<{ name: string; files: number; embedded: number; signals: Record<string, number> }>;\n hubs: Row[];\n recent: Row[];\n recentCaveat: string | null;\n}): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:');\n if (result.recentCaveat) parts.push(result.recentCaveat);\n parts.push(renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: { path: string; tokens: number; frontmatter: Row; parseError?: string | null; sections: Row[]; outbound: string[]; backlinks: string[]; unresolved: string[]; sectionsTotal: number; outboundTotal: number; backlinksTotal: number; unresolvedTotal: number; off: string[] }): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level as number)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRowStream","printRows","renderMap","renderPeek","OVERSIZE_BYTES","cell","value","String","replace","csvField","text","undefined","test","csvLine","values","map","join","warnOversize","bytes","rowCount","console","warn","Math","round","rows","format","columns","names","length","Object","keys","Set","rendered","row","name","log","Buffer","byteLength","renderRows","iterator","Symbol","first","next","rest","done","write","process","stdout","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","bigintSafe","_key","toString","indent","JSON","stringify","split","line","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","width","cells","col","natural","i","clip","w","padEnd","slice","formatRow","trimEnd","repeat","features","off","on","signalLabels","signals","entries","weight","presets","p","files","embedded","vectors","result","parts","docs","count","fields","fieldsTotal","push","hubs","includes","recentCaveat","recent","lines","path","tokens","parseError","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
|
package/dist/cjs/scan.js
CHANGED
|
@@ -50,7 +50,9 @@ function _interop_require_default(obj) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
function _iterable_to_array(iter) {
|
|
53
|
-
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null)
|
|
53
|
+
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
54
|
+
return Array.from(iter);
|
|
55
|
+
}
|
|
54
56
|
}
|
|
55
57
|
function _iterable_to_array_limit(arr, i) {
|
|
56
58
|
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
@@ -77,10 +79,10 @@ function _iterable_to_array_limit(arr, i) {
|
|
|
77
79
|
return _arr;
|
|
78
80
|
}
|
|
79
81
|
function _non_iterable_rest() {
|
|
80
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance
|
|
82
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
81
83
|
}
|
|
82
84
|
function _non_iterable_spread() {
|
|
83
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance
|
|
85
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
84
86
|
}
|
|
85
87
|
function _sliced_to_array(arr, i) {
|
|
86
88
|
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
@@ -128,7 +130,10 @@ function normalizeText(value) {
|
|
|
128
130
|
// carry high IDF, so they outrank prose. remove-markdown misses wikilinks and tables.
|
|
129
131
|
function stripText(value) {
|
|
130
132
|
var withoutWikilinks = value.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, '$2').replace(/\[\[([^\]]+)\]\]/g, '$1');
|
|
131
|
-
|
|
133
|
+
// remove-markdown deletes footnote definitions wholesale ("[^1]: text" -> ""), so unwrap
|
|
134
|
+
// them (and drop inline refs) before it runs; the definition text stays indexed.
|
|
135
|
+
var withoutFootnotes = withoutWikilinks.replace(/^\[\^[^\]]+\]:[ \t]?/gm, '').replace(/\[\^[^\]]+\]/g, '');
|
|
136
|
+
var withoutMarkdown = (0, _removemarkdown.default)(withoutFootnotes);
|
|
132
137
|
var withoutTables = withoutMarkdown.replace(/^\s*\|?[-\s|:]+\|\s*$/gm, '').replace(/\|/g, ' ');
|
|
133
138
|
return normalizeText(withoutTables);
|
|
134
139
|
}
|
|
@@ -194,8 +199,8 @@ function listFiles(cfg, baseDir) {
|
|
|
194
199
|
}
|
|
195
200
|
// Which presets want vectors is a property of the config, not of any file.
|
|
196
201
|
var embedding = (0, _indexts.embedEnabled)(cfg);
|
|
197
|
-
var
|
|
198
|
-
return (0, _indexts.
|
|
202
|
+
var vectorPresets = embedding ? new Set((0, _indexts.presetNames)(cfg).filter(function(name) {
|
|
203
|
+
return (0, _indexts.presetHasSignal)(cfg, name, 'vectors');
|
|
199
204
|
})) : null;
|
|
200
205
|
var files = [];
|
|
201
206
|
var _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
|
|
@@ -208,8 +213,8 @@ function listFiles(cfg, baseDir) {
|
|
|
208
213
|
var st = (0, _nodefs.statSync)(absPath, NO_THROW);
|
|
209
214
|
if (!(st === null || st === void 0 ? void 0 : st.isFile())) continue;
|
|
210
215
|
var presets = _to_consumable_array(coverage.get(relPath1)).sort();
|
|
211
|
-
var embed =
|
|
212
|
-
return
|
|
216
|
+
var embed = vectorPresets !== null && presets.some(function(name) {
|
|
217
|
+
return vectorPresets.has(name);
|
|
213
218
|
});
|
|
214
219
|
files.push({
|
|
215
220
|
relPath: relPath1,
|
package/dist/cjs/scan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan.ts"],"sourcesContent":["import { globSync, readFileSync, statSync } from 'node:fs';\nimport { join, sep } from 'node:path';\nimport removeMarkdown from 'remove-markdown';\nimport { isCollection, parseDocument, visit } from 'yaml';\nimport type { Config } from './config/index.ts';\nimport { embedEnabled, presetNames, presetSemanticEnabled } from './config/index.ts';\nimport type { Feature } from './features/types.ts';\n\n// Filesystem -> rows. Pure data in, data + warnings out; db.ts does the SQL.\n\n// Frontmatter keys that would collide with table columns. Exported so db.ts's upsert can tell\n// a feature-owned column (`_rank`) from a parsed one and leave it alone on reparse.\nexport const RESERVED_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_rank', '_parse_error', 'content', 'links', 'sections']);\n\n// YAML error codes whose recovery is unambiguous, so the parse is accepted rather than\n// quarantined. Only one qualifies: YAML 1.2 reserves `@` and `` ` `` at the start of a plain\n// scalar for future use, so they can never be valid and the text can only be what was typed\n// (`aliases: [@handle]` -> [\"@handle\"]). Every other code has a second reading -- an unquoted\n// `:` swallows the keys after it, an unquoted `[..](..)` drops the URL, a duplicate key picks\n// one value in silence -- so it writes values nobody wrote.\nconst ACCEPTED_YAML_CODES = new Set(['BAD_SCALAR_START']);\n\nfunction normalizeText(value: unknown): string {\n if (value === null || value === undefined) return '';\n return String(value).replace(/\\s+/g, ' ').trim();\n}\n\n// Keeps URL query strings, asset filenames, and HTML attributes out of the index: rare terms\n// carry high IDF, so they outrank prose. remove-markdown misses wikilinks and tables.\nfunction stripText(value: string): string {\n const withoutWikilinks = value.replace(/\\[\\[([^\\]|]+)\\|([^\\]]+)\\]\\]/g, '$2').replace(/\\[\\[([^\\]]+)\\]\\]/g, '$1');\n const withoutMarkdown = removeMarkdown(withoutWikilinks);\n const withoutTables = withoutMarkdown.replace(/^\\s*\\|?[-\\s|:]+\\|\\s*$/gm, '').replace(/\\|/g, ' ');\n return normalizeText(withoutTables);\n}\n\nexport interface FileStat {\n relPath: string;\n absPath: string;\n mtimeMs: number;\n ctimeMs: number; // filesystem birthtime; a clone or copy resets it, like _mtime\n size: number;\n presets: string[]; // every declared preset covering this file (>= 1; union, overlap allowed)\n embed: boolean; // true iff a model is named and some covering preset has semantic on\n}\n\n// Presets are views, not partitions: they overlap freely, and a file's covering set (not one\n// owner) drives indexing. Globs resolve relative to baseDir; unmatched files are not indexed.\nexport function toPosixPath(relPath: string, separator: string = sep): string {\n return separator === '\\\\' ? relPath.split(separator).join('/') : relPath;\n}\n\n// Every command pays listFiles before it answers (the freshness check stats each file), so\n// per-file work here is the hottest path in the package. Everything derivable from the config\n// alone is computed once, above the loop.\nconst NO_THROW = { throwIfNoEntry: false } as const;\n\nexport function listFiles(cfg: Config, baseDir: string): FileStat[] {\n const coverage = new Map<string, Set<string>>();\n const posixNeeded = sep === '\\\\';\n for (const name of presetNames(cfg)) {\n const preset = cfg.presets[name];\n for (const matched of globSync(preset.include, { cwd: baseDir, exclude: preset.exclude })) {\n const relPath = posixNeeded ? toPosixPath(matched) : matched;\n const set = coverage.get(relPath) ?? new Set<string>();\n set.add(name);\n coverage.set(relPath, set);\n }\n }\n\n // Which presets want vectors is a property of the config, not of any file.\n const embedding = embedEnabled(cfg);\n const semanticPresets = embedding ? new Set(presetNames(cfg).filter((name) => presetSemanticEnabled(cfg, name))) : null;\n\n const files: FileStat[] = [];\n for (const relPath of [...coverage.keys()].sort()) {\n const absPath = join(baseDir, relPath); // join re-applies the platform separator for fs calls\n // node:fs glob matches directories and dangling symlinks; fast-glob returned neither, so\n // one stat filters both back out (throwIfNoEntry keeps a dangling link from throwing).\n const st = statSync(absPath, NO_THROW);\n if (!st?.isFile()) continue;\n const presets = [...(coverage.get(relPath) as Set<string>)].sort();\n const embed = semanticPresets !== null && presets.some((name) => semanticPresets.has(name));\n files.push({ relPath, absPath, mtimeMs: st.mtimeMs, ctimeMs: st.birthtimeMs, size: st.size, presets, embed });\n }\n return files;\n}\n\nexport interface ParsedDoc {\n relPath: string;\n mtimeMs: number;\n ctimeMs: number;\n size: number;\n presets: string[];\n data: Record<string, string | number | bigint | null>;\n // NULL when the frontmatter parsed, the first YAML message otherwise. In the row rather than\n // a side table so `SELECT *` and any `IS NULL` investigation trip over it without being asked.\n parseError: string | null;\n // title/summary are duplicated from frontmatter so bm25() can weight them above the body text.\n search: { title: string; summary: string; text: string };\n // Per-feature extraction results, keyed by feature name; features store them at reconcile.\n extracted: Record<string, unknown>;\n}\n\n// SQLite's datetime() rejects a colonless offset (`-0800`) and a space separator, which ISO 8601\n// allows and producers emit. A rejected date is invisible, not excluded: every comparison is NULL.\nconst ISO_DATETIME = /^(\\d{4}-\\d{2}-\\d{2})[T ](\\d{2}:\\d{2}(?::\\d{2})?(?:\\.\\d+)?)(Z|[+-]\\d{2}(?::?\\d{2})?)?$/;\n\n// A value opening `YYYY-MM-DDT` was meant to be a datetime; prose never is. Reported when it\n// cannot be normalized, so a typo surfaces on the next crawl instead of at some later audit.\nconst MEANT_AS_DATETIME = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d/;\n\nexport function looksLikeDatetime(value: string): boolean {\n return MEANT_AS_DATETIME.test(value);\n}\n\n// Punctuation only, never a timezone conversion: the offset survives, so substr(d,1,10) is still\n// the local date. A shape that is not a real instant is left as written, and stays auditable.\nexport function normalizeDate(value: string): string {\n const m = ISO_DATETIME.exec(value);\n if (m === null) return value;\n const [, date, time, zone] = m;\n const digits = zone === undefined || zone === 'Z' ? '' : zone.replace(':', '');\n const offset = digits === '' ? (zone ?? '') : digits.length === 3 ? `${digits}:00` : `${digits.slice(0, 3)}:${digits.slice(3)}`;\n const normalized = `${date}T${time}${offset}`;\n return Number.isNaN(Date.parse(normalized)) ? value : normalized;\n}\n\n// Storage class follows the YAML scalar. Booleans store as 1/0, so `WHERE flag = 1` matches\n// and `WHERE flag = 'true'` cannot; `map` prints observed types so the mismatch is visible.\nfunction mapValue(value: unknown): string | number | bigint | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return BigInt(value ? 1 : 0);\n if (typeof value === 'number') return Number.isSafeInteger(value) ? BigInt(value) : value;\n if (typeof value === 'string') return normalizeDate(value);\n return JSON.stringify(value);\n}\n\n// The delimiter split is all this package used gray-matter for.\nfunction splitFrontmatter(raw: string): { fm: string | null; body: string } {\n const open = raw.match(/^---\\r?\\n/);\n if (!open) return { fm: null, body: raw };\n const rest = raw.slice(open[0].length);\n const close = rest.match(/^---\\r?(\\n|$)/m);\n if (!close || close.index === undefined) return { fm: null, body: raw };\n return { fm: rest.slice(0, close.index), body: rest.slice(close.index + close[0].length) };\n}\n\n// A well-formed document can still hold a value nobody meant: `created: {{date}}` is valid\n// YAML for a flow map used as a mapping key, so it raises no error and stores\n// {\"{ date }\": null}. No error code can catch that, but yaml notices the stringified key, so\n// this reports it with the path instead (yaml's own warning has none, fires once per document,\n// and is what trains readers to discard stderr).\nfunction warnStringifiedKeys(relPath: string, doc: ReturnType<typeof parseDocument>, warnings: string[]): void {\n let found = false;\n // Nested, not top level: `created: {{date}}` puts the collection key one level down, inside\n // the flow map that `{{...}}` parses as.\n visit(doc, {\n Pair(_key, pair) {\n if (!isCollection(pair.key)) return undefined;\n found = true;\n return visit.BREAK;\n },\n });\n // One per file: a template repeats the same mistake on every field it stamps.\n if (found) warnings.push(`warning: ${relPath} frontmatter has a key that is itself a list or mapping, stored as text; this is usually an unrendered template placeholder like {{date}}`);\n}\n\n// Accept a clean parse, and one whose every error is unambiguous (ACCEPTED_YAML_CODES).\n// Anything else is quarantined: no frontmatter columns at all, and `_parse_error` carries the\n// reason. Recovering it would write values nobody wrote, which is worse than absence because\n// no query can see it. The file is still indexed -- content, links and sections never touch\n// frontmatter -- so a broken note stays searchable while it is being hunted for.\n// yaml's message continues onto a source excerpt, so the first line is the sentence -- minus\n// the colon that introduced the part being dropped.\nfunction firstLine(message: string): string {\n return message.split('\\n')[0].replace(/:\\s*$/, '');\n}\n\nfunction parseFrontmatter(relPath: string, fm: string, warnings: string[]): { data: Record<string, unknown>; parseError: string | null } {\n // logLevel silences yaml's own pathless warnings; warnStringifiedKeys re-reports the one\n // that carries information, with the file it came from.\n const doc = parseDocument(fm, { logLevel: 'silent' });\n const refused = doc.errors.filter((err) => !ACCEPTED_YAML_CODES.has(err.code));\n if (refused.length > 0) {\n const detail = refused.length > 1 ? ` (and ${refused.length - 1} more)` : '';\n const parseError = `${firstLine(refused[0].message)}${detail}`;\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n let data: unknown;\n try {\n data = doc.toJS();\n } catch (err) {\n // Reaches here with doc.errors empty: `title: **Bold**` parses, then opens an alias on\n // materialisation. An empty error list is not a successful parse.\n const parseError = firstLine((err as Error).message);\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n if (data === null || data === undefined) return { data: {}, parseError: null };\n if (typeof data !== 'object' || Array.isArray(data)) {\n const parseError = 'frontmatter is not a key-value mapping';\n warnings.push(`warning: ${relPath} ${parseError}; none of it is indexed`);\n return { data: {}, parseError };\n }\n warnStringifiedKeys(relPath, doc, warnings);\n return { data: data as Record<string, unknown>, parseError: null };\n}\n\nexport function parseFile(file: FileStat, extractors: Feature[] = []): { doc: ParsedDoc; warnings: string[] } {\n const raw = readFileSync(file.absPath, 'utf8');\n const warnings: string[] = [];\n\n const { fm, body: content } = splitFrontmatter(raw);\n const { data, parseError } = fm === null ? { data: {} as Record<string, unknown>, parseError: null } : parseFrontmatter(file.relPath, fm, warnings);\n const mapped: Record<string, string | number | bigint | null> = {};\n\n for (const key of Object.keys(data)) {\n if (RESERVED_COLUMNS.has(key)) {\n warnings.push(`warning: ${file.relPath} has a frontmatter key named \"${key}\", which is reserved; ignoring it`);\n continue;\n }\n const value = mapValue(data[key]);\n if (typeof value === 'string' && looksLikeDatetime(value) && Number.isNaN(Date.parse(value))) {\n warnings.push(`warning: ${file.relPath}: ${key} is not a valid date (${value}), so it is invisible to every date comparison`);\n }\n mapped[key] = value;\n }\n\n // title/summary are plain YAML strings -- whitespace-collapse only;\n // the prose gets the full markdown strip.\n const search = { title: normalizeText(data.title), summary: normalizeText(data.summary), text: stripText(content) };\n\n return {\n doc: {\n relPath: file.relPath,\n mtimeMs: file.mtimeMs,\n ctimeMs: file.ctimeMs,\n size: file.size,\n presets: file.presets,\n data: mapped,\n parseError,\n search,\n extracted: Object.fromEntries(extractors.filter((f) => f.extract).map((f) => [f.name, f.extract?.(raw, content, search, data)])),\n },\n warnings,\n };\n}\n"],"names":["RESERVED_COLUMNS","listFiles","looksLikeDatetime","normalizeDate","parseFile","toPosixPath","Set","ACCEPTED_YAML_CODES","normalizeText","value","undefined","String","replace","trim","stripText","withoutWikilinks","withoutMarkdown","removeMarkdown","withoutTables","relPath","separator","sep","split","join","NO_THROW","throwIfNoEntry","cfg","baseDir","coverage","Map","posixNeeded","presetNames","name","preset","presets","globSync","include","cwd","exclude","matched","set","get","add","embedding","embedEnabled","semanticPresets","filter","presetSemanticEnabled","files","keys","sort","absPath","st","statSync","isFile","embed","some","has","push","mtimeMs","ctimeMs","birthtimeMs","size","ISO_DATETIME","MEANT_AS_DATETIME","test","m","exec","date","time","zone","digits","offset","length","slice","normalized","Number","isNaN","Date","parse","mapValue","BigInt","isSafeInteger","JSON","stringify","splitFrontmatter","raw","open","match","fm","body","rest","close","index","warnStringifiedKeys","doc","warnings","found","visit","Pair","_key","pair","isCollection","key","BREAK","firstLine","message","parseFrontmatter","parseDocument","logLevel","refused","errors","err","code","detail","parseError","data","toJS","Array","isArray","file","extractors","readFileSync","content","mapped","Object","search","title","summary","text","extracted","fromEntries","f","extract","map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan.ts"],"sourcesContent":["import { globSync, readFileSync, statSync } from 'node:fs';\nimport { join, sep } from 'node:path';\nimport removeMarkdown from 'remove-markdown';\nimport { isCollection, parseDocument, visit } from 'yaml';\nimport type { Config } from './config/index.ts';\nimport { embedEnabled, presetHasSignal, presetNames } from './config/index.ts';\nimport type { Feature } from './features/types.ts';\n\n// Filesystem -> rows. Pure data in, data + warnings out; db.ts does the SQL.\n\n// Frontmatter keys that would collide with table columns. Exported so db.ts's upsert can tell\n// a feature-owned column (`_rank`) from a parsed one and leave it alone on reparse.\nexport const RESERVED_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_rank', '_parse_error', 'content', 'links', 'sections']);\n\n// YAML error codes whose recovery is unambiguous, so the parse is accepted rather than\n// quarantined. Only one qualifies: YAML 1.2 reserves `@` and `` ` `` at the start of a plain\n// scalar for future use, so they can never be valid and the text can only be what was typed\n// (`aliases: [@handle]` -> [\"@handle\"]). Every other code has a second reading -- an unquoted\n// `:` swallows the keys after it, an unquoted `[..](..)` drops the URL, a duplicate key picks\n// one value in silence -- so it writes values nobody wrote.\nconst ACCEPTED_YAML_CODES = new Set(['BAD_SCALAR_START']);\n\nfunction normalizeText(value: unknown): string {\n if (value === null || value === undefined) return '';\n return String(value).replace(/\\s+/g, ' ').trim();\n}\n\n// Keeps URL query strings, asset filenames, and HTML attributes out of the index: rare terms\n// carry high IDF, so they outrank prose. remove-markdown misses wikilinks and tables.\nfunction stripText(value: string): string {\n const withoutWikilinks = value.replace(/\\[\\[([^\\]|]+)\\|([^\\]]+)\\]\\]/g, '$2').replace(/\\[\\[([^\\]]+)\\]\\]/g, '$1');\n // remove-markdown deletes footnote definitions wholesale (\"[^1]: text\" -> \"\"), so unwrap\n // them (and drop inline refs) before it runs; the definition text stays indexed.\n const withoutFootnotes = withoutWikilinks.replace(/^\\[\\^[^\\]]+\\]:[ \\t]?/gm, '').replace(/\\[\\^[^\\]]+\\]/g, '');\n const withoutMarkdown = removeMarkdown(withoutFootnotes);\n const withoutTables = withoutMarkdown.replace(/^\\s*\\|?[-\\s|:]+\\|\\s*$/gm, '').replace(/\\|/g, ' ');\n return normalizeText(withoutTables);\n}\n\nexport interface FileStat {\n relPath: string;\n absPath: string;\n mtimeMs: number;\n ctimeMs: number; // filesystem birthtime; a clone or copy resets it, like _mtime\n size: number;\n presets: string[]; // every declared preset covering this file (>= 1; union, overlap allowed)\n embed: boolean; // true iff a model is named and some covering preset's signals include vectors\n}\n\n// Presets are views, not partitions: they overlap freely, and a file's covering set (not one\n// owner) drives indexing. Globs resolve relative to baseDir; unmatched files are not indexed.\nexport function toPosixPath(relPath: string, separator: string = sep): string {\n return separator === '\\\\' ? relPath.split(separator).join('/') : relPath;\n}\n\n// Every command pays listFiles before it answers (the freshness check stats each file), so\n// per-file work here is the hottest path in the package. Everything derivable from the config\n// alone is computed once, above the loop.\nconst NO_THROW = { throwIfNoEntry: false } as const;\n\nexport function listFiles(cfg: Config, baseDir: string): FileStat[] {\n const coverage = new Map<string, Set<string>>();\n const posixNeeded = sep === '\\\\';\n for (const name of presetNames(cfg)) {\n const preset = cfg.presets[name];\n for (const matched of globSync(preset.include, { cwd: baseDir, exclude: preset.exclude })) {\n const relPath = posixNeeded ? toPosixPath(matched) : matched;\n const set = coverage.get(relPath) ?? new Set<string>();\n set.add(name);\n coverage.set(relPath, set);\n }\n }\n\n // Which presets want vectors is a property of the config, not of any file.\n const embedding = embedEnabled(cfg);\n const vectorPresets = embedding ? new Set(presetNames(cfg).filter((name) => presetHasSignal(cfg, name, 'vectors'))) : null;\n\n const files: FileStat[] = [];\n for (const relPath of [...coverage.keys()].sort()) {\n const absPath = join(baseDir, relPath); // join re-applies the platform separator for fs calls\n // node:fs glob matches directories and dangling symlinks; fast-glob returned neither, so\n // one stat filters both back out (throwIfNoEntry keeps a dangling link from throwing).\n const st = statSync(absPath, NO_THROW);\n if (!st?.isFile()) continue;\n const presets = [...(coverage.get(relPath) as Set<string>)].sort();\n const embed = vectorPresets !== null && presets.some((name) => vectorPresets.has(name));\n files.push({ relPath, absPath, mtimeMs: st.mtimeMs, ctimeMs: st.birthtimeMs, size: st.size, presets, embed });\n }\n return files;\n}\n\nexport interface ParsedDoc {\n relPath: string;\n mtimeMs: number;\n ctimeMs: number;\n size: number;\n presets: string[];\n data: Record<string, string | number | bigint | null>;\n // NULL when the frontmatter parsed, the first YAML message otherwise. In the row rather than\n // a side table so `SELECT *` and any `IS NULL` investigation trip over it without being asked.\n parseError: string | null;\n // title/summary are duplicated from frontmatter so bm25() can weight them above the body text.\n search: { title: string; summary: string; text: string };\n // Per-feature extraction results, keyed by feature name; features store them at reconcile.\n extracted: Record<string, unknown>;\n}\n\n// SQLite's datetime() rejects a colonless offset (`-0800`) and a space separator, which ISO 8601\n// allows and producers emit. A rejected date is invisible, not excluded: every comparison is NULL.\nconst ISO_DATETIME = /^(\\d{4}-\\d{2}-\\d{2})[T ](\\d{2}:\\d{2}(?::\\d{2})?(?:\\.\\d+)?)(Z|[+-]\\d{2}(?::?\\d{2})?)?$/;\n\n// A value opening `YYYY-MM-DDT` was meant to be a datetime; prose never is. Reported when it\n// cannot be normalized, so a typo surfaces on the next crawl instead of at some later audit.\nconst MEANT_AS_DATETIME = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d/;\n\nexport function looksLikeDatetime(value: string): boolean {\n return MEANT_AS_DATETIME.test(value);\n}\n\n// Punctuation only, never a timezone conversion: the offset survives, so substr(d,1,10) is still\n// the local date. A shape that is not a real instant is left as written, and stays auditable.\nexport function normalizeDate(value: string): string {\n const m = ISO_DATETIME.exec(value);\n if (m === null) return value;\n const [, date, time, zone] = m;\n const digits = zone === undefined || zone === 'Z' ? '' : zone.replace(':', '');\n const offset = digits === '' ? (zone ?? '') : digits.length === 3 ? `${digits}:00` : `${digits.slice(0, 3)}:${digits.slice(3)}`;\n const normalized = `${date}T${time}${offset}`;\n return Number.isNaN(Date.parse(normalized)) ? value : normalized;\n}\n\n// Storage class follows the YAML scalar. Booleans store as 1/0, so `WHERE flag = 1` matches\n// and `WHERE flag = 'true'` cannot; `map` prints observed types so the mismatch is visible.\nfunction mapValue(value: unknown): string | number | bigint | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return BigInt(value ? 1 : 0);\n if (typeof value === 'number') return Number.isSafeInteger(value) ? BigInt(value) : value;\n if (typeof value === 'string') return normalizeDate(value);\n return JSON.stringify(value);\n}\n\n// The delimiter split is all this package used gray-matter for.\nfunction splitFrontmatter(raw: string): { fm: string | null; body: string } {\n const open = raw.match(/^---\\r?\\n/);\n if (!open) return { fm: null, body: raw };\n const rest = raw.slice(open[0].length);\n const close = rest.match(/^---\\r?(\\n|$)/m);\n if (!close || close.index === undefined) return { fm: null, body: raw };\n return { fm: rest.slice(0, close.index), body: rest.slice(close.index + close[0].length) };\n}\n\n// A well-formed document can still hold a value nobody meant: `created: {{date}}` is valid\n// YAML for a flow map used as a mapping key, so it raises no error and stores\n// {\"{ date }\": null}. No error code can catch that, but yaml notices the stringified key, so\n// this reports it with the path instead (yaml's own warning has none, fires once per document,\n// and is what trains readers to discard stderr).\nfunction warnStringifiedKeys(relPath: string, doc: ReturnType<typeof parseDocument>, warnings: string[]): void {\n let found = false;\n // Nested, not top level: `created: {{date}}` puts the collection key one level down, inside\n // the flow map that `{{...}}` parses as.\n visit(doc, {\n Pair(_key, pair) {\n if (!isCollection(pair.key)) return undefined;\n found = true;\n return visit.BREAK;\n },\n });\n // One per file: a template repeats the same mistake on every field it stamps.\n if (found) warnings.push(`warning: ${relPath} frontmatter has a key that is itself a list or mapping, stored as text; this is usually an unrendered template placeholder like {{date}}`);\n}\n\n// Accept a clean parse, and one whose every error is unambiguous (ACCEPTED_YAML_CODES).\n// Anything else is quarantined: no frontmatter columns at all, and `_parse_error` carries the\n// reason. Recovering it would write values nobody wrote, which is worse than absence because\n// no query can see it. The file is still indexed -- content, links and sections never touch\n// frontmatter -- so a broken note stays searchable while it is being hunted for.\n// yaml's message continues onto a source excerpt, so the first line is the sentence -- minus\n// the colon that introduced the part being dropped.\nfunction firstLine(message: string): string {\n return message.split('\\n')[0].replace(/:\\s*$/, '');\n}\n\nfunction parseFrontmatter(relPath: string, fm: string, warnings: string[]): { data: Record<string, unknown>; parseError: string | null } {\n // logLevel silences yaml's own pathless warnings; warnStringifiedKeys re-reports the one\n // that carries information, with the file it came from.\n const doc = parseDocument(fm, { logLevel: 'silent' });\n const refused = doc.errors.filter((err) => !ACCEPTED_YAML_CODES.has(err.code));\n if (refused.length > 0) {\n const detail = refused.length > 1 ? ` (and ${refused.length - 1} more)` : '';\n const parseError = `${firstLine(refused[0].message)}${detail}`;\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n let data: unknown;\n try {\n data = doc.toJS();\n } catch (err) {\n // Reaches here with doc.errors empty: `title: **Bold**` parses, then opens an alias on\n // materialisation. An empty error list is not a successful parse.\n const parseError = firstLine((err as Error).message);\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n if (data === null || data === undefined) return { data: {}, parseError: null };\n if (typeof data !== 'object' || Array.isArray(data)) {\n const parseError = 'frontmatter is not a key-value mapping';\n warnings.push(`warning: ${relPath} ${parseError}; none of it is indexed`);\n return { data: {}, parseError };\n }\n warnStringifiedKeys(relPath, doc, warnings);\n return { data: data as Record<string, unknown>, parseError: null };\n}\n\nexport function parseFile(file: FileStat, extractors: Feature[] = []): { doc: ParsedDoc; warnings: string[] } {\n const raw = readFileSync(file.absPath, 'utf8');\n const warnings: string[] = [];\n\n const { fm, body: content } = splitFrontmatter(raw);\n const { data, parseError } = fm === null ? { data: {} as Record<string, unknown>, parseError: null } : parseFrontmatter(file.relPath, fm, warnings);\n const mapped: Record<string, string | number | bigint | null> = {};\n\n for (const key of Object.keys(data)) {\n if (RESERVED_COLUMNS.has(key)) {\n warnings.push(`warning: ${file.relPath} has a frontmatter key named \"${key}\", which is reserved; ignoring it`);\n continue;\n }\n const value = mapValue(data[key]);\n if (typeof value === 'string' && looksLikeDatetime(value) && Number.isNaN(Date.parse(value))) {\n warnings.push(`warning: ${file.relPath}: ${key} is not a valid date (${value}), so it is invisible to every date comparison`);\n }\n mapped[key] = value;\n }\n\n // title/summary are plain YAML strings -- whitespace-collapse only;\n // the prose gets the full markdown strip.\n const search = { title: normalizeText(data.title), summary: normalizeText(data.summary), text: stripText(content) };\n\n return {\n doc: {\n relPath: file.relPath,\n mtimeMs: file.mtimeMs,\n ctimeMs: file.ctimeMs,\n size: file.size,\n presets: file.presets,\n data: mapped,\n parseError,\n search,\n extracted: Object.fromEntries(extractors.filter((f) => f.extract).map((f) => [f.name, f.extract?.(raw, content, search, data)])),\n },\n warnings,\n };\n}\n"],"names":["RESERVED_COLUMNS","listFiles","looksLikeDatetime","normalizeDate","parseFile","toPosixPath","Set","ACCEPTED_YAML_CODES","normalizeText","value","undefined","String","replace","trim","stripText","withoutWikilinks","withoutFootnotes","withoutMarkdown","removeMarkdown","withoutTables","relPath","separator","sep","split","join","NO_THROW","throwIfNoEntry","cfg","baseDir","coverage","Map","posixNeeded","presetNames","name","preset","presets","globSync","include","cwd","exclude","matched","set","get","add","embedding","embedEnabled","vectorPresets","filter","presetHasSignal","files","keys","sort","absPath","st","statSync","isFile","embed","some","has","push","mtimeMs","ctimeMs","birthtimeMs","size","ISO_DATETIME","MEANT_AS_DATETIME","test","m","exec","date","time","zone","digits","offset","length","slice","normalized","Number","isNaN","Date","parse","mapValue","BigInt","isSafeInteger","JSON","stringify","splitFrontmatter","raw","open","match","fm","body","rest","close","index","warnStringifiedKeys","doc","warnings","found","visit","Pair","_key","pair","isCollection","key","BREAK","firstLine","message","parseFrontmatter","parseDocument","logLevel","refused","errors","err","code","detail","parseError","data","toJS","Array","isArray","file","extractors","readFileSync","content","mapped","Object","search","title","summary","text","extracted","fromEntries","f","extract","map"],"mappings":"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"}
|
package/dist/cjs/segment.js
CHANGED
|
@@ -21,9 +21,10 @@ _export(exports, {
|
|
|
21
21
|
// Segmentation is context-free: seg(query) appears inside seg(document) whenever the query is
|
|
22
22
|
// a substring of the document. That is the contract -- substring semantics, what `grep` and
|
|
23
23
|
// `LIKE '%..%'` give -- and it is what makes index and query agree on every input, always.
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
24
|
+
// Intl.Segmenter's word mode is context-dependent (`东京都政府` splits as `东 | 京都 | 政府`
|
|
25
|
+
// while the query `东京` splits as one word) and is rejected for that reason. Its grapheme
|
|
26
|
+
// mode has no such dependency -- UAX #29 cluster boundaries never look past adjacent
|
|
27
|
+
// characters -- so grapheme mode is used below; no dictionary, no word mode.
|
|
27
28
|
// Scripts written without word spaces: a closed set of writing systems.
|
|
28
29
|
// Script_Extensions, not Script: the katakana long-vowel mark ー is Script=Common.
|
|
29
30
|
var SCRIPTS = '\\p{scx=Han}\\p{scx=Hiragana}\\p{scx=Katakana}\\p{scx=Thai}\\p{scx=Khmer}\\p{scx=Lao}\\p{scx=Myanmar}';
|
|
@@ -31,25 +32,79 @@ var SCRIPTS = '\\p{scx=Han}\\p{scx=Hiragana}\\p{scx=Katakana}\\p{scx=Thai}\\p{sc
|
|
|
31
32
|
// Latin letter (decomposed é) never starts one.
|
|
32
33
|
var RUN = new RegExp("((?:[".concat(SCRIPTS, "]\\p{M}*)+)"), 'gu');
|
|
33
34
|
var HAS_RUN = new RegExp("[".concat(SCRIPTS, "]"), 'u');
|
|
34
|
-
// Grapheme
|
|
35
|
-
var GRAPHEME = RegExp("([^\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1-\\u05C2\\u05C4-\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7-\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u07FD\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u0897-\\u089F\\u08CA-\\u08E1\\u08E3-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962-\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7-\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2-\\u09E3\\u09FE\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47-\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70-\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2-\\u0AE3\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47-\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B62-\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C00-\\u0C04\\u0C3C\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55-\\u0C56\\u0C62-\\u0C63\\u0C81-\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5-\\u0CD6\\u0CE2-\\u0CE3\\u0CF3\\u0D00-\\u0D03\\u0D3B-\\u0D3C\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62-\\u0D63\\u0D81-\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2-\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EBC\\u0EC8-\\u0ECE\\u0F18-\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E-\\u0F3F\\u0F71-\\u0F84\\u0F86-\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1715\\u1732-\\u1734\\u1752-\\u1753\\u1772-\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u180F\\u1885-\\u1886\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1AB0-\\u1ADD\\u1AE0-\\u1AEB\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF4\\u1CF7-\\u1CF9\\u1DC0-\\u1DFF\\u20D0-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099-\\u309A\\uA66F-\\uA672\\uA674-\\uA67D\\uA69E-\\uA69F\\uA6F0-\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA82C\\uA880-\\uA881\\uA8B4-\\uA8C5\\uA8E0-\\uA8F1\\uA8FF\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uA9E5\\uAA29-\\uAA36\\uAA43\\uAA4C-\\uAA4D\\uAA7B-\\uAA7D\\uAAB0\\uAAB2-\\uAAB4\\uAAB7-\\uAAB8\\uAABE-\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5-\\uAAF6\\uABE3-\\uABEA\\uABEC-\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\u{101FD}\\u{102E0}\\u{10376}-\\u{1037A}\\u{10A01}-\\u{10A03}\\u{10A05}-\\u{10A06}\\u{10A0C}-\\u{10A0F}\\u{10A38}-\\u{10A3A}\\u{10A3F}\\u{10AE5}-\\u{10AE6}\\u{10D24}-\\u{10D27}\\u{10D69}-\\u{10D6D}\\u{10EAB}-\\u{10EAC}\\u{10EFA}-\\u{10EFF}\\u{10F46}-\\u{10F50}\\u{10F82}-\\u{10F85}\\u{11000}-\\u{11002}\\u{11038}-\\u{11046}\\u{11070}\\u{11073}-\\u{11074}\\u{1107F}-\\u{11082}\\u{110B0}-\\u{110BA}\\u{110C2}\\u{11100}-\\u{11102}\\u{11127}-\\u{11134}\\u{11145}-\\u{11146}\\u{11173}\\u{11180}-\\u{11182}\\u{111B3}-\\u{111C0}\\u{111C9}-\\u{111CC}\\u{111CE}-\\u{111CF}\\u{1122C}-\\u{11237}\\u{1123E}\\u{11241}\\u{112DF}-\\u{112EA}\\u{11300}-\\u{11303}\\u{1133B}-\\u{1133C}\\u{1133E}-\\u{11344}\\u{11347}-\\u{11348}\\u{1134B}-\\u{1134D}\\u{11357}\\u{11362}-\\u{11363}\\u{11366}-\\u{1136C}\\u{11370}-\\u{11374}\\u{113B8}-\\u{113C0}\\u{113C2}\\u{113C5}\\u{113C7}-\\u{113CA}\\u{113CC}-\\u{113D0}\\u{113D2}\\u{113E1}-\\u{113E2}\\u{11435}-\\u{11446}\\u{1145E}\\u{114B0}-\\u{114C3}\\u{115AF}-\\u{115B5}\\u{115B8}-\\u{115C0}\\u{115DC}-\\u{115DD}\\u{11630}-\\u{11640}\\u{116AB}-\\u{116B7}\\u{1171D}-\\u{1172B}\\u{1182C}-\\u{1183A}\\u{11930}-\\u{11935}\\u{11937}-\\u{11938}\\u{1193B}-\\u{1193E}\\u{11940}\\u{11942}-\\u{11943}\\u{119D1}-\\u{119D7}\\u{119DA}-\\u{119E0}\\u{119E4}\\u{11A01}-\\u{11A0A}\\u{11A33}-\\u{11A39}\\u{11A3B}-\\u{11A3E}\\u{11A47}\\u{11A51}-\\u{11A5B}\\u{11A8A}-\\u{11A99}\\u{11B60}-\\u{11B67}\\u{11C2F}-\\u{11C36}\\u{11C38}-\\u{11C3F}\\u{11C92}-\\u{11CA7}\\u{11CA9}-\\u{11CB6}\\u{11D31}-\\u{11D36}\\u{11D3A}\\u{11D3C}-\\u{11D3D}\\u{11D3F}-\\u{11D45}\\u{11D47}\\u{11D8A}-\\u{11D8E}\\u{11D90}-\\u{11D91}\\u{11D93}-\\u{11D97}\\u{11EF3}-\\u{11EF6}\\u{11F00}-\\u{11F01}\\u{11F03}\\u{11F34}-\\u{11F3A}\\u{11F3E}-\\u{11F42}\\u{11F5A}\\u{13440}\\u{13447}-\\u{13455}\\u{1611E}-\\u{1612F}\\u{16AF0}-\\u{16AF4}\\u{16B30}-\\u{16B36}\\u{16F4F}\\u{16F51}-\\u{16F87}\\u{16F8F}-\\u{16F92}\\u{16FE4}\\u{16FF0}-\\u{16FF1}\\u{1BC9D}-\\u{1BC9E}\\u{1CF00}-\\u{1CF2D}\\u{1CF30}-\\u{1CF46}\\u{1D165}-\\u{1D169}\\u{1D16D}-\\u{1D172}\\u{1D17B}-\\u{1D182}\\u{1D185}-\\u{1D18B}\\u{1D1AA}-\\u{1D1AD}\\u{1D242}-\\u{1D244}\\u{1DA00}-\\u{1DA36}\\u{1DA3B}-\\u{1DA6C}\\u{1DA75}\\u{1DA84}\\u{1DA9B}-\\u{1DA9F}\\u{1DAA1}-\\u{1DAAF}\\u{1E000}-\\u{1E006}\\u{1E008}-\\u{1E018}\\u{1E01B}-\\u{1E021}\\u{1E023}-\\u{1E024}\\u{1E026}-\\u{1E02A}\\u{1E08F}\\u{1E130}-\\u{1E136}\\u{1E2AE}\\u{1E2EC}-\\u{1E2EF}\\u{1E4EC}-\\u{1E4EF}\\u{1E5EE}-\\u{1E5EF}\\u{1E6E3}\\u{1E6E6}\\u{1E6EE}-\\u{1E6EF}\\u{1E6F5}\\u{1E8D0}-\\u{1E8D6}\\u{1E944}-\\u{1E94A}\\u{E0100}-\\u{E01EF}][\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1-\\u05C2\\u05C4-\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7-\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u07FD\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u0897-\\u089F\\u08CA-\\u08E1\\u08E3-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962-\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7-\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2-\\u09E3\\u09FE\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47-\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70-\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2-\\u0AE3\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47-\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B62-\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C00-\\u0C04\\u0C3C\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55-\\u0C56\\u0C62-\\u0C63\\u0C81-\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5-\\u0CD6\\u0CE2-\\u0CE3\\u0CF3\\u0D00-\\u0D03\\u0D3B-\\u0D3C\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62-\\u0D63\\u0D81-\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2-\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EBC\\u0EC8-\\u0ECE\\u0F18-\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E-\\u0F3F\\u0F71-\\u0F84\\u0F86-\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1715\\u1732-\\u1734\\u1752-\\u1753\\u1772-\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u180F\\u1885-\\u1886\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1AB0-\\u1ADD\\u1AE0-\\u1AEB\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF4\\u1CF7-\\u1CF9\\u1DC0-\\u1DFF\\u20D0-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099-\\u309A\\uA66F-\\uA672\\uA674-\\uA67D\\uA69E-\\uA69F\\uA6F0-\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA82C\\uA880-\\uA881\\uA8B4-\\uA8C5\\uA8E0-\\uA8F1\\uA8FF\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uA9E5\\uAA29-\\uAA36\\uAA43\\uAA4C-\\uAA4D\\uAA7B-\\uAA7D\\uAAB0\\uAAB2-\\uAAB4\\uAAB7-\\uAAB8\\uAABE-\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5-\\uAAF6\\uABE3-\\uABEA\\uABEC-\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\u{101FD}\\u{102E0}\\u{10376}-\\u{1037A}\\u{10A01}-\\u{10A03}\\u{10A05}-\\u{10A06}\\u{10A0C}-\\u{10A0F}\\u{10A38}-\\u{10A3A}\\u{10A3F}\\u{10AE5}-\\u{10AE6}\\u{10D24}-\\u{10D27}\\u{10D69}-\\u{10D6D}\\u{10EAB}-\\u{10EAC}\\u{10EFA}-\\u{10EFF}\\u{10F46}-\\u{10F50}\\u{10F82}-\\u{10F85}\\u{11000}-\\u{11002}\\u{11038}-\\u{11046}\\u{11070}\\u{11073}-\\u{11074}\\u{1107F}-\\u{11082}\\u{110B0}-\\u{110BA}\\u{110C2}\\u{11100}-\\u{11102}\\u{11127}-\\u{11134}\\u{11145}-\\u{11146}\\u{11173}\\u{11180}-\\u{11182}\\u{111B3}-\\u{111C0}\\u{111C9}-\\u{111CC}\\u{111CE}-\\u{111CF}\\u{1122C}-\\u{11237}\\u{1123E}\\u{11241}\\u{112DF}-\\u{112EA}\\u{11300}-\\u{11303}\\u{1133B}-\\u{1133C}\\u{1133E}-\\u{11344}\\u{11347}-\\u{11348}\\u{1134B}-\\u{1134D}\\u{11357}\\u{11362}-\\u{11363}\\u{11366}-\\u{1136C}\\u{11370}-\\u{11374}\\u{113B8}-\\u{113C0}\\u{113C2}\\u{113C5}\\u{113C7}-\\u{113CA}\\u{113CC}-\\u{113D0}\\u{113D2}\\u{113E1}-\\u{113E2}\\u{11435}-\\u{11446}\\u{1145E}\\u{114B0}-\\u{114C3}\\u{115AF}-\\u{115B5}\\u{115B8}-\\u{115C0}\\u{115DC}-\\u{115DD}\\u{11630}-\\u{11640}\\u{116AB}-\\u{116B7}\\u{1171D}-\\u{1172B}\\u{1182C}-\\u{1183A}\\u{11930}-\\u{11935}\\u{11937}-\\u{11938}\\u{1193B}-\\u{1193E}\\u{11940}\\u{11942}-\\u{11943}\\u{119D1}-\\u{119D7}\\u{119DA}-\\u{119E0}\\u{119E4}\\u{11A01}-\\u{11A0A}\\u{11A33}-\\u{11A39}\\u{11A3B}-\\u{11A3E}\\u{11A47}\\u{11A51}-\\u{11A5B}\\u{11A8A}-\\u{11A99}\\u{11B60}-\\u{11B67}\\u{11C2F}-\\u{11C36}\\u{11C38}-\\u{11C3F}\\u{11C92}-\\u{11CA7}\\u{11CA9}-\\u{11CB6}\\u{11D31}-\\u{11D36}\\u{11D3A}\\u{11D3C}-\\u{11D3D}\\u{11D3F}-\\u{11D45}\\u{11D47}\\u{11D8A}-\\u{11D8E}\\u{11D90}-\\u{11D91}\\u{11D93}-\\u{11D97}\\u{11EF3}-\\u{11EF6}\\u{11F00}-\\u{11F01}\\u{11F03}\\u{11F34}-\\u{11F3A}\\u{11F3E}-\\u{11F42}\\u{11F5A}\\u{13440}\\u{13447}-\\u{13455}\\u{1611E}-\\u{1612F}\\u{16AF0}-\\u{16AF4}\\u{16B30}-\\u{16B36}\\u{16F4F}\\u{16F51}-\\u{16F87}\\u{16F8F}-\\u{16F92}\\u{16FE4}\\u{16FF0}-\\u{16FF1}\\u{1BC9D}-\\u{1BC9E}\\u{1CF00}-\\u{1CF2D}\\u{1CF30}-\\u{1CF46}\\u{1D165}-\\u{1D169}\\u{1D16D}-\\u{1D172}\\u{1D17B}-\\u{1D182}\\u{1D185}-\\u{1D18B}\\u{1D1AA}-\\u{1D1AD}\\u{1D242}-\\u{1D244}\\u{1DA00}-\\u{1DA36}\\u{1DA3B}-\\u{1DA6C}\\u{1DA75}\\u{1DA84}\\u{1DA9B}-\\u{1DA9F}\\u{1DAA1}-\\u{1DAAF}\\u{1E000}-\\u{1E006}\\u{1E008}-\\u{1E018}\\u{1E01B}-\\u{1E021}\\u{1E023}-\\u{1E024}\\u{1E026}-\\u{1E02A}\\u{1E08F}\\u{1E130}-\\u{1E136}\\u{1E2AE}\\u{1E2EC}-\\u{1E2EF}\\u{1E4EC}-\\u{1E4EF}\\u{1E5EE}-\\u{1E5EF}\\u{1E6E3}\\u{1E6E6}\\u{1E6EE}-\\u{1E6EF}\\u{1E6F5}\\u{1E8D0}-\\u{1E8D6}\\u{1E944}-\\u{1E94A}\\u{E0100}-\\u{E01EF}]*)", "gu");
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
// Grapheme clusters, ECMA-402/UAX #29: base char plus its marks, ZWJ sequences, Hangul jamo.
|
|
36
|
+
// Built once (construction cost amortizes) and used for both index and query splitting.
|
|
37
|
+
var GRAPHEME_SEGMENTER = new Intl.Segmenter(undefined, {
|
|
38
|
+
granularity: 'grapheme'
|
|
39
|
+
});
|
|
40
|
+
// unicode61 drops Unicode punctuation as a separator. Some of it (。、「」) has Script_Extensions
|
|
41
|
+
// into an unspaced script, so RUN keeps it -- a grapheme matching this becomes a split point.
|
|
42
|
+
var PUNCTUATION = RegExp("[\\u0021-\\u0023\\u0025-\\u002A\\u002C-\\u002F\\u003A-\\u003B\\u003F-\\u0040\\u005B-\\u005D\\u005F\\u007B\\u007D\\u00A1\\u00A7\\u00AB\\u00B6-\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589-\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3-\\u05F4\\u0609-\\u060A\\u060C-\\u060D\\u061B\\u061D-\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964-\\u0965\\u0970\\u09FD\\u0A76\\u0AF0\\u0C77\\u0C84\\u0DF4\\u0E4F\\u0E5A-\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9-\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166E\\u169B-\\u169C\\u16EB-\\u16ED\\u1735-\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944-\\u1945\\u1A1E-\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B4E-\\u1B4F\\u1B5A-\\u1B60\\u1B7D-\\u1B7F\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E-\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D-\\u207E\\u208D-\\u208E\\u2308-\\u230B\\u2329-\\u232A\\u2768-\\u2775\\u27C5-\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC-\\u29FD\\u2CF9-\\u2CFC\\u2CFE-\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E4F\\u2E52-\\u2E5D\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE-\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE-\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E-\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE-\\uA9DF\\uAA5C-\\uAA5F\\uAADE-\\uAADF\\uAAF0-\\uAAF1\\uABEB\\uFD3E-\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A-\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A-\\uFF1B\\uFF1F-\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65\\u{10100}-\\u{10102}\\u{1039F}\\u{103D0}\\u{1056F}\\u{10857}\\u{1091F}\\u{1093F}\\u{10A50}-\\u{10A58}\\u{10A7F}\\u{10AF0}-\\u{10AF6}\\u{10B39}-\\u{10B3F}\\u{10B99}-\\u{10B9C}\\u{10D6E}\\u{10EAD}\\u{10ED0}\\u{10F55}-\\u{10F59}\\u{10F86}-\\u{10F89}\\u{11047}-\\u{1104D}\\u{110BB}-\\u{110BC}\\u{110BE}-\\u{110C1}\\u{11140}-\\u{11143}\\u{11174}-\\u{11175}\\u{111C5}-\\u{111C8}\\u{111CD}\\u{111DB}\\u{111DD}-\\u{111DF}\\u{11238}-\\u{1123D}\\u{112A9}\\u{113D4}-\\u{113D5}\\u{113D7}-\\u{113D8}\\u{1144B}-\\u{1144F}\\u{1145A}-\\u{1145B}\\u{1145D}\\u{114C6}\\u{115C1}-\\u{115D7}\\u{11641}-\\u{11643}\\u{11660}-\\u{1166C}\\u{116B9}\\u{1173C}-\\u{1173E}\\u{1183B}\\u{11944}-\\u{11946}\\u{119E2}\\u{11A3F}-\\u{11A46}\\u{11A9A}-\\u{11A9C}\\u{11A9E}-\\u{11AA2}\\u{11B00}-\\u{11B09}\\u{11BE1}\\u{11C41}-\\u{11C45}\\u{11C70}-\\u{11C71}\\u{11EF7}-\\u{11EF8}\\u{11F43}-\\u{11F4F}\\u{11FFF}\\u{12470}-\\u{12474}\\u{12FF1}-\\u{12FF2}\\u{16A6E}-\\u{16A6F}\\u{16AF5}\\u{16B37}-\\u{16B3B}\\u{16B44}\\u{16D6D}-\\u{16D6F}\\u{16E97}-\\u{16E9A}\\u{16FE2}\\u{1BC9F}\\u{1DA87}-\\u{1DA8B}\\u{1E5FF}\\u{1E95E}-\\u{1E95F}]", "u");
|
|
43
|
+
// Token barrier between separate runs (or a punctuation split within one) so their graphemes
|
|
44
|
+
// are never phrase-adjacent. U+A7F7: a letter (so FTS5 keeps it as a token) no one types.
|
|
38
45
|
var BARRIER = 'ꟷ';
|
|
39
46
|
function graphemes(run) {
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
return Array.from(GRAPHEME_SEGMENTER.segment(run), function(s) {
|
|
48
|
+
return s.segment;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// A run's graphemes, cut into punctuation-free groups at every punctuation grapheme (dropped,
|
|
52
|
+
// matching unicode61). The one place punctuation is classified, so index and query agree.
|
|
53
|
+
function splitOnPunctuation(run) {
|
|
54
|
+
var groups = [
|
|
55
|
+
[]
|
|
56
|
+
];
|
|
57
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
58
|
+
try {
|
|
59
|
+
for(var _iterator = graphemes(run)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
60
|
+
var g = _step.value;
|
|
61
|
+
if (PUNCTUATION.test(g)) groups.push([]);
|
|
62
|
+
else groups[groups.length - 1].push(g);
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
_didIteratorError = true;
|
|
66
|
+
_iteratorError = err;
|
|
67
|
+
} finally{
|
|
68
|
+
try {
|
|
69
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
70
|
+
_iterator.return();
|
|
71
|
+
}
|
|
72
|
+
} finally{
|
|
73
|
+
if (_didIteratorError) {
|
|
74
|
+
throw _iteratorError;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return groups.filter(function(g) {
|
|
79
|
+
return g.length > 0;
|
|
80
|
+
});
|
|
42
81
|
}
|
|
43
82
|
function segmentField(text) {
|
|
44
83
|
if (!HAS_RUN.test(text)) return '';
|
|
45
84
|
var out = text.replace(RUN, function(run) {
|
|
46
|
-
|
|
85
|
+
var body = splitOnPunctuation(run).map(function(g) {
|
|
86
|
+
return g.join(' ');
|
|
87
|
+
}).join(" ".concat(BARRIER, " "));
|
|
88
|
+
return " ".concat(BARRIER, " ").concat(body, " ").concat(BARRIER, " ");
|
|
47
89
|
});
|
|
48
90
|
return out.replace(/\s+/g, ' ').trim();
|
|
49
91
|
}
|
|
50
92
|
// A `title:`/`summary:`/`text:` qualifier directly before a run that is about to become a
|
|
51
93
|
// quoted grapheme phrase, so the rewrite can retarget it at the matching `_seg` column.
|
|
52
94
|
var QUALIFIER = /(^|[\s(])(-?)(title|summary|text)\s*:\s*$/;
|
|
95
|
+
// An unqualified run's target: raw title/summary/text drop punctuation as unicode61's token
|
|
96
|
+
// separator, so two adjacent single-grapheme phrase positions match across punctuation the same
|
|
97
|
+
// as across a real gap (`数数` vs `数。数`) -- a false positive only the barriered `_seg` columns
|
|
98
|
+
// are safe from. FTS5's column-set filter, not parens+OR, so the group still composes under
|
|
99
|
+
// AND/OR/NOT/juxtaposition exactly like the single-column qualifier form below.
|
|
100
|
+
var SIDECAR_COLUMNS = '{title_seg summary_seg text_seg}:';
|
|
101
|
+
// A run's punctuation-free groups, each its own quoted phrase (bare token if one grapheme),
|
|
102
|
+
// space-joined -- the same split points segmentField barriers, so query and index agree.
|
|
103
|
+
function runQuery(run, columnPrefix) {
|
|
104
|
+
return splitOnPunctuation(run).map(function(g) {
|
|
105
|
+
return "".concat(columnPrefix).concat(g.length > 1 ? '"'.concat(g.join(' '), '"') : g[0]);
|
|
106
|
+
}).join(' ');
|
|
107
|
+
}
|
|
53
108
|
function segmentMatch(terms) {
|
|
54
109
|
if (!HAS_RUN.test(terms)) return terms;
|
|
55
110
|
var out = '';
|
|
@@ -84,13 +139,11 @@ function segmentMatch(terms) {
|
|
|
84
139
|
out += pieces[i]; // an author's phrase is matched as written
|
|
85
140
|
continue;
|
|
86
141
|
}
|
|
87
|
-
var g = graphemes(pieces[i]);
|
|
88
|
-
var phrase = g.length > 1 ? '"'.concat(g.join(' '), '"') : g[0];
|
|
89
142
|
var m = out.match(QUALIFIER);
|
|
90
143
|
if (m) {
|
|
91
|
-
out = "".concat(out.slice(0, m.index)).concat(m[1]).concat(m[2]).concat(m[3], "_seg:")
|
|
144
|
+
out = "".concat(out.slice(0, m.index)).concat(m[1]).concat(runQuery(pieces[i], "".concat(m[2]).concat(m[3], "_seg:")));
|
|
92
145
|
} else {
|
|
93
|
-
out +=
|
|
146
|
+
out += runQuery(pieces[i], SIDECAR_COLUMNS);
|
|
94
147
|
}
|
|
95
148
|
}
|
|
96
149
|
return out;
|
package/dist/cjs/segment.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/segment.ts"],"sourcesContent":["// Word boundaries FTS5's tokenizers cannot find on their own.\n//\n// Segmentation is context-free: seg(query) appears inside seg(document) whenever the query is\n// a substring of the document. That is the contract -- substring semantics, what `grep` and\n// `LIKE '%..%'` give -- and it is what makes index and query agree on every input, always.\n//
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/segment.ts"],"sourcesContent":["// Word boundaries FTS5's tokenizers cannot find on their own.\n//\n// Segmentation is context-free: seg(query) appears inside seg(document) whenever the query is\n// a substring of the document. That is the contract -- substring semantics, what `grep` and\n// `LIKE '%..%'` give -- and it is what makes index and query agree on every input, always.\n// Intl.Segmenter's word mode is context-dependent (`东京都政府` splits as `东 | 京都 | 政府`\n// while the query `东京` splits as one word) and is rejected for that reason. Its grapheme\n// mode has no such dependency -- UAX #29 cluster boundaries never look past adjacent\n// characters -- so grapheme mode is used below; no dictionary, no word mode.\n\n// Scripts written without word spaces: a closed set of writing systems.\n// Script_Extensions, not Script: the katakana long-vowel mark ー is Script=Common.\nconst SCRIPTS = '\\\\p{scx=Han}\\\\p{scx=Hiragana}\\\\p{scx=Katakana}\\\\p{scx=Thai}\\\\p{scx=Khmer}\\\\p{scx=Lao}\\\\p{scx=Myanmar}';\n// A run is script BASE characters with their combining marks attached; a bare mark after a\n// Latin letter (decomposed é) never starts one.\nconst RUN = new RegExp(`((?:[${SCRIPTS}]\\\\p{M}*)+)`, 'gu');\nconst HAS_RUN = new RegExp(`[${SCRIPTS}]`, 'u');\n// Grapheme clusters, ECMA-402/UAX #29: base char plus its marks, ZWJ sequences, Hangul jamo.\n// Built once (construction cost amortizes) and used for both index and query splitting.\nconst GRAPHEME_SEGMENTER = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n// unicode61 drops Unicode punctuation as a separator. Some of it (。、「」) has Script_Extensions\n// into an unspaced script, so RUN keeps it -- a grapheme matching this becomes a split point.\nconst PUNCTUATION = /\\p{P}/u;\n// Token barrier between separate runs (or a punctuation split within one) so their graphemes\n// are never phrase-adjacent. U+A7F7: a letter (so FTS5 keeps it as a token) no one types.\nconst BARRIER = 'ꟷ';\n\nfunction graphemes(run: string): string[] {\n return Array.from(GRAPHEME_SEGMENTER.segment(run), (s) => s.segment);\n}\n\n// A run's graphemes, cut into punctuation-free groups at every punctuation grapheme (dropped,\n// matching unicode61). The one place punctuation is classified, so index and query agree.\nfunction splitOnPunctuation(run: string): string[][] {\n const groups: string[][] = [[]];\n for (const g of graphemes(run)) {\n if (PUNCTUATION.test(g)) groups.push([]);\n else groups[groups.length - 1].push(g);\n }\n return groups.filter((g) => g.length > 0);\n}\n\n// Index side: '' when the field has no unspaced-script run (the common case, paid for by\n// nothing). Otherwise each run explodes into its graphemes, barrier-delimited from its\n// neighbors and from a punctuation split within itself.\nexport function segmentField(text: string): string {\n if (!HAS_RUN.test(text)) return '';\n const out = text.replace(RUN, (run) => {\n const body = splitOnPunctuation(run)\n .map((g) => g.join(' '))\n .join(` ${BARRIER} `);\n return ` ${BARRIER} ${body} ${BARRIER} `;\n });\n return out.replace(/\\s+/g, ' ').trim();\n}\n\n// A `title:`/`summary:`/`text:` qualifier directly before a run that is about to become a\n// quoted grapheme phrase, so the rewrite can retarget it at the matching `_seg` column.\nconst QUALIFIER = /(^|[\\s(])(-?)(title|summary|text)\\s*:\\s*$/;\n\n// An unqualified run's target: raw title/summary/text drop punctuation as unicode61's token\n// separator, so two adjacent single-grapheme phrase positions match across punctuation the same\n// as across a real gap (`数数` vs `数。数`) -- a false positive only the barriered `_seg` columns\n// are safe from. FTS5's column-set filter, not parens+OR, so the group still composes under\n// AND/OR/NOT/juxtaposition exactly like the single-column qualifier form below.\nconst SIDECAR_COLUMNS = '{title_seg summary_seg text_seg}:';\n\n// A run's punctuation-free groups, each its own quoted phrase (bare token if one grapheme),\n// space-joined -- the same split points segmentField barriers, so query and index agree.\nfunction runQuery(run: string, columnPrefix: string): string {\n return splitOnPunctuation(run)\n .map((g) => `${columnPrefix}${g.length > 1 ? `\"${g.join(' ')}\"` : g[0]}`)\n .join(' ');\n}\n\n// Query side: each unspaced run becomes phrases of its graphemes, matching how segmentField\n// indexed it. A qualifier ahead of such a run maps to its `_seg` column; unqualified maps to all\n// three (SIDECAR_COLUMNS), since raw columns cannot express the contract. An author's own quoted\n// phrase is their explicit escape hatch to FTS5's native syntax, and passes through byte-identical.\nexport function segmentMatch(terms: string): string {\n if (!HAS_RUN.test(terms)) return terms;\n let out = '';\n let quoted = false;\n const pieces = terms.split(RUN); // split keeps captured runs at odd indices\n for (let i = 0; i < pieces.length; i++) {\n if (i % 2 === 0) {\n for (const ch of pieces[i]) if (ch === '\"') quoted = !quoted;\n out += pieces[i];\n continue;\n }\n if (quoted) {\n out += pieces[i]; // an author's phrase is matched as written\n continue;\n }\n const m = out.match(QUALIFIER);\n if (m) {\n out = `${out.slice(0, m.index)}${m[1]}${runQuery(pieces[i], `${m[2]}${m[3]}_seg:`)}`;\n } else {\n out += runQuery(pieces[i], SIDECAR_COLUMNS);\n }\n }\n return out;\n}\n"],"names":["segmentField","segmentMatch","SCRIPTS","RUN","RegExp","HAS_RUN","GRAPHEME_SEGMENTER","Intl","Segmenter","undefined","granularity","PUNCTUATION","BARRIER","graphemes","run","Array","from","segment","s","splitOnPunctuation","groups","g","test","push","length","filter","text","out","replace","body","map","join","trim","QUALIFIER","SIDECAR_COLUMNS","runQuery","columnPrefix","terms","quoted","pieces","split","i","ch","m","match","slice","index"],"mappings":"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"}
|
package/dist/cjs/traverse.js
CHANGED
|
@@ -19,10 +19,12 @@ function _array_without_holes(arr) {
|
|
|
19
19
|
if (Array.isArray(arr)) return _array_like_to_array(arr);
|
|
20
20
|
}
|
|
21
21
|
function _iterable_to_array(iter) {
|
|
22
|
-
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null)
|
|
22
|
+
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
23
|
+
return Array.from(iter);
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
26
|
function _non_iterable_spread() {
|
|
25
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance
|
|
27
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
26
28
|
}
|
|
27
29
|
function _to_consumable_array(arr) {
|
|
28
30
|
return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
|
package/dist/cjs/traverse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/traverse.ts"],"sourcesContent":["// Frontier-by-frontier BFS through a temp visited table, one indexed anti-join per ring: a\n// local question touches a neighborhood, never the whole edge list.\nimport type { DatabaseSync } from 'node:sqlite';\n\ntype Direction = 'forward' | 'reverse' | 'both';\n\ninterface FindPathOptions {\n directed?: boolean;\n maxDepth?: number;\n allowed?: Set<string>;\n}\n\nfunction resetVisited(db: DatabaseSync): void {\n db.exec('DROP TABLE IF EXISTS temp.visited');\n db.exec('CREATE TEMP TABLE visited (path TEXT PRIMARY KEY, depth INTEGER NOT NULL, pred TEXT)');\n}\n\n// Materializes the caller-resolved scope Set into a temp table so it joins like any other\n// indexed column. `extra`, when given, is always in scope -- findPath's `to` endpoint.\nfunction setupAllowed(db: DatabaseSync, allowed: Set<string>, extra?: string): void {\n db.exec('DROP TABLE IF EXISTS temp.allowed_nodes');\n db.exec('CREATE TEMP TABLE allowed_nodes (path TEXT PRIMARY KEY)');\n db.prepare('INSERT INTO allowed_nodes SELECT DISTINCT value FROM json_each(?1)').run(JSON.stringify([...allowed]));\n if (extra !== undefined) db.prepare('INSERT OR IGNORE INTO allowed_nodes VALUES (?)').run(extra);\n}\n\n// Only resolved links (dst IS NOT NULL) are followed, in either direction.\nfunction candidateSelect(direction: Direction): string {\n const forward = 'SELECT l.dst AS path, l.src AS pred FROM links l JOIN visited v ON v.path = l.src AND v.depth = ?1 WHERE l.dst IS NOT NULL';\n const reverse = 'SELECT l.src AS path, l.dst AS pred FROM links l JOIN visited v ON v.path = l.dst AND v.depth = ?1 WHERE l.dst IS NOT NULL';\n if (direction === 'forward') return forward;\n if (direction === 'reverse') return reverse;\n return `${forward} UNION ALL ${reverse}`;\n}\n\n// One ring: candidates adjacent to the previous ring's frontier (?1), anti-joined against\n// everything already visited, optionally filtered to the allowed set, capped (?3) and\n// inserted at the new depth (?2). RETURNING hands back exactly what this ring newly reached.\nfunction ringSql(direction: Direction, hasAllowed: boolean): string {\n return `\nINSERT INTO visited (path, depth, pred)\nSELECT cand.path, ?2, MIN(cand.pred)\nFROM (${candidateSelect(direction)}) cand\nWHERE NOT EXISTS (SELECT 1 FROM visited v2 WHERE v2.path = cand.path)\n${hasAllowed ? 'AND EXISTS (SELECT 1 FROM allowed_nodes a WHERE a.path = cand.path)' : ''}\nGROUP BY cand.path\nORDER BY cand.path\nLIMIT ?3\nRETURNING path`;\n}\n\nfunction reconstructPath(db: DatabaseSync, to: string): string[] {\n const lookup = db.prepare('SELECT pred FROM visited WHERE path = ?');\n const path: string[] = [];\n let cur: string | null = to;\n while (cur !== null) {\n path.push(cur);\n const row = lookup.get(cur) as { pred: string | null } | undefined;\n cur = row ? row.pred : null;\n }\n return path.reverse();\n}\n\n// One BFS from `from`, tracking a predecessor per node. Undirected by default, matching\n// personalizedRank; null when `to` is unreached within `maxDepth`.\nexport function findPath(db: DatabaseSync, from: string, to: string, opts: FindPathOptions = {}): string[] | null {\n if (from === to) return [from];\n\n const direction: Direction = opts.directed ? 'forward' : 'both';\n const maxDepth = opts.maxDepth ?? Infinity;\n if (maxDepth <= 0) return null;\n\n resetVisited(db);\n db.prepare('INSERT INTO visited (path, depth, pred) VALUES (?, 0, NULL)').run(from);\n if (opts.allowed) setupAllowed(db, opts.allowed, to);\n\n const stmt = db.prepare(ringSql(direction, !!opts.allowed));\n for (let ring = 1; ring <= maxDepth; ring++) {\n const rows = stmt.all(ring - 1, ring, -1) as Array<{ path: string }>;\n if (rows.length === 0) break;\n if (rows.some((row) => row.path === to)) return reconstructPath(db, to);\n }\n return null;\n}\n"],"names":["findPath","resetVisited","db","exec","setupAllowed","allowed","extra","prepare","run","JSON","stringify","undefined","candidateSelect","direction","forward","reverse","ringSql","hasAllowed","reconstructPath","to","lookup","path","cur","push","row","get","pred","from","opts","directed","maxDepth","Infinity","stmt","ring","rows","all","length","some"],"mappings":"AAAA,2FAA2F;AAC3F,oEAAoE;;;;;+BAgEpDA;;;eAAAA
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/traverse.ts"],"sourcesContent":["// Frontier-by-frontier BFS through a temp visited table, one indexed anti-join per ring: a\n// local question touches a neighborhood, never the whole edge list.\nimport type { DatabaseSync } from 'node:sqlite';\n\ntype Direction = 'forward' | 'reverse' | 'both';\n\ninterface FindPathOptions {\n directed?: boolean;\n maxDepth?: number;\n allowed?: Set<string>;\n}\n\nfunction resetVisited(db: DatabaseSync): void {\n db.exec('DROP TABLE IF EXISTS temp.visited');\n db.exec('CREATE TEMP TABLE visited (path TEXT PRIMARY KEY, depth INTEGER NOT NULL, pred TEXT)');\n}\n\n// Materializes the caller-resolved scope Set into a temp table so it joins like any other\n// indexed column. `extra`, when given, is always in scope -- findPath's `to` endpoint.\nfunction setupAllowed(db: DatabaseSync, allowed: Set<string>, extra?: string): void {\n db.exec('DROP TABLE IF EXISTS temp.allowed_nodes');\n db.exec('CREATE TEMP TABLE allowed_nodes (path TEXT PRIMARY KEY)');\n db.prepare('INSERT INTO allowed_nodes SELECT DISTINCT value FROM json_each(?1)').run(JSON.stringify([...allowed]));\n if (extra !== undefined) db.prepare('INSERT OR IGNORE INTO allowed_nodes VALUES (?)').run(extra);\n}\n\n// Only resolved links (dst IS NOT NULL) are followed, in either direction.\nfunction candidateSelect(direction: Direction): string {\n const forward = 'SELECT l.dst AS path, l.src AS pred FROM links l JOIN visited v ON v.path = l.src AND v.depth = ?1 WHERE l.dst IS NOT NULL';\n const reverse = 'SELECT l.src AS path, l.dst AS pred FROM links l JOIN visited v ON v.path = l.dst AND v.depth = ?1 WHERE l.dst IS NOT NULL';\n if (direction === 'forward') return forward;\n if (direction === 'reverse') return reverse;\n return `${forward} UNION ALL ${reverse}`;\n}\n\n// One ring: candidates adjacent to the previous ring's frontier (?1), anti-joined against\n// everything already visited, optionally filtered to the allowed set, capped (?3) and\n// inserted at the new depth (?2). RETURNING hands back exactly what this ring newly reached.\nfunction ringSql(direction: Direction, hasAllowed: boolean): string {\n return `\nINSERT INTO visited (path, depth, pred)\nSELECT cand.path, ?2, MIN(cand.pred)\nFROM (${candidateSelect(direction)}) cand\nWHERE NOT EXISTS (SELECT 1 FROM visited v2 WHERE v2.path = cand.path)\n${hasAllowed ? 'AND EXISTS (SELECT 1 FROM allowed_nodes a WHERE a.path = cand.path)' : ''}\nGROUP BY cand.path\nORDER BY cand.path\nLIMIT ?3\nRETURNING path`;\n}\n\nfunction reconstructPath(db: DatabaseSync, to: string): string[] {\n const lookup = db.prepare('SELECT pred FROM visited WHERE path = ?');\n const path: string[] = [];\n let cur: string | null = to;\n while (cur !== null) {\n path.push(cur);\n const row = lookup.get(cur) as { pred: string | null } | undefined;\n cur = row ? row.pred : null;\n }\n return path.reverse();\n}\n\n// One BFS from `from`, tracking a predecessor per node. Undirected by default, matching\n// personalizedRank; null when `to` is unreached within `maxDepth`.\nexport function findPath(db: DatabaseSync, from: string, to: string, opts: FindPathOptions = {}): string[] | null {\n if (from === to) return [from];\n\n const direction: Direction = opts.directed ? 'forward' : 'both';\n const maxDepth = opts.maxDepth ?? Infinity;\n if (maxDepth <= 0) return null;\n\n resetVisited(db);\n db.prepare('INSERT INTO visited (path, depth, pred) VALUES (?, 0, NULL)').run(from);\n if (opts.allowed) setupAllowed(db, opts.allowed, to);\n\n const stmt = db.prepare(ringSql(direction, !!opts.allowed));\n for (let ring = 1; ring <= maxDepth; ring++) {\n const rows = stmt.all(ring - 1, ring, -1) as Array<{ path: string }>;\n if (rows.length === 0) break;\n if (rows.some((row) => row.path === to)) return reconstructPath(db, to);\n }\n return null;\n}\n"],"names":["findPath","resetVisited","db","exec","setupAllowed","allowed","extra","prepare","run","JSON","stringify","undefined","candidateSelect","direction","forward","reverse","ringSql","hasAllowed","reconstructPath","to","lookup","path","cur","push","row","get","pred","from","opts","directed","maxDepth","Infinity","stmt","ring","rows","all","length","some"],"mappings":"AAAA,2FAA2F;AAC3F,oEAAoE;;;;;+BAgEpDA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AArDhB,SAASC,aAAaC,EAAgB;IACpCA,GAAGC,IAAI,CAAC;IACRD,GAAGC,IAAI,CAAC;AACV;AAEA,0FAA0F;AAC1F,uFAAuF;AACvF,SAASC,aAAaF,EAAgB,EAAEG,OAAoB,EAAEC,KAAc;IAC1EJ,GAAGC,IAAI,CAAC;IACRD,GAAGC,IAAI,CAAC;IACRD,GAAGK,OAAO,CAAC,sEAAsEC,GAAG,CAACC,KAAKC,SAAS,CAAE,qBAAGL;IACxG,IAAIC,UAAUK,WAAWT,GAAGK,OAAO,CAAC,kDAAkDC,GAAG,CAACF;AAC5F;AAEA,2EAA2E;AAC3E,SAASM,gBAAgBC,SAAoB;IAC3C,IAAMC,UAAU;IAChB,IAAMC,UAAU;IAChB,IAAIF,cAAc,WAAW,OAAOC;IACpC,IAAID,cAAc,WAAW,OAAOE;IACpC,OAAO,AAAC,GAAuBA,OAArBD,SAAQ,eAAqB,OAARC;AACjC;AAEA,0FAA0F;AAC1F,sFAAsF;AACtF,6FAA6F;AAC7F,SAASC,QAAQH,SAAoB,EAAEI,UAAmB;IACxD,OAAO,AAAC,0FAKRA,OAFML,gBAAgBC,YAAW,mFAEuD,OAAxFI,aAAa,wEAAwE,IAAG;AAK1F;AAEA,SAASC,gBAAgBhB,EAAgB,EAAEiB,EAAU;IACnD,IAAMC,SAASlB,GAAGK,OAAO,CAAC;IAC1B,IAAMc,OAAiB,EAAE;IACzB,IAAIC,MAAqBH;IACzB,MAAOG,QAAQ,KAAM;QACnBD,KAAKE,IAAI,CAACD;QACV,IAAME,MAAMJ,OAAOK,GAAG,CAACH;QACvBA,MAAME,MAAMA,IAAIE,IAAI,GAAG;IACzB;IACA,OAAOL,KAAKN,OAAO;AACrB;AAIO,SAASf,SAASE,EAAgB,EAAEyB,IAAY,EAAER,EAAU;QAAES,OAAAA,iEAAwB,CAAC;QAI3EA;IAHjB,IAAID,SAASR,IAAI,OAAO;QAACQ;KAAK;IAE9B,IAAMd,YAAuBe,KAAKC,QAAQ,GAAG,YAAY;IACzD,IAAMC,YAAWF,iBAAAA,KAAKE,QAAQ,cAAbF,4BAAAA,iBAAiBG;IAClC,IAAID,YAAY,GAAG,OAAO;IAE1B7B,aAAaC;IACbA,GAAGK,OAAO,CAAC,+DAA+DC,GAAG,CAACmB;IAC9E,IAAIC,KAAKvB,OAAO,EAAED,aAAaF,IAAI0B,KAAKvB,OAAO,EAAEc;IAEjD,IAAMa,OAAO9B,GAAGK,OAAO,CAACS,QAAQH,WAAW,CAAC,CAACe,KAAKvB,OAAO;IACzD,IAAK,IAAI4B,OAAO,GAAGA,QAAQH,UAAUG,OAAQ;QAC3C,IAAMC,OAAOF,KAAKG,GAAG,CAACF,OAAO,GAAGA,MAAM,CAAC;QACvC,IAAIC,KAAKE,MAAM,KAAK,GAAG;QACvB,IAAIF,KAAKG,IAAI,CAAC,SAACb;mBAAQA,IAAIH,IAAI,KAAKF;YAAK,OAAOD,gBAAgBhB,IAAIiB;IACtE;IACA,OAAO;AACT"}
|
package/dist/cjs/watch.js
CHANGED
|
@@ -20,11 +20,8 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
|
20
20
|
reject(error);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
-
if (info.done)
|
|
24
|
-
|
|
25
|
-
} else {
|
|
26
|
-
Promise.resolve(value).then(_next, _throw);
|
|
27
|
-
}
|
|
23
|
+
if (info.done) resolve(value);
|
|
24
|
+
else Promise.resolve(value).then(_next, _throw);
|
|
28
25
|
}
|
|
29
26
|
function _async_to_generator(fn) {
|
|
30
27
|
return function() {
|
package/dist/cjs/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/watch.ts"],"sourcesContent":["import { watch as fsWatch } from 'node:fs';\nimport type { ResolvedConfig } from './config/index.ts';\nimport { STATE_DIR } from './config/index.ts';\nimport { docCount, getMeta, open, reconcile, setMeta } from './db/index.ts';\nimport { SenseError } from './errors.ts';\n\n// Watch is a cache pre-warmer, not a correctness mechanism: open() always reconciles anyway, so any fs event just triggers a debounced full reconcile.\nconst DEBOUNCE_MS = 200;\nconst HEARTBEAT_INTERVAL_MS = 5000;\nconst STALE_HEARTBEAT_MS = 15000;\n\nexport type WatchEvent = { type: 'started'; baseDir: string; dbPath: string } | { type: 'reconciled'; parsed: number; total: number; warnings: string[] } | { type: 'reconcile-error'; message: string };\n\nexport interface WatchOptions {\n force?: boolean;\n onEvent?: (event: WatchEvent) => void;\n}\n\n// Runs in the foreground until SIGINT/SIGTERM. Throws WATCH_ACTIVE if another watcher's heartbeat is still fresh and --force wasn't given.\nexport async function runWatch(cfg: ResolvedConfig, opts: WatchOptions = {}): Promise<void> {\n const onEvent = opts.onEvent ?? (() => {});\n const { db, dbPath, warnings: initialWarnings, parsed: initialParsed } = open(cfg);\n const baseDir = cfg.baseDir;\n\n const existingHeartbeat = getMeta(db, 'watch_heartbeat');\n if (existingHeartbeat && !opts.force) {\n const age = Date.now() - Date.parse(existingHeartbeat);\n if (age >= 0 && age < STALE_HEARTBEAT_MS) {\n db.close();\n throw new SenseError('WATCH_ACTIVE', `another watcher appears active (heartbeat ${Math.round(age / 1000)}s ago); use --force to override`);\n }\n }\n\n onEvent({ type: 'started', baseDir, dbPath });\n if (initialWarnings.length > 0 || initialParsed > 0) {\n onEvent({ type: 'reconciled', parsed: initialParsed, total: docCount(db), warnings: initialWarnings });\n }\n\n const touchHeartbeat = () => {\n setMeta(db, 'watch_heartbeat', new Date().toISOString());\n setMeta(db, 'watch_pid', String(process.pid));\n };\n touchHeartbeat();\n\n let debounceTimer: NodeJS.Timeout | null = null;\n const scheduleReconcile = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n try {\n const { parsed, warnings } = reconcile(db, cfg, baseDir);\n onEvent({ type: 'reconciled', parsed, total: docCount(db), warnings });\n } catch (err) {\n onEvent({ type: 'reconcile-error', message: (err as Error).message });\n }\n }, DEBOUNCE_MS);\n };\n\n // Ignore our own state dir, or the heartbeat write would retrigger itself forever.\n const watcher = fsWatch(baseDir, { recursive: true }, (_event, filename) => {\n if (typeof filename === 'string' && filename.startsWith(STATE_DIR)) return;\n scheduleReconcile();\n });\n const heartbeatTimer = setInterval(touchHeartbeat, HEARTBEAT_INTERVAL_MS);\n\n return new Promise<void>((resolveShutdown) => {\n const cleanExit = () => {\n clearInterval(heartbeatTimer);\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher.close();\n setMeta(db, 'watch_heartbeat', null);\n setMeta(db, 'watch_pid', null);\n db.close();\n resolveShutdown();\n };\n process.once('SIGINT', cleanExit);\n process.once('SIGTERM', cleanExit);\n });\n}\n"],"names":["runWatch","DEBOUNCE_MS","HEARTBEAT_INTERVAL_MS","STALE_HEARTBEAT_MS","cfg","opts","onEvent","open","db","dbPath","initialWarnings","initialParsed","baseDir","existingHeartbeat","age","touchHeartbeat","debounceTimer","scheduleReconcile","watcher","heartbeatTimer","warnings","parsed","getMeta","force","Date","now","parse","close","SenseError","Math","round","type","length","total","docCount","setMeta","toISOString","String","process","pid","clearTimeout","setTimeout","reconcile","err","message","fsWatch","recursive","_event","filename","startsWith","STATE_DIR","setInterval","Promise","resolveShutdown","cleanExit","clearInterval","once"],"mappings":";;;;+BAmBsBA;;;eAAAA;;;sBAnBW;uBAEP;wBACkC;wBACjC
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/watch.ts"],"sourcesContent":["import { watch as fsWatch } from 'node:fs';\nimport type { ResolvedConfig } from './config/index.ts';\nimport { STATE_DIR } from './config/index.ts';\nimport { docCount, getMeta, open, reconcile, setMeta } from './db/index.ts';\nimport { SenseError } from './errors.ts';\n\n// Watch is a cache pre-warmer, not a correctness mechanism: open() always reconciles anyway, so any fs event just triggers a debounced full reconcile.\nconst DEBOUNCE_MS = 200;\nconst HEARTBEAT_INTERVAL_MS = 5000;\nconst STALE_HEARTBEAT_MS = 15000;\n\nexport type WatchEvent = { type: 'started'; baseDir: string; dbPath: string } | { type: 'reconciled'; parsed: number; total: number; warnings: string[] } | { type: 'reconcile-error'; message: string };\n\nexport interface WatchOptions {\n force?: boolean;\n onEvent?: (event: WatchEvent) => void;\n}\n\n// Runs in the foreground until SIGINT/SIGTERM. Throws WATCH_ACTIVE if another watcher's heartbeat is still fresh and --force wasn't given.\nexport async function runWatch(cfg: ResolvedConfig, opts: WatchOptions = {}): Promise<void> {\n const onEvent = opts.onEvent ?? (() => {});\n const { db, dbPath, warnings: initialWarnings, parsed: initialParsed } = open(cfg);\n const baseDir = cfg.baseDir;\n\n const existingHeartbeat = getMeta(db, 'watch_heartbeat');\n if (existingHeartbeat && !opts.force) {\n const age = Date.now() - Date.parse(existingHeartbeat);\n if (age >= 0 && age < STALE_HEARTBEAT_MS) {\n db.close();\n throw new SenseError('WATCH_ACTIVE', `another watcher appears active (heartbeat ${Math.round(age / 1000)}s ago); use --force to override`);\n }\n }\n\n onEvent({ type: 'started', baseDir, dbPath });\n if (initialWarnings.length > 0 || initialParsed > 0) {\n onEvent({ type: 'reconciled', parsed: initialParsed, total: docCount(db), warnings: initialWarnings });\n }\n\n const touchHeartbeat = () => {\n setMeta(db, 'watch_heartbeat', new Date().toISOString());\n setMeta(db, 'watch_pid', String(process.pid));\n };\n touchHeartbeat();\n\n let debounceTimer: NodeJS.Timeout | null = null;\n const scheduleReconcile = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n try {\n const { parsed, warnings } = reconcile(db, cfg, baseDir);\n onEvent({ type: 'reconciled', parsed, total: docCount(db), warnings });\n } catch (err) {\n onEvent({ type: 'reconcile-error', message: (err as Error).message });\n }\n }, DEBOUNCE_MS);\n };\n\n // Ignore our own state dir, or the heartbeat write would retrigger itself forever.\n const watcher = fsWatch(baseDir, { recursive: true }, (_event, filename) => {\n if (typeof filename === 'string' && filename.startsWith(STATE_DIR)) return;\n scheduleReconcile();\n });\n const heartbeatTimer = setInterval(touchHeartbeat, HEARTBEAT_INTERVAL_MS);\n\n return new Promise<void>((resolveShutdown) => {\n const cleanExit = () => {\n clearInterval(heartbeatTimer);\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher.close();\n setMeta(db, 'watch_heartbeat', null);\n setMeta(db, 'watch_pid', null);\n db.close();\n resolveShutdown();\n };\n process.once('SIGINT', cleanExit);\n process.once('SIGTERM', cleanExit);\n });\n}\n"],"names":["runWatch","DEBOUNCE_MS","HEARTBEAT_INTERVAL_MS","STALE_HEARTBEAT_MS","cfg","opts","onEvent","open","db","dbPath","initialWarnings","initialParsed","baseDir","existingHeartbeat","age","touchHeartbeat","debounceTimer","scheduleReconcile","watcher","heartbeatTimer","warnings","parsed","getMeta","force","Date","now","parse","close","SenseError","Math","round","type","length","total","docCount","setMeta","toISOString","String","process","pid","clearTimeout","setTimeout","reconcile","err","message","fsWatch","recursive","_event","filename","startsWith","STATE_DIR","setInterval","Promise","resolveShutdown","cleanExit","clearInterval","once"],"mappings":"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"}
|