dirsql 0.3.40__tar.gz → 0.3.42__tar.gz
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.
- {dirsql-0.3.40 → dirsql-0.3.42}/Cargo.lock +1 -1
- {dirsql-0.3.40 → dirsql-0.3.42}/PKG-INFO +1 -1
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/_async.py +4 -35
- dirsql-0.3.42/dirsql/cli/interpret/__init__.py +14 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/cli/main.py +2 -12
- {dirsql-0.3.40/packages/python → dirsql-0.3.42}/docs/.vitepress/config.ts +10 -13
- {dirsql-0.3.40/packages/rust → dirsql-0.3.42}/docs/api/index.md +3 -2
- {dirsql-0.3.40/packages/python → dirsql-0.3.42}/docs/cli/config.md +12 -7
- {dirsql-0.3.40/packages/rust → dirsql-0.3.42}/docs/cli/index.md +1 -1
- dirsql-0.3.42/docs/tests/integration/sidebar.spec.ts +46 -0
- dirsql-0.3.42/docs/tests/unit/config.test.ts +49 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/Cargo.toml +1 -1
- {dirsql-0.3.40 → dirsql-0.3.42/packages/python}/docs/.vitepress/config.ts +10 -13
- {dirsql-0.3.40 → dirsql-0.3.42/packages/python}/docs/api/index.md +3 -2
- {dirsql-0.3.40 → dirsql-0.3.42/packages/python}/docs/cli/config.md +12 -7
- {dirsql-0.3.40 → dirsql-0.3.42/packages/python}/docs/cli/index.md +1 -1
- dirsql-0.3.42/packages/python/docs/tests/integration/sidebar.spec.ts +46 -0
- dirsql-0.3.42/packages/python/docs/tests/unit/config.test.ts +49 -0
- dirsql-0.3.42/packages/python/e2e-attestation.json +6 -0
- {dirsql-0.3.40/packages/python → dirsql-0.3.42/packages/rust}/docs/api/index.md +3 -2
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/cli/config.md +12 -7
- {dirsql-0.3.40/packages/python → dirsql-0.3.42/packages/rust}/docs/cli/index.md +1 -1
- {dirsql-0.3.40 → dirsql-0.3.42}/pyproject.toml +1 -1
- dirsql-0.3.40/dirsql/cli/interpret/__init__.py +0 -17
- dirsql-0.3.40/dirsql/cli/interpret/dispatch_extract.py +0 -41
- dirsql-0.3.40/dirsql/cli/interpret/load_app.py +0 -32
- dirsql-0.3.40/dirsql/cli/interpret/run.py +0 -66
- dirsql-0.3.40/dirsql/cli/interpret/write_message.py +0 -18
- dirsql-0.3.40/dirsql/resolve_config.py +0 -61
- dirsql-0.3.40/docs/tests/unit/config.test.ts +0 -22
- dirsql-0.3.40/packages/python/docs/tests/unit/config.test.ts +0 -22
- dirsql-0.3.40/packages/python/e2e-attestation.json +0 -6
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/data/a/meta.json +0 -1
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/data/b/meta.json +0 -1
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/dirsql.config.py +0 -29
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/interpret/data/a/meta.json +0 -1
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/interpret/data/b/meta.json +0 -1
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config.py +0 -27
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config_no_app.py +0 -3
- dirsql-0.3.40/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config_raises.py +0 -21
- dirsql-0.3.40/packages/python/tests/e2e/interpret_subprocess.py +0 -96
- {dirsql-0.3.40 → dirsql-0.3.42}/Cargo.toml +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/README.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/__init__.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/dirsql/py.typed +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/AGENTS.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/cli/http-api.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/cli/init.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/cli/server.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/getting-started.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/guide/async.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/guide/crdt.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/guide/persistence.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/guide/querying.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/guide/tables.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/guide/watching.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/index.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/migrations.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/package.json +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/README.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/conftest.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/cli/http-api.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/cli/init.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/cli/server.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/guide/async.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/guide/crdt.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/guide/persistence.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/guide/querying.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/guide/tables.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/guide/watching.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/README.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/cli/http-api.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/cli/init.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/cli/server.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/guide/async.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/guide/crdt.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/guide/persistence.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/guide/querying.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/guide/tables.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/guide/watching.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/index.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/cli/native_config.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.40 → dirsql-0.3.42}/packages/rust/src/watcher.rs +0 -0
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
"""Async-by-default DirSQL wrapper."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
from dirsql._dirsql import DirSQL as _RustDirSQL
|
|
7
|
-
from dirsql.resolve_config import resolve_config
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
# `typing.override` is 3.12+; the package supports 3.11, so source it from
|
|
11
|
-
# `typing_extensions` for the type checker only. At runtime `@override` is
|
|
12
|
-
# a pure marker, so a no-op identity avoids the runtime dependency.
|
|
13
|
-
from typing_extensions import override
|
|
14
|
-
else:
|
|
15
|
-
|
|
16
|
-
def override(func):
|
|
17
|
-
return func
|
|
18
6
|
|
|
19
7
|
|
|
20
8
|
class _WatchStream:
|
|
@@ -55,9 +43,10 @@ class DirSQL:
|
|
|
55
43
|
async for event in db.watch():
|
|
56
44
|
...
|
|
57
45
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
Supply a ``root``, a ``config`` path, or both. When both are set, the
|
|
47
|
+
explicit ``root`` wins over any ``[dirsql].root`` in the config file (a
|
|
48
|
+
warning is emitted on stderr). If neither is given, the initial scan
|
|
49
|
+
fails with a "no root directory" error raised by the core.
|
|
61
50
|
|
|
62
51
|
Pass ``persist=True`` to keep an on-disk SQLite cache (default location:
|
|
63
52
|
``<root>/.dirsql/cache.db``). Override the location with ``persist_path``.
|
|
@@ -79,8 +68,6 @@ class DirSQL:
|
|
|
79
68
|
persist_path=None,
|
|
80
69
|
extensions=None,
|
|
81
70
|
):
|
|
82
|
-
if root is None and config is None:
|
|
83
|
-
raise TypeError("DirSQL requires either a root directory or a config= path")
|
|
84
71
|
self._root = root
|
|
85
72
|
self._tables = tables
|
|
86
73
|
self._ignore = ignore
|
|
@@ -136,21 +123,3 @@ class DirSQL:
|
|
|
136
123
|
def watch(self):
|
|
137
124
|
"""Start watching for file changes. Returns an async iterable of RowEvent."""
|
|
138
125
|
return _WatchStream(self._db)
|
|
139
|
-
|
|
140
|
-
@property
|
|
141
|
-
@override
|
|
142
|
-
def __dict__(self):
|
|
143
|
-
"""Resolved construction state as a JSON-serializable dict.
|
|
144
|
-
|
|
145
|
-
Recomputed on each access; reads the ``.dirsql.toml`` if ``config=``
|
|
146
|
-
was supplied. Works before ``await db.ready()``.
|
|
147
|
-
"""
|
|
148
|
-
return resolve_config(
|
|
149
|
-
self._root,
|
|
150
|
-
self._tables,
|
|
151
|
-
self._ignore,
|
|
152
|
-
self._config,
|
|
153
|
-
self._persist,
|
|
154
|
-
self._persist_path,
|
|
155
|
-
self._extensions,
|
|
156
|
-
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Empty package shell — the native-config ``interpret`` helper was removed.
|
|
2
|
+
|
|
3
|
+
The ``dirsql interpret`` subcommand and its NDJSON ``extract`` loop (``run``,
|
|
4
|
+
``load_app``, ``dispatch_extract``, ``write_message``) were removed in #321
|
|
5
|
+
(#323). The CLI now accepts only ``.dirsql.toml``; to run user-defined
|
|
6
|
+
``extract`` callbacks, use the programmatic SDK (``DirSQL(...)`` with
|
|
7
|
+
in-process closures).
|
|
8
|
+
|
|
9
|
+
This ``__init__.py`` carries no logic and no re-exports. It remains only
|
|
10
|
+
because the colocated-test tooling cannot yet express *deleting* an exempt
|
|
11
|
+
package barrel (the co-change check flags a deleted source that has no
|
|
12
|
+
co-deleted colocated test, and a retained exempt for a deleted path is
|
|
13
|
+
rejected as stale). The directory is removed once that is resolved.
|
|
14
|
+
"""
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"""Console-script entry point. Execs the bundled binary on POSIX,
|
|
2
|
-
subprocesses it on Windows.
|
|
3
|
-
|
|
4
|
-
orchestrator can spawn this script for native-language configs (#196)
|
|
5
|
-
without depending on the bundled Rust binary."""
|
|
2
|
+
subprocesses it on Windows. All argv is forwarded transparently to the
|
|
3
|
+
bundled Rust binary."""
|
|
6
4
|
|
|
7
5
|
from __future__ import annotations
|
|
8
6
|
|
|
@@ -18,14 +16,6 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
18
16
|
if argv is None:
|
|
19
17
|
argv = sys.argv[1:]
|
|
20
18
|
|
|
21
|
-
if argv and argv[0] == "interpret":
|
|
22
|
-
from .interpret.run import run
|
|
23
|
-
|
|
24
|
-
try:
|
|
25
|
-
return run(argv[1:])
|
|
26
|
-
except KeyboardInterrupt:
|
|
27
|
-
return 130
|
|
28
|
-
|
|
29
19
|
try:
|
|
30
20
|
binary = binary_path()
|
|
31
21
|
except FileNotFoundError as exc:
|
|
@@ -19,19 +19,12 @@ export default defineConfig({
|
|
|
19
19
|
{ text: 'GitHub', link: 'https://github.com/thekevinscott/dirsql' }
|
|
20
20
|
],
|
|
21
21
|
|
|
22
|
+
// A single global sidebar shown on every page. The CLI section is a
|
|
23
|
+
// self-contained group with all its subpages -- but it never *replaces*
|
|
24
|
+
// the rest of the nav. There is intentionally no path-scoped (`/cli/`)
|
|
25
|
+
// key: a path-scoped sidebar swaps the whole tree out, which deletes the
|
|
26
|
+
// other sections when you enter CLI (see #301). Keep one sidebar.
|
|
22
27
|
sidebar: {
|
|
23
|
-
'/cli/': [
|
|
24
|
-
{
|
|
25
|
-
text: 'CLI',
|
|
26
|
-
items: [
|
|
27
|
-
{ text: 'Overview & Installation', link: '/cli/' },
|
|
28
|
-
{ text: 'Running the Server', link: '/cli/server' },
|
|
29
|
-
{ text: 'Generating a Config (`init`)', link: '/cli/init' },
|
|
30
|
-
{ text: 'Configuration File', link: '/cli/config' },
|
|
31
|
-
{ text: 'HTTP API', link: '/cli/http-api' }
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
28
|
'/': [
|
|
36
29
|
{
|
|
37
30
|
text: 'Tutorials',
|
|
@@ -53,7 +46,11 @@ export default defineConfig({
|
|
|
53
46
|
{
|
|
54
47
|
text: 'CLI',
|
|
55
48
|
items: [
|
|
56
|
-
{ text: '
|
|
49
|
+
{ text: 'Overview & Installation', link: '/cli/' },
|
|
50
|
+
{ text: 'Running the Server', link: '/cli/server' },
|
|
51
|
+
{ text: 'Generating a Config (`init`)', link: '/cli/init' },
|
|
52
|
+
{ text: 'Configuration File', link: '/cli/config' },
|
|
53
|
+
{ text: 'HTTP API', link: '/cli/http-api' }
|
|
57
54
|
]
|
|
58
55
|
},
|
|
59
56
|
{
|
|
@@ -59,6 +59,7 @@ new DirSQL({
|
|
|
59
59
|
tables?: TableDef[],
|
|
60
60
|
ignore?: string[],
|
|
61
61
|
config?: string,
|
|
62
|
+
extensions?: ExtensionSpec[], // [{ path: string, entrypoint?: string }]
|
|
62
63
|
})
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -76,7 +77,7 @@ In Python, the constructor starts scanning in a background thread and returns im
|
|
|
76
77
|
- `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
|
|
77
78
|
- `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
|
|
78
79
|
- `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly; its `[[dirsql.extension]]` entries are appended to any programmatic `extensions`.
|
|
79
|
-
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python
|
|
80
|
+
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`; TypeScript: `{ path, entrypoint? }` objects). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python, Rust, and TypeScript SDKs. See [Loading extensions](../cli/config.md#loading-extensions).
|
|
80
81
|
|
|
81
82
|
### Methods
|
|
82
83
|
|
|
@@ -162,7 +163,7 @@ JSON.stringify(db) // via db.toJSON()
|
|
|
162
163
|
|
|
163
164
|
:::
|
|
164
165
|
|
|
165
|
-
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`.
|
|
166
|
+
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`. All three SDK snapshots also include `extensions` -- an array of `{ path, entrypoint }` (empty when none are configured; `entrypoint` is `null` when no override was supplied). Excludes the original `config` path (already merged into `root` / `tables` / `ignore`), per-table `extract`, and per-table `name`. Available immediately after construction in Python and TypeScript; Rust's sync `build()` returns a ready instance.
|
|
166
167
|
|
|
167
168
|
---
|
|
168
169
|
|
|
@@ -239,7 +239,7 @@ def extract_meta(path):
|
|
|
239
239
|
|
|
240
240
|
# Python must export a module-level `app`.
|
|
241
241
|
app = DirSQL(
|
|
242
|
-
root="papers", #
|
|
242
|
+
root="papers", # optional; defaults to the current directory
|
|
243
243
|
tables=[
|
|
244
244
|
Table(
|
|
245
245
|
ddl="CREATE TABLE papers (title TEXT, _path TEXT)",
|
|
@@ -269,7 +269,7 @@ import { readFileSync } from "node:fs";
|
|
|
269
269
|
import { DirSQL } from "dirsql";
|
|
270
270
|
|
|
271
271
|
export default new DirSQL({
|
|
272
|
-
root: "papers", //
|
|
272
|
+
root: "papers", // optional; defaults to the current directory
|
|
273
273
|
tables: [
|
|
274
274
|
{
|
|
275
275
|
ddl: "CREATE TABLE papers (title TEXT, _path TEXT)",
|
|
@@ -285,7 +285,7 @@ const { readFileSync } = require("node:fs");
|
|
|
285
285
|
const { DirSQL } = require("dirsql");
|
|
286
286
|
|
|
287
287
|
module.exports = new DirSQL({
|
|
288
|
-
root: "papers", //
|
|
288
|
+
root: "papers", // optional; defaults to the current directory
|
|
289
289
|
tables: [
|
|
290
290
|
{
|
|
291
291
|
ddl: "CREATE TABLE papers (title TEXT, _path TEXT)",
|
|
@@ -308,10 +308,15 @@ These apply to both the Python and JavaScript forms above.
|
|
|
308
308
|
package) uses `module.exports = new DirSQL(...)`. Only the extension
|
|
309
309
|
matters — the file can be named anything; `dirsql.config.{py,mjs,cjs}` is the
|
|
310
310
|
suggested convention, not a requirement.
|
|
311
|
-
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
- **`root` defaults to the current directory.** A native-language config with
|
|
312
|
+
no `root` indexes the process's current working directory — the directory you
|
|
313
|
+
ran `dirsql` from. (This differs from TOML configs, which default the scan
|
|
314
|
+
root to the config file's own directory.) Pass `root` explicitly to index
|
|
315
|
+
somewhere else.
|
|
316
|
+
- **No nested `config=`.** A native-language config builds its `DirSQL` from
|
|
317
|
+
`tables` and an optional `root`; it must not itself set `config=` to delegate
|
|
318
|
+
to another config file. `dirsql interpret` rejects such a config (a nested
|
|
319
|
+
config can't be represented in the handshake and would recurse).
|
|
315
320
|
- **Install the launcher on your `PATH`.** To run your `extract`, the server
|
|
316
321
|
spawns `dirsql interpret`, so the matching `dirsql` launcher must be installed
|
|
317
322
|
and on your `PATH` — a global `pip`/`uv` install for `.py`, or `npm` for
|
|
@@ -20,7 +20,7 @@ Everything you need to run `dirsql` as a CLI lives in this section:
|
|
|
20
20
|
- **[Configuration File](./config.md)** — the `.dirsql.toml` format and the
|
|
21
21
|
`.py` / `.js` native-language alternative. Custom tables
|
|
22
22
|
are defined through a config file; without one, the server runs in
|
|
23
|
-
[zero-config mode](./server.md#
|
|
23
|
+
[zero-config mode](./server.md#defaults).
|
|
24
24
|
- **[HTTP API](./http-api.md)** — the `POST /query` and `GET /events`
|
|
25
25
|
endpoints, status codes, and event streaming.
|
|
26
26
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
// Regression for #301: entering the CLI section must NOT replace the sidebar.
|
|
4
|
+
// The full set of sections has to stay visible on every page, including
|
|
5
|
+
// `/cli/*`, so navigation never loses its place.
|
|
6
|
+
const SECTIONS = ['Tutorials', 'How-to Guides', 'CLI', 'Reference']
|
|
7
|
+
|
|
8
|
+
async function sidebarSections(page: import('@playwright/test').Page) {
|
|
9
|
+
return await page.evaluate(() =>
|
|
10
|
+
Array.from(document.querySelectorAll('.VPSidebar .group .text'))
|
|
11
|
+
.map((el) => el.textContent?.trim())
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (const path of ['guide/tables.html', 'cli/index.html', 'cli/server.html']) {
|
|
17
|
+
test(`every section stays in the sidebar on ${path}`, async ({ page }) => {
|
|
18
|
+
await page.goto(`./${path}`)
|
|
19
|
+
await page.waitForSelector('.VPSidebar .group')
|
|
20
|
+
const sections = await sidebarSections(page)
|
|
21
|
+
for (const section of SECTIONS) {
|
|
22
|
+
expect(sections).toContain(section)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test('the CLI sidebar group lists all CLI subpages', async ({ page }) => {
|
|
28
|
+
await page.goto('./cli/index.html')
|
|
29
|
+
await page.waitForSelector('.VPSidebar .group')
|
|
30
|
+
const cliLinks = await page.evaluate(() => {
|
|
31
|
+
const groups = Array.from(document.querySelectorAll('.VPSidebar .group'))
|
|
32
|
+
const cli = groups.find(
|
|
33
|
+
(g) => g.querySelector('.text')?.textContent?.trim() === 'CLI'
|
|
34
|
+
)
|
|
35
|
+
return Array.from(cli?.querySelectorAll('a') ?? []).map(
|
|
36
|
+
(a) => new URL((a as HTMLAnchorElement).href).pathname
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
expect(cliLinks).toEqual([
|
|
40
|
+
'/dirsql/cli/',
|
|
41
|
+
'/dirsql/cli/server.html',
|
|
42
|
+
'/dirsql/cli/init.html',
|
|
43
|
+
'/dirsql/cli/config.html',
|
|
44
|
+
'/dirsql/cli/http-api.html'
|
|
45
|
+
])
|
|
46
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import config from '../../.vitepress/config'
|
|
3
|
+
|
|
4
|
+
type SidebarItem = { text?: string; link?: string; items?: SidebarItem[] }
|
|
5
|
+
|
|
6
|
+
describe('vitepress config', () => {
|
|
7
|
+
it('has the expected site title and base path', () => {
|
|
8
|
+
expect(config.title).toBe('dirsql')
|
|
9
|
+
expect(config.base).toBe('/dirsql/')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
// Regression guard: CLI docs live in their own `/cli/` section, not
|
|
13
|
+
// interleaved with the SDK how-to guides (see #179).
|
|
14
|
+
it('keeps CLI pages out of the How-to Guides group', () => {
|
|
15
|
+
const sidebar = config.themeConfig!.sidebar as Record<string, SidebarItem[]>
|
|
16
|
+
const howTo = sidebar['/'].find((group) => group.text === 'How-to Guides')
|
|
17
|
+
const links = (howTo!.items ?? []).map((item) => item.link)
|
|
18
|
+
expect(links).not.toContain('/guide/cli')
|
|
19
|
+
expect(links).not.toContain('/guide/init')
|
|
20
|
+
expect(links).not.toContain('/guide/config')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// Regression guard: the sidebar must never *replace* itself when entering a
|
|
24
|
+
// section. A path-scoped key (e.g. `/cli/`) swaps the whole tree out, which
|
|
25
|
+
// deletes the other sections and reads as the nav breaking (see #301). There
|
|
26
|
+
// must be exactly one global `/` sidebar.
|
|
27
|
+
it('has a single global sidebar with no replacing path-scoped keys', () => {
|
|
28
|
+
const sidebar = config.themeConfig!.sidebar as Record<string, SidebarItem[]>
|
|
29
|
+
expect(Object.keys(sidebar)).toEqual(['/'])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// The CLI section is self-contained: its group carries all CLI subpages,
|
|
33
|
+
// alongside (never instead of) the other sections (see #301).
|
|
34
|
+
it('shows every CLI subpage in a self-contained CLI group', () => {
|
|
35
|
+
const sidebar = config.themeConfig!.sidebar as Record<string, SidebarItem[]>
|
|
36
|
+
const groupTexts = sidebar['/'].map((group) => group.text)
|
|
37
|
+
expect(groupTexts).toEqual(['Tutorials', 'How-to Guides', 'CLI', 'Reference'])
|
|
38
|
+
|
|
39
|
+
const cli = sidebar['/'].find((group) => group.text === 'CLI')
|
|
40
|
+
const links = (cli!.items ?? []).map((item) => item.link)
|
|
41
|
+
expect(links).toEqual([
|
|
42
|
+
'/cli/',
|
|
43
|
+
'/cli/server',
|
|
44
|
+
'/cli/init',
|
|
45
|
+
'/cli/config',
|
|
46
|
+
'/cli/http-api'
|
|
47
|
+
])
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
|
|
|
4
4
|
# pypi/maturin handler can rewrite it via `write-version` before
|
|
5
5
|
# `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
|
|
6
6
|
# and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.42"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -19,19 +19,12 @@ export default defineConfig({
|
|
|
19
19
|
{ text: 'GitHub', link: 'https://github.com/thekevinscott/dirsql' }
|
|
20
20
|
],
|
|
21
21
|
|
|
22
|
+
// A single global sidebar shown on every page. The CLI section is a
|
|
23
|
+
// self-contained group with all its subpages -- but it never *replaces*
|
|
24
|
+
// the rest of the nav. There is intentionally no path-scoped (`/cli/`)
|
|
25
|
+
// key: a path-scoped sidebar swaps the whole tree out, which deletes the
|
|
26
|
+
// other sections when you enter CLI (see #301). Keep one sidebar.
|
|
22
27
|
sidebar: {
|
|
23
|
-
'/cli/': [
|
|
24
|
-
{
|
|
25
|
-
text: 'CLI',
|
|
26
|
-
items: [
|
|
27
|
-
{ text: 'Overview & Installation', link: '/cli/' },
|
|
28
|
-
{ text: 'Running the Server', link: '/cli/server' },
|
|
29
|
-
{ text: 'Generating a Config (`init`)', link: '/cli/init' },
|
|
30
|
-
{ text: 'Configuration File', link: '/cli/config' },
|
|
31
|
-
{ text: 'HTTP API', link: '/cli/http-api' }
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
28
|
'/': [
|
|
36
29
|
{
|
|
37
30
|
text: 'Tutorials',
|
|
@@ -53,7 +46,11 @@ export default defineConfig({
|
|
|
53
46
|
{
|
|
54
47
|
text: 'CLI',
|
|
55
48
|
items: [
|
|
56
|
-
{ text: '
|
|
49
|
+
{ text: 'Overview & Installation', link: '/cli/' },
|
|
50
|
+
{ text: 'Running the Server', link: '/cli/server' },
|
|
51
|
+
{ text: 'Generating a Config (`init`)', link: '/cli/init' },
|
|
52
|
+
{ text: 'Configuration File', link: '/cli/config' },
|
|
53
|
+
{ text: 'HTTP API', link: '/cli/http-api' }
|
|
57
54
|
]
|
|
58
55
|
},
|
|
59
56
|
{
|
|
@@ -59,6 +59,7 @@ new DirSQL({
|
|
|
59
59
|
tables?: TableDef[],
|
|
60
60
|
ignore?: string[],
|
|
61
61
|
config?: string,
|
|
62
|
+
extensions?: ExtensionSpec[], // [{ path: string, entrypoint?: string }]
|
|
62
63
|
})
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -76,7 +77,7 @@ In Python, the constructor starts scanning in a background thread and returns im
|
|
|
76
77
|
- `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
|
|
77
78
|
- `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
|
|
78
79
|
- `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly; its `[[dirsql.extension]]` entries are appended to any programmatic `extensions`.
|
|
79
|
-
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python
|
|
80
|
+
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`; TypeScript: `{ path, entrypoint? }` objects). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python, Rust, and TypeScript SDKs. See [Loading extensions](../cli/config.md#loading-extensions).
|
|
80
81
|
|
|
81
82
|
### Methods
|
|
82
83
|
|
|
@@ -162,7 +163,7 @@ JSON.stringify(db) // via db.toJSON()
|
|
|
162
163
|
|
|
163
164
|
:::
|
|
164
165
|
|
|
165
|
-
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`.
|
|
166
|
+
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`. All three SDK snapshots also include `extensions` -- an array of `{ path, entrypoint }` (empty when none are configured; `entrypoint` is `null` when no override was supplied). Excludes the original `config` path (already merged into `root` / `tables` / `ignore`), per-table `extract`, and per-table `name`. Available immediately after construction in Python and TypeScript; Rust's sync `build()` returns a ready instance.
|
|
166
167
|
|
|
167
168
|
---
|
|
168
169
|
|
|
@@ -239,7 +239,7 @@ def extract_meta(path):
|
|
|
239
239
|
|
|
240
240
|
# Python must export a module-level `app`.
|
|
241
241
|
app = DirSQL(
|
|
242
|
-
root="papers", #
|
|
242
|
+
root="papers", # optional; defaults to the current directory
|
|
243
243
|
tables=[
|
|
244
244
|
Table(
|
|
245
245
|
ddl="CREATE TABLE papers (title TEXT, _path TEXT)",
|
|
@@ -269,7 +269,7 @@ import { readFileSync } from "node:fs";
|
|
|
269
269
|
import { DirSQL } from "dirsql";
|
|
270
270
|
|
|
271
271
|
export default new DirSQL({
|
|
272
|
-
root: "papers", //
|
|
272
|
+
root: "papers", // optional; defaults to the current directory
|
|
273
273
|
tables: [
|
|
274
274
|
{
|
|
275
275
|
ddl: "CREATE TABLE papers (title TEXT, _path TEXT)",
|
|
@@ -285,7 +285,7 @@ const { readFileSync } = require("node:fs");
|
|
|
285
285
|
const { DirSQL } = require("dirsql");
|
|
286
286
|
|
|
287
287
|
module.exports = new DirSQL({
|
|
288
|
-
root: "papers", //
|
|
288
|
+
root: "papers", // optional; defaults to the current directory
|
|
289
289
|
tables: [
|
|
290
290
|
{
|
|
291
291
|
ddl: "CREATE TABLE papers (title TEXT, _path TEXT)",
|
|
@@ -308,10 +308,15 @@ These apply to both the Python and JavaScript forms above.
|
|
|
308
308
|
package) uses `module.exports = new DirSQL(...)`. Only the extension
|
|
309
309
|
matters — the file can be named anything; `dirsql.config.{py,mjs,cjs}` is the
|
|
310
310
|
suggested convention, not a requirement.
|
|
311
|
-
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
- **`root` defaults to the current directory.** A native-language config with
|
|
312
|
+
no `root` indexes the process's current working directory — the directory you
|
|
313
|
+
ran `dirsql` from. (This differs from TOML configs, which default the scan
|
|
314
|
+
root to the config file's own directory.) Pass `root` explicitly to index
|
|
315
|
+
somewhere else.
|
|
316
|
+
- **No nested `config=`.** A native-language config builds its `DirSQL` from
|
|
317
|
+
`tables` and an optional `root`; it must not itself set `config=` to delegate
|
|
318
|
+
to another config file. `dirsql interpret` rejects such a config (a nested
|
|
319
|
+
config can't be represented in the handshake and would recurse).
|
|
315
320
|
- **Install the launcher on your `PATH`.** To run your `extract`, the server
|
|
316
321
|
spawns `dirsql interpret`, so the matching `dirsql` launcher must be installed
|
|
317
322
|
and on your `PATH` — a global `pip`/`uv` install for `.py`, or `npm` for
|
|
@@ -20,7 +20,7 @@ Everything you need to run `dirsql` as a CLI lives in this section:
|
|
|
20
20
|
- **[Configuration File](./config.md)** — the `.dirsql.toml` format and the
|
|
21
21
|
`.py` / `.js` native-language alternative. Custom tables
|
|
22
22
|
are defined through a config file; without one, the server runs in
|
|
23
|
-
[zero-config mode](./server.md#
|
|
23
|
+
[zero-config mode](./server.md#defaults).
|
|
24
24
|
- **[HTTP API](./http-api.md)** — the `POST /query` and `GET /events`
|
|
25
25
|
endpoints, status codes, and event streaming.
|
|
26
26
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
// Regression for #301: entering the CLI section must NOT replace the sidebar.
|
|
4
|
+
// The full set of sections has to stay visible on every page, including
|
|
5
|
+
// `/cli/*`, so navigation never loses its place.
|
|
6
|
+
const SECTIONS = ['Tutorials', 'How-to Guides', 'CLI', 'Reference']
|
|
7
|
+
|
|
8
|
+
async function sidebarSections(page: import('@playwright/test').Page) {
|
|
9
|
+
return await page.evaluate(() =>
|
|
10
|
+
Array.from(document.querySelectorAll('.VPSidebar .group .text'))
|
|
11
|
+
.map((el) => el.textContent?.trim())
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (const path of ['guide/tables.html', 'cli/index.html', 'cli/server.html']) {
|
|
17
|
+
test(`every section stays in the sidebar on ${path}`, async ({ page }) => {
|
|
18
|
+
await page.goto(`./${path}`)
|
|
19
|
+
await page.waitForSelector('.VPSidebar .group')
|
|
20
|
+
const sections = await sidebarSections(page)
|
|
21
|
+
for (const section of SECTIONS) {
|
|
22
|
+
expect(sections).toContain(section)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test('the CLI sidebar group lists all CLI subpages', async ({ page }) => {
|
|
28
|
+
await page.goto('./cli/index.html')
|
|
29
|
+
await page.waitForSelector('.VPSidebar .group')
|
|
30
|
+
const cliLinks = await page.evaluate(() => {
|
|
31
|
+
const groups = Array.from(document.querySelectorAll('.VPSidebar .group'))
|
|
32
|
+
const cli = groups.find(
|
|
33
|
+
(g) => g.querySelector('.text')?.textContent?.trim() === 'CLI'
|
|
34
|
+
)
|
|
35
|
+
return Array.from(cli?.querySelectorAll('a') ?? []).map(
|
|
36
|
+
(a) => new URL((a as HTMLAnchorElement).href).pathname
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
expect(cliLinks).toEqual([
|
|
40
|
+
'/dirsql/cli/',
|
|
41
|
+
'/dirsql/cli/server.html',
|
|
42
|
+
'/dirsql/cli/init.html',
|
|
43
|
+
'/dirsql/cli/config.html',
|
|
44
|
+
'/dirsql/cli/http-api.html'
|
|
45
|
+
])
|
|
46
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import config from '../../.vitepress/config'
|
|
3
|
+
|
|
4
|
+
type SidebarItem = { text?: string; link?: string; items?: SidebarItem[] }
|
|
5
|
+
|
|
6
|
+
describe('vitepress config', () => {
|
|
7
|
+
it('has the expected site title and base path', () => {
|
|
8
|
+
expect(config.title).toBe('dirsql')
|
|
9
|
+
expect(config.base).toBe('/dirsql/')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
// Regression guard: CLI docs live in their own `/cli/` section, not
|
|
13
|
+
// interleaved with the SDK how-to guides (see #179).
|
|
14
|
+
it('keeps CLI pages out of the How-to Guides group', () => {
|
|
15
|
+
const sidebar = config.themeConfig!.sidebar as Record<string, SidebarItem[]>
|
|
16
|
+
const howTo = sidebar['/'].find((group) => group.text === 'How-to Guides')
|
|
17
|
+
const links = (howTo!.items ?? []).map((item) => item.link)
|
|
18
|
+
expect(links).not.toContain('/guide/cli')
|
|
19
|
+
expect(links).not.toContain('/guide/init')
|
|
20
|
+
expect(links).not.toContain('/guide/config')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// Regression guard: the sidebar must never *replace* itself when entering a
|
|
24
|
+
// section. A path-scoped key (e.g. `/cli/`) swaps the whole tree out, which
|
|
25
|
+
// deletes the other sections and reads as the nav breaking (see #301). There
|
|
26
|
+
// must be exactly one global `/` sidebar.
|
|
27
|
+
it('has a single global sidebar with no replacing path-scoped keys', () => {
|
|
28
|
+
const sidebar = config.themeConfig!.sidebar as Record<string, SidebarItem[]>
|
|
29
|
+
expect(Object.keys(sidebar)).toEqual(['/'])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// The CLI section is self-contained: its group carries all CLI subpages,
|
|
33
|
+
// alongside (never instead of) the other sections (see #301).
|
|
34
|
+
it('shows every CLI subpage in a self-contained CLI group', () => {
|
|
35
|
+
const sidebar = config.themeConfig!.sidebar as Record<string, SidebarItem[]>
|
|
36
|
+
const groupTexts = sidebar['/'].map((group) => group.text)
|
|
37
|
+
expect(groupTexts).toEqual(['Tutorials', 'How-to Guides', 'CLI', 'Reference'])
|
|
38
|
+
|
|
39
|
+
const cli = sidebar['/'].find((group) => group.text === 'CLI')
|
|
40
|
+
const links = (cli!.items ?? []).map((item) => item.link)
|
|
41
|
+
expect(links).toEqual([
|
|
42
|
+
'/cli/',
|
|
43
|
+
'/cli/server',
|
|
44
|
+
'/cli/init',
|
|
45
|
+
'/cli/config',
|
|
46
|
+
'/cli/http-api'
|
|
47
|
+
])
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -59,6 +59,7 @@ new DirSQL({
|
|
|
59
59
|
tables?: TableDef[],
|
|
60
60
|
ignore?: string[],
|
|
61
61
|
config?: string,
|
|
62
|
+
extensions?: ExtensionSpec[], // [{ path: string, entrypoint?: string }]
|
|
62
63
|
})
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -76,7 +77,7 @@ In Python, the constructor starts scanning in a background thread and returns im
|
|
|
76
77
|
- `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
|
|
77
78
|
- `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
|
|
78
79
|
- `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly; its `[[dirsql.extension]]` entries are appended to any programmatic `extensions`.
|
|
79
|
-
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python
|
|
80
|
+
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`; TypeScript: `{ path, entrypoint? }` objects). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python, Rust, and TypeScript SDKs. See [Loading extensions](../cli/config.md#loading-extensions).
|
|
80
81
|
|
|
81
82
|
### Methods
|
|
82
83
|
|
|
@@ -162,7 +163,7 @@ JSON.stringify(db) // via db.toJSON()
|
|
|
162
163
|
|
|
163
164
|
:::
|
|
164
165
|
|
|
165
|
-
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`.
|
|
166
|
+
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`. All three SDK snapshots also include `extensions` -- an array of `{ path, entrypoint }` (empty when none are configured; `entrypoint` is `null` when no override was supplied). Excludes the original `config` path (already merged into `root` / `tables` / `ignore`), per-table `extract`, and per-table `name`. Available immediately after construction in Python and TypeScript; Rust's sync `build()` returns a ready instance.
|
|
166
167
|
|
|
167
168
|
---
|
|
168
169
|
|