dirsql 0.4.69__tar.gz → 0.4.71__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.4.69 → dirsql-0.4.71}/Cargo.lock +2 -2
- {dirsql-0.4.69 → dirsql-0.4.71}/PKG-INFO +1 -1
- {dirsql-0.4.69/packages/rust → dirsql-0.4.71}/docs/reference/path-tables.md +9 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.71/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +6 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/path-tables.md +9 -0
- dirsql-0.4.71/packages/python/e2e-attestations/claude-1267-posix-classes.json +7 -0
- dirsql-0.4.71/packages/python/e2e-attestations/claude-1271-node-modules-named.json +7 -0
- dirsql-0.4.71/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +37 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/Cargo.toml +1 -1
- {dirsql-0.4.69 → dirsql-0.4.71/packages/rust}/docs/reference/path-tables.md +9 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/db.rs +13 -28
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/lib.rs +1 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/matcher.rs +11 -1
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/path_table.rs +43 -2
- dirsql-0.4.71/packages/rust/src/posix_class.rs +313 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/scanner.rs +2 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/Cargo.toml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/README.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/_async.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/plan_entry_path.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/py.typed +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/read_config.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/resolve_configs_extension_specs.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/dirsql/resolve_package.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/AGENTS.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/context/.gitattributes +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/context/recipes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/context/usage.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/explanation.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/getting-started.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/embed.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/persist.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/index.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/package.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/plugins.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/reference/cli.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/reference/columns.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/reference/config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/README.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/conftest.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/context/.gitattributes +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/context/recipes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/context/usage.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/e2e/speed_of_light.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/README.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/context/.gitattributes +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/context/recipes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/context/usage.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/context.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/run.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/extension_resolution.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/on_file.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/row_event_flat.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/vtab_scaffold.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.69 → dirsql-0.4.71}/pyproject.toml +0 -0
|
@@ -552,7 +552,7 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
|
|
552
552
|
|
|
553
553
|
[[package]]
|
|
554
554
|
name = "dirsql"
|
|
555
|
-
version = "0.4.
|
|
555
|
+
version = "0.4.71"
|
|
556
556
|
dependencies = [
|
|
557
557
|
"assert_cmd",
|
|
558
558
|
"axum",
|
|
@@ -601,7 +601,7 @@ dependencies = [
|
|
|
601
601
|
|
|
602
602
|
[[package]]
|
|
603
603
|
name = "dirsql-py-ext"
|
|
604
|
-
version = "0.4.
|
|
604
|
+
version = "0.4.71"
|
|
605
605
|
dependencies = [
|
|
606
606
|
"dirsql",
|
|
607
607
|
"pyo3",
|
|
@@ -295,6 +295,15 @@ SELECT path FROM './dist'; -- scans dist/ even when gitignored
|
|
|
295
295
|
The `.gitignore` files in force there, including those above it, still
|
|
296
296
|
filter what lies beneath it.
|
|
297
297
|
|
|
298
|
+
A `node_modules` component after a glob names it too, at any depth:
|
|
299
|
+
|
|
300
|
+
```sql
|
|
301
|
+
SELECT path FROM './**/node_modules/*/package.json'; -- every node_modules
|
|
302
|
+
SELECT path FROM './*/node_modules/**'; -- one level down
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Only the literal name counts; `'./**/*.js'` still skips every `node_modules`.
|
|
306
|
+
|
|
298
307
|
### Hidden files
|
|
299
308
|
|
|
300
309
|
A path component starting with `.` is skipped unless the path spells it, the
|
|
@@ -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.4.
|
|
7
|
+
version = "0.4.71"
|
|
8
8
|
# abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
|
|
9
9
|
# `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
|
|
10
10
|
# (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
**Fixed** A path-table pattern that names `node_modules` after a glob
|
|
2
|
+
component now scans it: `'./**/node_modules/**'` lists every `node_modules`
|
|
3
|
+
in the tree and `'./*/node_modules/*/*'` the ones one level down. Only a
|
|
4
|
+
`node_modules` in the literal prefix used to count, so these returned nothing.
|
|
5
|
+
A pattern that does not name `node_modules`, such as `'./**'` or
|
|
6
|
+
`'./**/*.js'`, still skips it.
|
|
@@ -295,6 +295,15 @@ SELECT path FROM './dist'; -- scans dist/ even when gitignored
|
|
|
295
295
|
The `.gitignore` files in force there, including those above it, still
|
|
296
296
|
filter what lies beneath it.
|
|
297
297
|
|
|
298
|
+
A `node_modules` component after a glob names it too, at any depth:
|
|
299
|
+
|
|
300
|
+
```sql
|
|
301
|
+
SELECT path FROM './**/node_modules/*/package.json'; -- every node_modules
|
|
302
|
+
SELECT path FROM './*/node_modules/**'; -- one level down
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Only the literal name counts; `'./**/*.js'` still skips every `node_modules`.
|
|
306
|
+
|
|
298
307
|
### Hidden files
|
|
299
308
|
|
|
300
309
|
A path component starting with `.` is skipped unless the path spells it, the
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
### Core: `node_modules` named after a glob is scanned
|
|
2
|
+
|
|
3
|
+
#### Summary
|
|
4
|
+
|
|
5
|
+
A path-table pattern with a literal `node_modules` component after a glob,
|
|
6
|
+
such as `'./**/node_modules/**'`, now scans the `node_modules` directories it
|
|
7
|
+
names; it used to return nothing. Every surface that resolves a path-table is
|
|
8
|
+
affected: the CLI, the REPL, the HTTP server, the SDKs, and the `--on-file`
|
|
9
|
+
form. Nothing breaks; such a query can return more rows. A pattern that does
|
|
10
|
+
not name `node_modules` still skips it, and declared `[[table]]` globs are
|
|
11
|
+
unchanged.
|
|
12
|
+
|
|
13
|
+
#### Required changes
|
|
14
|
+
|
|
15
|
+
_None._
|
|
16
|
+
|
|
17
|
+
#### Deprecations removed
|
|
18
|
+
|
|
19
|
+
_None._
|
|
20
|
+
|
|
21
|
+
#### Behavior changes without code changes
|
|
22
|
+
|
|
23
|
+
- `'./**/node_modules/**'` lists files under every `node_modules`.
|
|
24
|
+
- `'./*/node_modules/*/*'` lists files two levels into each `node_modules`
|
|
25
|
+
one level down.
|
|
26
|
+
|
|
27
|
+
#### Verification
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cd "$(mktemp -d)"
|
|
31
|
+
mkdir -p node_modules/pkg pkg/node_modules/dep
|
|
32
|
+
touch node_modules/pkg/index.js pkg/node_modules/dep/i.js
|
|
33
|
+
dirsql query "SELECT path FROM './**/node_modules/*/*' ORDER BY path"
|
|
34
|
+
# expected: [{"path":"node_modules/pkg/index.js"},{"path":"pkg/node_modules/dep/i.js"}]
|
|
35
|
+
dirsql query "SELECT path FROM './**/*.js'"
|
|
36
|
+
# expected: []
|
|
37
|
+
```
|
|
@@ -6,7 +6,7 @@ description = "Ephemeral SQL index over a local directory"
|
|
|
6
6
|
# version stays for the binding crates (publish = false). The literal
|
|
7
7
|
# intentionally lags the published version: putitoutthere rewrites it to
|
|
8
8
|
# the planned release version at build time and never commits it back.
|
|
9
|
-
version = "0.4.
|
|
9
|
+
version = "0.4.71"
|
|
10
10
|
edition.workspace = true
|
|
11
11
|
# Literal `license` (not `license.workspace = true`) because
|
|
12
12
|
# putitoutthere's preflight check reads `[package].license` directly
|
|
@@ -295,6 +295,15 @@ SELECT path FROM './dist'; -- scans dist/ even when gitignored
|
|
|
295
295
|
The `.gitignore` files in force there, including those above it, still
|
|
296
296
|
filter what lies beneath it.
|
|
297
297
|
|
|
298
|
+
A `node_modules` component after a glob names it too, at any depth:
|
|
299
|
+
|
|
300
|
+
```sql
|
|
301
|
+
SELECT path FROM './**/node_modules/*/package.json'; -- every node_modules
|
|
302
|
+
SELECT path FROM './*/node_modules/**'; -- one level down
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Only the literal name counts; `'./**/*.js'` still skips every `node_modules`.
|
|
306
|
+
|
|
298
307
|
### Hidden files
|
|
299
308
|
|
|
300
309
|
A path component starting with `.` is skipped unless the path spells it, the
|
|
@@ -315,7 +315,8 @@ pub struct Db {
|
|
|
315
315
|
/// exactly where `files` used to exist implicitly. A user who declared
|
|
316
316
|
/// tables and forgot `files` gets the plain SQLite error.
|
|
317
317
|
hint_legacy_files_table: bool,
|
|
318
|
-
///
|
|
318
|
+
/// Configured skip rules a path-table scan applies on top of the table's
|
|
319
|
+
/// [`PathTable::default_ignores`].
|
|
319
320
|
path_table_ignore: Vec<String>,
|
|
320
321
|
/// Whether a path-table scan respects `.gitignore` files. On by default;
|
|
321
322
|
/// the CLI's `--no-ignore` turns it off.
|
|
@@ -351,14 +352,6 @@ fn worker_error(message: String) -> DbError {
|
|
|
351
352
|
DbError::Sqlite(rusqlite::Error::UserFunctionError(message.into()))
|
|
352
353
|
}
|
|
353
354
|
|
|
354
|
-
/// The skip rules a fresh `Db` starts with.
|
|
355
|
-
fn default_path_table_ignore() -> Vec<String> {
|
|
356
|
-
path_table::DEFAULT_IGNORES
|
|
357
|
-
.iter()
|
|
358
|
-
.map(|s| (*s).to_string())
|
|
359
|
-
.collect()
|
|
360
|
-
}
|
|
361
|
-
|
|
362
355
|
impl Db {
|
|
363
356
|
/// Open the default, ephemeral `Db`: an **anonymous disk-backed temp
|
|
364
357
|
/// database** (`Connection::open("")`), not `:memory:`.
|
|
@@ -382,7 +375,7 @@ impl Db {
|
|
|
382
375
|
scope,
|
|
383
376
|
path_table_root: None,
|
|
384
377
|
hint_legacy_files_table: false,
|
|
385
|
-
path_table_ignore:
|
|
378
|
+
path_table_ignore: Vec::new(),
|
|
386
379
|
path_table_gitignore: true,
|
|
387
380
|
path_table_parser: None,
|
|
388
381
|
calls: CallReporter::new(),
|
|
@@ -407,7 +400,7 @@ impl Db {
|
|
|
407
400
|
scope,
|
|
408
401
|
path_table_root: None,
|
|
409
402
|
hint_legacy_files_table: false,
|
|
410
|
-
path_table_ignore:
|
|
403
|
+
path_table_ignore: Vec::new(),
|
|
411
404
|
path_table_gitignore: true,
|
|
412
405
|
path_table_parser: None,
|
|
413
406
|
calls: CallReporter::new(),
|
|
@@ -1170,10 +1163,15 @@ impl Db {
|
|
|
1170
1163
|
.path_table_root
|
|
1171
1164
|
.as_deref()
|
|
1172
1165
|
.expect("a path-table resolves only under an index root");
|
|
1166
|
+
let ignore: Vec<String> = table
|
|
1167
|
+
.default_ignores()
|
|
1168
|
+
.map(str::to_string)
|
|
1169
|
+
.chain(self.path_table_ignore.iter().cloned())
|
|
1170
|
+
.collect();
|
|
1173
1171
|
self.conn.execute_batch(&path_table_ddl(
|
|
1174
1172
|
name,
|
|
1175
1173
|
table,
|
|
1176
|
-
&
|
|
1174
|
+
&ignore,
|
|
1177
1175
|
self.path_table_gitignore,
|
|
1178
1176
|
self.path_table_parser.as_deref(),
|
|
1179
1177
|
index_root,
|
|
@@ -3083,14 +3081,6 @@ mod tests {
|
|
|
3083
3081
|
);
|
|
3084
3082
|
}
|
|
3085
3083
|
|
|
3086
|
-
#[test]
|
|
3087
|
-
fn default_path_table_ignore_carries_the_documented_defaults() {
|
|
3088
|
-
assert_eq!(
|
|
3089
|
-
default_path_table_ignore(),
|
|
3090
|
-
vec!["**/node_modules/**".to_string(), "**/.git/**".to_string()]
|
|
3091
|
-
);
|
|
3092
|
-
}
|
|
3093
|
-
|
|
3094
3084
|
fn docs_path_table() -> PathTable {
|
|
3095
3085
|
PathTable {
|
|
3096
3086
|
root: PathBuf::from("/root"),
|
|
@@ -3304,17 +3294,12 @@ mod tests {
|
|
|
3304
3294
|
}
|
|
3305
3295
|
|
|
3306
3296
|
#[test]
|
|
3307
|
-
fn
|
|
3297
|
+
fn add_path_table_ignore_accumulates_configured_rules() {
|
|
3308
3298
|
let mut db = Db::new().unwrap();
|
|
3309
3299
|
db.add_path_table_ignore(vec!["*.tmp".to_string()]);
|
|
3300
|
+
db.add_path_table_ignore(vec!["*.bak".to_string()]);
|
|
3310
3301
|
|
|
3311
|
-
assert_eq!(db.path_table_ignore
|
|
3312
|
-
assert!(
|
|
3313
|
-
db.path_table_ignore
|
|
3314
|
-
.contains(&"**/node_modules/**".to_string()),
|
|
3315
|
-
"the built-in defaults must survive: {:?}",
|
|
3316
|
-
db.path_table_ignore
|
|
3317
|
-
);
|
|
3302
|
+
assert_eq!(db.path_table_ignore, ["*.tmp", "*.bak"]);
|
|
3318
3303
|
}
|
|
3319
3304
|
|
|
3320
3305
|
#[test]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use crate::posix_class::expand_posix_classes;
|
|
1
2
|
use globset::GlobBuilder;
|
|
2
3
|
use regex::{Regex, RegexBuilder};
|
|
3
4
|
use std::path::Path;
|
|
@@ -20,7 +21,9 @@ pub(crate) struct Pattern(Regex);
|
|
|
20
21
|
impl Pattern {
|
|
21
22
|
/// `*` and `?` stop at `/`; `**` crosses it.
|
|
22
23
|
pub(crate) fn new(glob: &str) -> Result<Self, GlobError> {
|
|
23
|
-
let glob = GlobBuilder::new(glob)
|
|
24
|
+
let glob = GlobBuilder::new(&expand_posix_classes(glob))
|
|
25
|
+
.literal_separator(true)
|
|
26
|
+
.build()?;
|
|
24
27
|
let regex = RegexBuilder::new(&unicode_regex(glob.regex()))
|
|
25
28
|
.dot_matches_new_line(true)
|
|
26
29
|
.build()?;
|
|
@@ -586,4 +589,11 @@ mod tests {
|
|
|
586
589
|
.is_empty()
|
|
587
590
|
);
|
|
588
591
|
}
|
|
592
|
+
|
|
593
|
+
#[test]
|
|
594
|
+
fn a_posix_class_in_a_table_glob_matches_its_characters() {
|
|
595
|
+
let matcher = TableMatcher::new(&[("notes/[[:digit:]].md", "n")], &[]).unwrap();
|
|
596
|
+
assert_eq!(names(&matcher, "notes/7.md"), vec!["n"]);
|
|
597
|
+
assert!(matcher.match_all(Path::new("notes/x.md")).is_empty());
|
|
598
|
+
}
|
|
589
599
|
}
|
|
@@ -16,8 +16,11 @@ use typed_path::{
|
|
|
16
16
|
|
|
17
17
|
/// Directories a path-table scan skips, at any depth. They are skipped only
|
|
18
18
|
/// *beneath* the literal part of the path you write, so naming one explicitly
|
|
19
|
-
/// still scans it.
|
|
20
|
-
|
|
19
|
+
/// still scans it. See [`PathTable::default_ignores`] for `node_modules`
|
|
20
|
+
/// named after a glob.
|
|
21
|
+
pub const DEFAULT_IGNORES: [&str; 2] = [NODE_MODULES_IGNORE, "**/.git/**"];
|
|
22
|
+
|
|
23
|
+
const NODE_MODULES_IGNORE: &str = "**/node_modules/**";
|
|
21
24
|
|
|
22
25
|
/// The glob a directory expands to: one level, like `ls`. Any depth is
|
|
23
26
|
/// spelled explicitly as `**`.
|
|
@@ -36,6 +39,18 @@ pub struct PathTable {
|
|
|
36
39
|
pub path_prefix: String,
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
impl PathTable {
|
|
43
|
+
/// The [`DEFAULT_IGNORES`] this table applies. A glob with a
|
|
44
|
+
/// `node_modules` component names that directory wherever the component
|
|
45
|
+
/// sits, so its skip rule is dropped.
|
|
46
|
+
pub fn default_ignores(&self) -> impl Iterator<Item = &'static str> {
|
|
47
|
+
let names_node_modules = self.glob.split('/').any(|c| c == "node_modules");
|
|
48
|
+
DEFAULT_IGNORES
|
|
49
|
+
.into_iter()
|
|
50
|
+
.filter(move |rule| !(names_node_modules && *rule == NODE_MODULES_IGNORE))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
/// What a name SQLite could not find turns out to be.
|
|
40
55
|
#[derive(Debug, PartialEq)]
|
|
41
56
|
pub enum Resolution {
|
|
@@ -315,6 +330,32 @@ mod tests {
|
|
|
315
330
|
assert_eq!(DEFAULT_IGNORES, ["**/node_modules/**", "**/.git/**"]);
|
|
316
331
|
}
|
|
317
332
|
|
|
333
|
+
fn table_globbing(glob: &str) -> PathTable {
|
|
334
|
+
PathTable {
|
|
335
|
+
root: PathBuf::from("/r"),
|
|
336
|
+
glob: glob.to_string(),
|
|
337
|
+
path_prefix: String::new(),
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
fn default_ignores_of(glob: &str) -> Vec<&'static str> {
|
|
342
|
+
table_globbing(glob).default_ignores().collect()
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
#[test]
|
|
346
|
+
fn a_glob_not_naming_node_modules_keeps_every_default_ignore() {
|
|
347
|
+
assert_eq!(default_ignores_of("**"), DEFAULT_IGNORES);
|
|
348
|
+
assert_eq!(default_ignores_of("**/*.js"), DEFAULT_IGNORES);
|
|
349
|
+
assert_eq!(default_ignores_of("node_modules*/*"), DEFAULT_IGNORES);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
#[test]
|
|
353
|
+
fn a_glob_naming_node_modules_anywhere_drops_its_ignore() {
|
|
354
|
+
assert_eq!(default_ignores_of("**/node_modules/**"), ["**/.git/**"]);
|
|
355
|
+
assert_eq!(default_ignores_of("*/node_modules/*/*"), ["**/.git/**"]);
|
|
356
|
+
assert_eq!(default_ignores_of("node_modules"), ["**/.git/**"]);
|
|
357
|
+
}
|
|
358
|
+
|
|
318
359
|
#[test]
|
|
319
360
|
fn has_glob_metacharacter_spots_each_metacharacter() {
|
|
320
361
|
assert!(has_glob_metacharacter("a*"));
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
//! POSIX character classes (`[[:digit:]]`) for globset, which has no
|
|
2
|
+
//! `[:name:]` syntax: each bracket expression holding one is rewritten into an
|
|
3
|
+
//! equivalent bracket of plain ranges before the glob is compiled.
|
|
4
|
+
|
|
5
|
+
/// Rewrite every bracket expression in `pattern` that holds a `[:name:]`
|
|
6
|
+
/// class into plain ranges. Brackets without one, unclosed brackets and
|
|
7
|
+
/// backslash-escaped characters are left exactly as written.
|
|
8
|
+
pub(crate) fn expand_posix_classes(pattern: &str) -> String {
|
|
9
|
+
let chars: Vec<char> = pattern.chars().collect();
|
|
10
|
+
let mut out = String::with_capacity(pattern.len());
|
|
11
|
+
let mut i = 0;
|
|
12
|
+
while i < chars.len() {
|
|
13
|
+
match chars[i] {
|
|
14
|
+
'\\' => {
|
|
15
|
+
let end = (i + 2).min(chars.len());
|
|
16
|
+
out.extend(&chars[i..end]);
|
|
17
|
+
i = end;
|
|
18
|
+
}
|
|
19
|
+
'[' => match bracket(&chars, i) {
|
|
20
|
+
Some((end, Some(rewritten))) => {
|
|
21
|
+
out.push_str(&rewritten);
|
|
22
|
+
i = end;
|
|
23
|
+
}
|
|
24
|
+
Some((end, None)) => {
|
|
25
|
+
out.extend(&chars[i..end]);
|
|
26
|
+
i = end;
|
|
27
|
+
}
|
|
28
|
+
None => {
|
|
29
|
+
out.push('[');
|
|
30
|
+
i += 1;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
c => {
|
|
34
|
+
out.push(c);
|
|
35
|
+
i += 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Parse the bracket expression opening at `start`. `None` when it never
|
|
43
|
+
/// closes; otherwise the index past its `]`, plus its rewrite when it holds a
|
|
44
|
+
/// class.
|
|
45
|
+
fn bracket(chars: &[char], start: usize) -> Option<(usize, Option<String>)> {
|
|
46
|
+
let mut j = start + 1;
|
|
47
|
+
let negated = matches!(chars.get(j), Some('!' | '^'));
|
|
48
|
+
if negated {
|
|
49
|
+
j += 1;
|
|
50
|
+
}
|
|
51
|
+
let body_start = j;
|
|
52
|
+
let mut ranges: Vec<(char, char)> = Vec::new();
|
|
53
|
+
let mut has_class = false;
|
|
54
|
+
// bash matches nothing at all when a range ends in a class, negated or not.
|
|
55
|
+
let mut range_into_class = false;
|
|
56
|
+
loop {
|
|
57
|
+
let c = *chars.get(j)?;
|
|
58
|
+
if c == ']' && j > body_start {
|
|
59
|
+
j += 1;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
if let Some((name, next)) = class_at(chars, j) {
|
|
63
|
+
ranges.extend_from_slice(class_ranges(&name));
|
|
64
|
+
has_class = true;
|
|
65
|
+
j = next;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
match (chars.get(j + 1), chars.get(j + 2)) {
|
|
69
|
+
(Some('-'), Some(&end)) if end != ']' => {
|
|
70
|
+
if let Some((_, next)) = class_at(chars, j + 2) {
|
|
71
|
+
has_class = true;
|
|
72
|
+
range_into_class = true;
|
|
73
|
+
j = next;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if c <= end {
|
|
77
|
+
ranges.push((c, end));
|
|
78
|
+
}
|
|
79
|
+
j += 3;
|
|
80
|
+
}
|
|
81
|
+
_ => {
|
|
82
|
+
ranges.push((c, c));
|
|
83
|
+
j += 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if !has_class {
|
|
88
|
+
return Some((j, None));
|
|
89
|
+
}
|
|
90
|
+
let rewritten = if range_into_class {
|
|
91
|
+
"[\0]".to_string()
|
|
92
|
+
} else {
|
|
93
|
+
render(negated, ranges)
|
|
94
|
+
};
|
|
95
|
+
Some((j, Some(rewritten)))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// The class `[:name:]` starting at `j`, with the index past its `:]`. A `]`
|
|
99
|
+
/// before the `:]` means the `[` is an ordinary character, as in bash.
|
|
100
|
+
fn class_at(chars: &[char], j: usize) -> Option<(String, usize)> {
|
|
101
|
+
if chars.get(j) != Some(&'[') || chars.get(j + 1) != Some(&':') {
|
|
102
|
+
return None;
|
|
103
|
+
}
|
|
104
|
+
let mut k = j + 2;
|
|
105
|
+
loop {
|
|
106
|
+
match (chars.get(k)?, chars.get(k + 1)) {
|
|
107
|
+
(':', Some(']')) => return Some((chars[j + 2..k].iter().collect(), k + 2)),
|
|
108
|
+
(']', _) => return None,
|
|
109
|
+
_ => k += 1,
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// The ASCII members of a class; an unknown name has none, as in bash.
|
|
115
|
+
fn class_ranges(name: &str) -> &'static [(char, char)] {
|
|
116
|
+
match name {
|
|
117
|
+
"alnum" => &[('0', '9'), ('A', 'Z'), ('a', 'z')],
|
|
118
|
+
"alpha" => &[('A', 'Z'), ('a', 'z')],
|
|
119
|
+
"ascii" => &[('\0', '\x7f')],
|
|
120
|
+
"blank" => &[(' ', ' '), ('\t', '\t')],
|
|
121
|
+
"cntrl" => &[('\0', '\x1f'), ('\x7f', '\x7f')],
|
|
122
|
+
"digit" => &[('0', '9')],
|
|
123
|
+
"graph" => &[('!', '~')],
|
|
124
|
+
"lower" => &[('a', 'z')],
|
|
125
|
+
"print" => &[(' ', '~')],
|
|
126
|
+
"punct" => &[('!', '/'), (':', '@'), ('[', '`'), ('{', '~')],
|
|
127
|
+
"space" => &[('\t', '\r'), (' ', ' ')],
|
|
128
|
+
"upper" => &[('A', 'Z')],
|
|
129
|
+
"word" => &[('0', '9'), ('A', 'Z'), ('a', 'z'), ('_', '_')],
|
|
130
|
+
"xdigit" => &[('0', '9'), ('A', 'F'), ('a', 'f')],
|
|
131
|
+
_ => &[],
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/// Characters globset reads as syntax at some position inside a bracket, so
|
|
136
|
+
/// they are pulled out of ranges and placed where they are literal.
|
|
137
|
+
const POSITIONAL: [char; 4] = [']', '-', '!', '^'];
|
|
138
|
+
|
|
139
|
+
/// A globset bracket matching exactly `ranges` (or everything else when
|
|
140
|
+
/// `negated`). A bracket never matches the separator, so `/` is dropped from a
|
|
141
|
+
/// positive set and added to a negated one. NUL, which no path holds, stands
|
|
142
|
+
/// in when nothing else may open the bracket.
|
|
143
|
+
fn render(negated: bool, ranges: Vec<(char, char)>) -> String {
|
|
144
|
+
let mut set: Vec<(u32, u32)> = ranges
|
|
145
|
+
.into_iter()
|
|
146
|
+
.map(|(a, b)| (a as u32, b as u32))
|
|
147
|
+
.collect();
|
|
148
|
+
set = without(set, '/');
|
|
149
|
+
if negated {
|
|
150
|
+
set.push(('/' as u32, '/' as u32));
|
|
151
|
+
}
|
|
152
|
+
let present = |c: char| set.iter().any(|&(a, b)| a <= c as u32 && c as u32 <= b);
|
|
153
|
+
let specials: Vec<char> = POSITIONAL.into_iter().filter(|&c| present(c)).collect();
|
|
154
|
+
let mut plain = POSITIONAL.into_iter().fold(set.clone(), without);
|
|
155
|
+
plain.sort_unstable();
|
|
156
|
+
if plain.is_empty() && !specials.contains(&']') {
|
|
157
|
+
plain.push((0, 0));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let mut out = String::from("[");
|
|
161
|
+
if negated {
|
|
162
|
+
out.push('!');
|
|
163
|
+
}
|
|
164
|
+
if specials.contains(&']') {
|
|
165
|
+
out.push(']');
|
|
166
|
+
}
|
|
167
|
+
for (a, b) in plain {
|
|
168
|
+
out.extend(char::from_u32(a));
|
|
169
|
+
if a != b {
|
|
170
|
+
out.push('-');
|
|
171
|
+
out.extend(char::from_u32(b));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for c in ['!', '^', '-'] {
|
|
175
|
+
if specials.contains(&c) {
|
|
176
|
+
out.push(c);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
out.push(']');
|
|
180
|
+
out
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/// `set` with `c` removed, splitting any range that spans it. `c` is never
|
|
184
|
+
/// NUL, so `c - 1` cannot underflow.
|
|
185
|
+
fn without(set: Vec<(u32, u32)>, c: char) -> Vec<(u32, u32)> {
|
|
186
|
+
let c = c as u32;
|
|
187
|
+
set.into_iter()
|
|
188
|
+
.flat_map(|(a, b)| [(a, b.min(c - 1)), (a.max(c + 1), b)])
|
|
189
|
+
.filter(|&(a, b)| a <= b)
|
|
190
|
+
.collect()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#[cfg(test)]
|
|
194
|
+
mod tests {
|
|
195
|
+
use super::*;
|
|
196
|
+
|
|
197
|
+
#[test]
|
|
198
|
+
fn a_class_becomes_its_ranges() {
|
|
199
|
+
assert_eq!(expand_posix_classes("[[:digit:]].md"), "[0-9].md");
|
|
200
|
+
assert_eq!(expand_posix_classes("[[:upper:]]*"), "[A-Z]*");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#[test]
|
|
204
|
+
fn every_named_class_expands() {
|
|
205
|
+
let cases = [
|
|
206
|
+
("alnum", "[0-9A-Za-z]"),
|
|
207
|
+
("alpha", "[A-Za-z]"),
|
|
208
|
+
("ascii", "[]\0- \"-,.0-\\_-\x7f!^-]"),
|
|
209
|
+
("blank", "[\t ]"),
|
|
210
|
+
("cntrl", "[\0-\x1f\x7f]"),
|
|
211
|
+
("digit", "[0-9]"),
|
|
212
|
+
("graph", "[]\"-,.0-\\_-~!^-]"),
|
|
213
|
+
("lower", "[a-z]"),
|
|
214
|
+
("print", "[] \"-,.0-\\_-~!^-]"),
|
|
215
|
+
("punct", "[]\"-,.:-@[-\\_-`{-~!^-]"),
|
|
216
|
+
("space", "[\t-\r ]"),
|
|
217
|
+
("upper", "[A-Z]"),
|
|
218
|
+
("word", "[0-9A-Z_a-z]"),
|
|
219
|
+
("xdigit", "[0-9A-Fa-f]"),
|
|
220
|
+
];
|
|
221
|
+
for (name, want) in cases {
|
|
222
|
+
assert_eq!(
|
|
223
|
+
expand_posix_classes(&format!("[[:{name}:]]")),
|
|
224
|
+
want,
|
|
225
|
+
"{name}"
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#[test]
|
|
231
|
+
fn a_negated_class_also_excludes_the_separator() {
|
|
232
|
+
assert_eq!(expand_posix_classes("[![:digit:]]"), "[!/0-9]");
|
|
233
|
+
assert_eq!(expand_posix_classes("[^[:digit:]]"), "[!/0-9]");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
#[test]
|
|
237
|
+
fn classes_and_characters_combine() {
|
|
238
|
+
assert_eq!(expand_posix_classes("[a[:digit:]]"), "[0-9a]");
|
|
239
|
+
assert_eq!(expand_posix_classes("[[:digit:][:upper:]]"), "[0-9A-Z]");
|
|
240
|
+
assert_eq!(expand_posix_classes("[[:digit:]x-z]"), "[0-9x-z]");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#[test]
|
|
244
|
+
fn a_dash_after_a_class_is_literal() {
|
|
245
|
+
assert_eq!(expand_posix_classes("[[:digit:]-z]"), "[0-9z-]");
|
|
246
|
+
assert_eq!(expand_posix_classes("[[:digit:]-]"), "[0-9-]");
|
|
247
|
+
assert_eq!(expand_posix_classes("[[:digit:]x-]"), "[0-9x-]");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
#[test]
|
|
251
|
+
fn a_leading_close_bracket_is_a_member() {
|
|
252
|
+
assert_eq!(expand_posix_classes("[][:digit:]]"), "[]0-9]");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#[test]
|
|
256
|
+
fn an_unknown_class_contributes_nothing() {
|
|
257
|
+
assert_eq!(expand_posix_classes("[[:foo:]a]"), "[a]");
|
|
258
|
+
assert_eq!(expand_posix_classes("[[:DIGIT:]]"), "[\0]");
|
|
259
|
+
assert_eq!(expand_posix_classes("[![:foo:]]"), "[!/]");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
#[test]
|
|
263
|
+
fn a_lone_bang_is_kept_off_the_negation_position() {
|
|
264
|
+
assert_eq!(expand_posix_classes("[[:foo:]!]"), "[\0!]");
|
|
265
|
+
assert_eq!(expand_posix_classes("[[:foo:]^]"), "[\0^]");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
#[test]
|
|
269
|
+
fn a_range_ending_in_a_class_matches_nothing() {
|
|
270
|
+
assert_eq!(expand_posix_classes("[x-[:digit:]]"), "[\0]");
|
|
271
|
+
assert_eq!(expand_posix_classes("[!x-[:digit:]]"), "[\0]");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
#[test]
|
|
275
|
+
fn a_reversed_range_beside_a_class_is_empty() {
|
|
276
|
+
assert_eq!(expand_posix_classes("[z-a[:digit:]]"), "[0-9]");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#[test]
|
|
280
|
+
fn a_bracket_without_a_class_is_untouched() {
|
|
281
|
+
for pattern in [
|
|
282
|
+
"[a-c]*",
|
|
283
|
+
"[!x].md",
|
|
284
|
+
"[]]",
|
|
285
|
+
"[[:a]",
|
|
286
|
+
"{a,b}/[xy]",
|
|
287
|
+
"[a:digit:]]",
|
|
288
|
+
"[[:a][:digit:]]",
|
|
289
|
+
] {
|
|
290
|
+
assert_eq!(expand_posix_classes(pattern), pattern);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
#[test]
|
|
295
|
+
fn an_unclosed_bracket_is_untouched() {
|
|
296
|
+
assert_eq!(expand_posix_classes("[[:digit:]"), "[[:digit:]");
|
|
297
|
+
assert_eq!(expand_posix_classes("a["), "a[");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#[test]
|
|
301
|
+
fn an_escaped_bracket_is_untouched() {
|
|
302
|
+
assert_eq!(expand_posix_classes("\\[[:digit:]]"), "\\[[:digit:]]");
|
|
303
|
+
assert_eq!(expand_posix_classes("a\\"), "a\\");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
#[test]
|
|
307
|
+
fn text_around_brackets_is_kept() {
|
|
308
|
+
assert_eq!(
|
|
309
|
+
expand_posix_classes("**/v[[:digit:]]/*.md"),
|
|
310
|
+
"**/v[0-9]/*.md"
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
}
|