@smthrs/std 0.0.0-stage → 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -0
- package/LICENSE +21 -0
- package/README.md +152 -2
- package/dist/cjs/ApplyPatch.d.ts +174 -0
- package/dist/cjs/ApplyPatch.d.ts.map +1 -0
- package/dist/cjs/ApplyPatch.js +309 -0
- package/dist/cjs/ApplyPatch.js.map +7 -0
- package/dist/cjs/Bash.d.ts +380 -0
- package/dist/cjs/Bash.d.ts.map +1 -0
- package/dist/cjs/Bash.js +332 -0
- package/dist/cjs/Bash.js.map +7 -0
- package/dist/cjs/Checkpoints.d.ts +279 -0
- package/dist/cjs/Checkpoints.d.ts.map +1 -0
- package/dist/cjs/Checkpoints.js +145 -0
- package/dist/cjs/Checkpoints.js.map +7 -0
- package/dist/cjs/Container.d.ts +132 -0
- package/dist/cjs/Container.d.ts.map +1 -0
- package/dist/cjs/Container.js +113 -0
- package/dist/cjs/Container.js.map +7 -0
- package/dist/cjs/Edit.d.ts +203 -0
- package/dist/cjs/Edit.d.ts.map +1 -0
- package/dist/cjs/Edit.js +258 -0
- package/dist/cjs/Edit.js.map +7 -0
- package/dist/cjs/ExaWebSearch.d.ts +22 -0
- package/dist/cjs/ExaWebSearch.d.ts.map +1 -0
- package/dist/cjs/ExaWebSearch.js +138 -0
- package/dist/cjs/ExaWebSearch.js.map +7 -0
- package/dist/cjs/Explore.d.ts +328 -0
- package/dist/cjs/Explore.d.ts.map +1 -0
- package/dist/cjs/Explore.js +90 -0
- package/dist/cjs/Explore.js.map +7 -0
- package/dist/cjs/Fetch.d.ts +130 -0
- package/dist/cjs/Fetch.d.ts.map +1 -0
- package/dist/cjs/Fetch.js +64 -0
- package/dist/cjs/Fetch.js.map +7 -0
- package/dist/cjs/Glob.d.ts +204 -0
- package/dist/cjs/Glob.d.ts.map +1 -0
- package/dist/cjs/Glob.js +94 -0
- package/dist/cjs/Glob.js.map +7 -0
- package/dist/cjs/Grep.d.ts +347 -0
- package/dist/cjs/Grep.d.ts.map +1 -0
- package/dist/cjs/Grep.js +181 -0
- package/dist/cjs/Grep.js.map +7 -0
- package/dist/cjs/HttpPost.d.ts +130 -0
- package/dist/cjs/HttpPost.d.ts.map +1 -0
- package/dist/cjs/HttpPost.js +72 -0
- package/dist/cjs/HttpPost.js.map +7 -0
- package/dist/cjs/LanguageServer.d.ts +90 -0
- package/dist/cjs/LanguageServer.d.ts.map +1 -0
- package/dist/cjs/LanguageServer.js +60 -0
- package/dist/cjs/LanguageServer.js.map +7 -0
- package/dist/cjs/Ls.d.ts +164 -0
- package/dist/cjs/Ls.d.ts.map +1 -0
- package/dist/cjs/Ls.js +136 -0
- package/dist/cjs/Ls.js.map +7 -0
- package/dist/cjs/Lsp.d.ts +125 -0
- package/dist/cjs/Lsp.d.ts.map +1 -0
- package/dist/cjs/Lsp.js +137 -0
- package/dist/cjs/Lsp.js.map +7 -0
- package/dist/cjs/Manifest.d.ts +918 -0
- package/dist/cjs/Manifest.d.ts.map +1 -0
- package/dist/cjs/Manifest.js +144 -0
- package/dist/cjs/Manifest.js.map +7 -0
- package/dist/cjs/NativeSearch.d.ts +38 -0
- package/dist/cjs/NativeSearch.d.ts.map +1 -0
- package/dist/cjs/NativeSearch.js +326 -0
- package/dist/cjs/NativeSearch.js.map +7 -0
- package/dist/cjs/NodeLanguageServer.d.ts +128 -0
- package/dist/cjs/NodeLanguageServer.d.ts.map +1 -0
- package/dist/cjs/NodeLanguageServer.js +796 -0
- package/dist/cjs/NodeLanguageServer.js.map +7 -0
- package/dist/cjs/PortableSearch.d.ts +24 -0
- package/dist/cjs/PortableSearch.d.ts.map +1 -0
- package/dist/cjs/PortableSearch.js +233 -0
- package/dist/cjs/PortableSearch.js.map +7 -0
- package/dist/cjs/Probe.d.ts +193 -0
- package/dist/cjs/Probe.d.ts.map +1 -0
- package/dist/cjs/Probe.js +134 -0
- package/dist/cjs/Probe.js.map +7 -0
- package/dist/cjs/Read.d.ts +189 -0
- package/dist/cjs/Read.d.ts.map +1 -0
- package/dist/cjs/Read.js +223 -0
- package/dist/cjs/Read.js.map +7 -0
- package/dist/cjs/Relocate.d.ts +73 -0
- package/dist/cjs/Relocate.d.ts.map +1 -0
- package/dist/cjs/Relocate.js +72 -0
- package/dist/cjs/Relocate.js.map +7 -0
- package/dist/cjs/Search.d.ts +163 -0
- package/dist/cjs/Search.d.ts.map +1 -0
- package/dist/cjs/Search.js +51 -0
- package/dist/cjs/Search.js.map +7 -0
- package/dist/cjs/SearchConformance.d.ts +115 -0
- package/dist/cjs/SearchConformance.d.ts.map +1 -0
- package/dist/cjs/SearchConformance.js +172 -0
- package/dist/cjs/SearchConformance.js.map +7 -0
- package/dist/cjs/SearchContract.d.ts +114 -0
- package/dist/cjs/SearchContract.d.ts.map +1 -0
- package/dist/cjs/SearchContract.js +339 -0
- package/dist/cjs/SearchContract.js.map +7 -0
- package/dist/cjs/ShellCommand.d.ts +164 -0
- package/dist/cjs/ShellCommand.d.ts.map +1 -0
- package/dist/cjs/ShellCommand.js +102 -0
- package/dist/cjs/ShellCommand.js.map +7 -0
- package/dist/cjs/StdError.d.ts +55 -0
- package/dist/cjs/StdError.d.ts.map +1 -0
- package/dist/cjs/StdError.js +74 -0
- package/dist/cjs/StdError.js.map +7 -0
- package/dist/cjs/TestRun.d.ts +311 -0
- package/dist/cjs/TestRun.d.ts.map +1 -0
- package/dist/cjs/TestRun.js +228 -0
- package/dist/cjs/TestRun.js.map +7 -0
- package/dist/cjs/TestRunner.d.ts +102 -0
- package/dist/cjs/TestRunner.d.ts.map +1 -0
- package/dist/cjs/TestRunner.js +54 -0
- package/dist/cjs/TestRunner.js.map +7 -0
- package/dist/cjs/TreeFingerprint.d.ts +140 -0
- package/dist/cjs/TreeFingerprint.d.ts.map +1 -0
- package/dist/cjs/TreeFingerprint.js +87 -0
- package/dist/cjs/TreeFingerprint.js.map +7 -0
- package/dist/cjs/UpdatePlan.d.ts +152 -0
- package/dist/cjs/UpdatePlan.d.ts.map +1 -0
- package/dist/cjs/UpdatePlan.js +87 -0
- package/dist/cjs/UpdatePlan.js.map +7 -0
- package/dist/cjs/WebFetch.d.ts +134 -0
- package/dist/cjs/WebFetch.d.ts.map +1 -0
- package/dist/cjs/WebFetch.js +140 -0
- package/dist/cjs/WebFetch.js.map +7 -0
- package/dist/cjs/WebSearch.d.ts +181 -0
- package/dist/cjs/WebSearch.d.ts.map +1 -0
- package/dist/cjs/WebSearch.js +86 -0
- package/dist/cjs/WebSearch.js.map +7 -0
- package/dist/cjs/Write.d.ts +147 -0
- package/dist/cjs/Write.d.ts.map +1 -0
- package/dist/cjs/Write.js +122 -0
- package/dist/cjs/Write.js.map +7 -0
- package/dist/cjs/index.d.ts +127 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +99 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/ApplyPatch.d.ts +145 -0
- package/dist/cjs/internal/ApplyPatch.d.ts.map +1 -0
- package/dist/cjs/internal/ApplyPatch.js +462 -0
- package/dist/cjs/internal/ApplyPatch.js.map +7 -0
- package/dist/cjs/internal/CodexText.d.ts +73 -0
- package/dist/cjs/internal/CodexText.d.ts.map +1 -0
- package/dist/cjs/internal/CodexText.js +108 -0
- package/dist/cjs/internal/CodexText.js.map +7 -0
- package/dist/cjs/internal/Declaration.d.ts +49 -0
- package/dist/cjs/internal/Declaration.d.ts.map +1 -0
- package/dist/cjs/internal/Declaration.js +46 -0
- package/dist/cjs/internal/Declaration.js.map +7 -0
- package/dist/cjs/internal/Diagnostics.d.ts +77 -0
- package/dist/cjs/internal/Diagnostics.d.ts.map +1 -0
- package/dist/cjs/internal/Diagnostics.js +89 -0
- package/dist/cjs/internal/Diagnostics.js.map +7 -0
- package/dist/cjs/internal/EnvelopePrecheck.d.ts +67 -0
- package/dist/cjs/internal/EnvelopePrecheck.d.ts.map +1 -0
- package/dist/cjs/internal/EnvelopePrecheck.js +124 -0
- package/dist/cjs/internal/EnvelopePrecheck.js.map +7 -0
- package/dist/cjs/internal/Exec.d.ts +139 -0
- package/dist/cjs/internal/Exec.d.ts.map +1 -0
- package/dist/cjs/internal/Exec.js +158 -0
- package/dist/cjs/internal/Exec.js.map +7 -0
- package/dist/cjs/internal/FileMutation.d.ts +109 -0
- package/dist/cjs/internal/FileMutation.d.ts.map +1 -0
- package/dist/cjs/internal/FileMutation.js +116 -0
- package/dist/cjs/internal/FileMutation.js.map +7 -0
- package/dist/cjs/internal/FsFailure.d.ts +38 -0
- package/dist/cjs/internal/FsFailure.d.ts.map +1 -0
- package/dist/cjs/internal/FsFailure.js +40 -0
- package/dist/cjs/internal/FsFailure.js.map +7 -0
- package/dist/cjs/internal/GitWorktree.d.ts +108 -0
- package/dist/cjs/internal/GitWorktree.d.ts.map +1 -0
- package/dist/cjs/internal/GitWorktree.js +276 -0
- package/dist/cjs/internal/GitWorktree.js.map +7 -0
- package/dist/cjs/internal/Grouping.d.ts +51 -0
- package/dist/cjs/internal/Grouping.d.ts.map +1 -0
- package/dist/cjs/internal/Grouping.js +83 -0
- package/dist/cjs/internal/Grouping.js.map +7 -0
- package/dist/cjs/internal/Html.d.ts +20 -0
- package/dist/cjs/internal/Html.d.ts.map +1 -0
- package/dist/cjs/internal/Html.js +81 -0
- package/dist/cjs/internal/Html.js.map +7 -0
- package/dist/cjs/internal/Http.d.ts +95 -0
- package/dist/cjs/internal/Http.d.ts.map +1 -0
- package/dist/cjs/internal/Http.js +153 -0
- package/dist/cjs/internal/Http.js.map +7 -0
- package/dist/cjs/internal/HttpNetwork.d.ts +27 -0
- package/dist/cjs/internal/HttpNetwork.d.ts.map +1 -0
- package/dist/cjs/internal/HttpNetwork.js +146 -0
- package/dist/cjs/internal/HttpNetwork.js.map +7 -0
- package/dist/cjs/internal/Ignore.d.ts +37 -0
- package/dist/cjs/internal/Ignore.d.ts.map +1 -0
- package/dist/cjs/internal/Ignore.js +100 -0
- package/dist/cjs/internal/Ignore.js.map +7 -0
- package/dist/cjs/internal/LinearRegex.d.ts +19 -0
- package/dist/cjs/internal/LinearRegex.d.ts.map +1 -0
- package/dist/cjs/internal/LinearRegex.js +166 -0
- package/dist/cjs/internal/LinearRegex.js.map +7 -0
- package/dist/cjs/internal/Match.d.ts +85 -0
- package/dist/cjs/internal/Match.d.ts.map +1 -0
- package/dist/cjs/internal/Match.js +99 -0
- package/dist/cjs/internal/Match.js.map +7 -0
- package/dist/cjs/internal/Paths.d.ts +23 -0
- package/dist/cjs/internal/Paths.d.ts.map +1 -0
- package/dist/cjs/internal/Paths.js +52 -0
- package/dist/cjs/internal/Paths.js.map +7 -0
- package/dist/cjs/internal/Preserve.d.ts +25 -0
- package/dist/cjs/internal/Preserve.d.ts.map +1 -0
- package/dist/cjs/internal/Preserve.js +88 -0
- package/dist/cjs/internal/Preserve.js.map +7 -0
- package/dist/cjs/internal/Prune.d.ts +35 -0
- package/dist/cjs/internal/Prune.d.ts.map +1 -0
- package/dist/cjs/internal/Prune.js +54 -0
- package/dist/cjs/internal/Prune.js.map +7 -0
- package/dist/cjs/internal/SearchContract.d.ts +63 -0
- package/dist/cjs/internal/SearchContract.d.ts.map +1 -0
- package/dist/cjs/internal/SearchContract.js +46 -0
- package/dist/cjs/internal/SearchContract.js.map +7 -0
- package/dist/cjs/internal/Symbols.d.ts +39 -0
- package/dist/cjs/internal/Symbols.d.ts.map +1 -0
- package/dist/cjs/internal/Symbols.js +59 -0
- package/dist/cjs/internal/Symbols.js.map +7 -0
- package/dist/cjs/internal/TestReport.d.ts +52 -0
- package/dist/cjs/internal/TestReport.d.ts.map +1 -0
- package/dist/cjs/internal/TestReport.js +131 -0
- package/dist/cjs/internal/TestReport.js.map +7 -0
- package/dist/cjs/internal/Text.d.ts +114 -0
- package/dist/cjs/internal/Text.d.ts.map +1 -0
- package/dist/cjs/internal/Text.js +82 -0
- package/dist/cjs/internal/Text.js.map +7 -0
- package/dist/cjs/internal/Url.d.ts +13 -0
- package/dist/cjs/internal/Url.d.ts.map +1 -0
- package/dist/cjs/internal/Url.js +35 -0
- package/dist/cjs/internal/Url.js.map +7 -0
- package/dist/cjs/internal/Walk.d.ts +72 -0
- package/dist/cjs/internal/Walk.d.ts.map +1 -0
- package/dist/cjs/internal/Walk.js +108 -0
- package/dist/cjs/internal/Walk.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/ApplyPatch.d.ts +174 -0
- package/dist/esm/ApplyPatch.d.ts.map +1 -0
- package/dist/esm/ApplyPatch.js +346 -0
- package/dist/esm/ApplyPatch.js.map +1 -0
- package/dist/esm/Bash.d.ts +380 -0
- package/dist/esm/Bash.d.ts.map +1 -0
- package/dist/esm/Bash.js +505 -0
- package/dist/esm/Bash.js.map +1 -0
- package/dist/esm/Checkpoints.d.ts +279 -0
- package/dist/esm/Checkpoints.d.ts.map +1 -0
- package/dist/esm/Checkpoints.js +298 -0
- package/dist/esm/Checkpoints.js.map +1 -0
- package/dist/esm/Container.d.ts +132 -0
- package/dist/esm/Container.d.ts.map +1 -0
- package/dist/esm/Container.js +151 -0
- package/dist/esm/Container.js.map +1 -0
- package/dist/esm/Edit.d.ts +203 -0
- package/dist/esm/Edit.d.ts.map +1 -0
- package/dist/esm/Edit.js +296 -0
- package/dist/esm/Edit.js.map +1 -0
- package/dist/esm/ExaWebSearch.d.ts +22 -0
- package/dist/esm/ExaWebSearch.d.ts.map +1 -0
- package/dist/esm/ExaWebSearch.js +107 -0
- package/dist/esm/ExaWebSearch.js.map +1 -0
- package/dist/esm/Explore.d.ts +328 -0
- package/dist/esm/Explore.d.ts.map +1 -0
- package/dist/esm/Explore.js +106 -0
- package/dist/esm/Explore.js.map +1 -0
- package/dist/esm/Fetch.d.ts +130 -0
- package/dist/esm/Fetch.d.ts.map +1 -0
- package/dist/esm/Fetch.js +91 -0
- package/dist/esm/Fetch.js.map +1 -0
- package/dist/esm/Glob.d.ts +204 -0
- package/dist/esm/Glob.d.ts.map +1 -0
- package/dist/esm/Glob.js +177 -0
- package/dist/esm/Glob.js.map +1 -0
- package/dist/esm/Grep.d.ts +347 -0
- package/dist/esm/Grep.d.ts.map +1 -0
- package/dist/esm/Grep.js +289 -0
- package/dist/esm/Grep.js.map +1 -0
- package/dist/esm/HttpPost.d.ts +130 -0
- package/dist/esm/HttpPost.d.ts.map +1 -0
- package/dist/esm/HttpPost.js +89 -0
- package/dist/esm/HttpPost.js.map +1 -0
- package/dist/esm/LanguageServer.d.ts +90 -0
- package/dist/esm/LanguageServer.d.ts.map +1 -0
- package/dist/esm/LanguageServer.js +57 -0
- package/dist/esm/LanguageServer.js.map +1 -0
- package/dist/esm/Ls.d.ts +164 -0
- package/dist/esm/Ls.d.ts.map +1 -0
- package/dist/esm/Ls.js +178 -0
- package/dist/esm/Ls.js.map +1 -0
- package/dist/esm/Lsp.d.ts +125 -0
- package/dist/esm/Lsp.d.ts.map +1 -0
- package/dist/esm/Lsp.js +165 -0
- package/dist/esm/Lsp.js.map +1 -0
- package/dist/esm/Manifest.d.ts +918 -0
- package/dist/esm/Manifest.d.ts.map +1 -0
- package/dist/esm/Manifest.js +153 -0
- package/dist/esm/Manifest.js.map +1 -0
- package/dist/esm/NativeSearch.d.ts +38 -0
- package/dist/esm/NativeSearch.d.ts.map +1 -0
- package/dist/esm/NativeSearch.js +378 -0
- package/dist/esm/NativeSearch.js.map +1 -0
- package/dist/esm/NodeLanguageServer.d.ts +128 -0
- package/dist/esm/NodeLanguageServer.d.ts.map +1 -0
- package/dist/esm/NodeLanguageServer.js +843 -0
- package/dist/esm/NodeLanguageServer.js.map +1 -0
- package/dist/esm/PortableSearch.d.ts +24 -0
- package/dist/esm/PortableSearch.d.ts.map +1 -0
- package/dist/esm/PortableSearch.js +240 -0
- package/dist/esm/PortableSearch.js.map +1 -0
- package/dist/esm/Probe.d.ts +193 -0
- package/dist/esm/Probe.d.ts.map +1 -0
- package/dist/esm/Probe.js +225 -0
- package/dist/esm/Probe.js.map +1 -0
- package/dist/esm/Read.d.ts +189 -0
- package/dist/esm/Read.d.ts.map +1 -0
- package/dist/esm/Read.js +300 -0
- package/dist/esm/Read.js.map +1 -0
- package/dist/esm/Relocate.d.ts +73 -0
- package/dist/esm/Relocate.d.ts.map +1 -0
- package/dist/esm/Relocate.js +153 -0
- package/dist/esm/Relocate.js.map +1 -0
- package/dist/esm/Search.d.ts +163 -0
- package/dist/esm/Search.d.ts.map +1 -0
- package/dist/esm/Search.js +47 -0
- package/dist/esm/Search.js.map +1 -0
- package/dist/esm/SearchConformance.d.ts +115 -0
- package/dist/esm/SearchConformance.d.ts.map +1 -0
- package/dist/esm/SearchConformance.js +193 -0
- package/dist/esm/SearchConformance.js.map +1 -0
- package/dist/esm/SearchContract.d.ts +114 -0
- package/dist/esm/SearchContract.d.ts.map +1 -0
- package/dist/esm/SearchContract.js +461 -0
- package/dist/esm/SearchContract.js.map +1 -0
- package/dist/esm/ShellCommand.d.ts +164 -0
- package/dist/esm/ShellCommand.d.ts.map +1 -0
- package/dist/esm/ShellCommand.js +159 -0
- package/dist/esm/ShellCommand.js.map +1 -0
- package/dist/esm/StdError.d.ts +55 -0
- package/dist/esm/StdError.d.ts.map +1 -0
- package/dist/esm/StdError.js +71 -0
- package/dist/esm/StdError.js.map +1 -0
- package/dist/esm/TestRun.d.ts +311 -0
- package/dist/esm/TestRun.d.ts.map +1 -0
- package/dist/esm/TestRun.js +316 -0
- package/dist/esm/TestRun.js.map +1 -0
- package/dist/esm/TestRunner.d.ts +102 -0
- package/dist/esm/TestRunner.d.ts.map +1 -0
- package/dist/esm/TestRunner.js +68 -0
- package/dist/esm/TestRunner.js.map +1 -0
- package/dist/esm/TreeFingerprint.d.ts +140 -0
- package/dist/esm/TreeFingerprint.d.ts.map +1 -0
- package/dist/esm/TreeFingerprint.js +170 -0
- package/dist/esm/TreeFingerprint.js.map +1 -0
- package/dist/esm/UpdatePlan.d.ts +152 -0
- package/dist/esm/UpdatePlan.d.ts.map +1 -0
- package/dist/esm/UpdatePlan.js +129 -0
- package/dist/esm/UpdatePlan.js.map +1 -0
- package/dist/esm/WebFetch.d.ts +134 -0
- package/dist/esm/WebFetch.d.ts.map +1 -0
- package/dist/esm/WebFetch.js +151 -0
- package/dist/esm/WebFetch.js.map +1 -0
- package/dist/esm/WebSearch.d.ts +181 -0
- package/dist/esm/WebSearch.d.ts.map +1 -0
- package/dist/esm/WebSearch.js +134 -0
- package/dist/esm/WebSearch.js.map +1 -0
- package/dist/esm/Write.d.ts +147 -0
- package/dist/esm/Write.d.ts.map +1 -0
- package/dist/esm/Write.js +144 -0
- package/dist/esm/Write.js.map +1 -0
- package/dist/esm/index.d.ts +127 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +127 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/ApplyPatch.d.ts +145 -0
- package/dist/esm/internal/ApplyPatch.d.ts.map +1 -0
- package/dist/esm/internal/ApplyPatch.js +489 -0
- package/dist/esm/internal/ApplyPatch.js.map +1 -0
- package/dist/esm/internal/CodexText.d.ts +73 -0
- package/dist/esm/internal/CodexText.d.ts.map +1 -0
- package/dist/esm/internal/CodexText.js +156 -0
- package/dist/esm/internal/CodexText.js.map +1 -0
- package/dist/esm/internal/Declaration.d.ts +49 -0
- package/dist/esm/internal/Declaration.d.ts.map +1 -0
- package/dist/esm/internal/Declaration.js +42 -0
- package/dist/esm/internal/Declaration.js.map +1 -0
- package/dist/esm/internal/Diagnostics.d.ts +77 -0
- package/dist/esm/internal/Diagnostics.d.ts.map +1 -0
- package/dist/esm/internal/Diagnostics.js +99 -0
- package/dist/esm/internal/Diagnostics.js.map +1 -0
- package/dist/esm/internal/EnvelopePrecheck.d.ts +67 -0
- package/dist/esm/internal/EnvelopePrecheck.d.ts.map +1 -0
- package/dist/esm/internal/EnvelopePrecheck.js +167 -0
- package/dist/esm/internal/EnvelopePrecheck.js.map +1 -0
- package/dist/esm/internal/Exec.d.ts +139 -0
- package/dist/esm/internal/Exec.d.ts.map +1 -0
- package/dist/esm/internal/Exec.js +193 -0
- package/dist/esm/internal/Exec.js.map +1 -0
- package/dist/esm/internal/FileMutation.d.ts +109 -0
- package/dist/esm/internal/FileMutation.d.ts.map +1 -0
- package/dist/esm/internal/FileMutation.js +123 -0
- package/dist/esm/internal/FileMutation.js.map +1 -0
- package/dist/esm/internal/FsFailure.d.ts +38 -0
- package/dist/esm/internal/FsFailure.d.ts.map +1 -0
- package/dist/esm/internal/FsFailure.js +39 -0
- package/dist/esm/internal/FsFailure.js.map +1 -0
- package/dist/esm/internal/GitWorktree.d.ts +108 -0
- package/dist/esm/internal/GitWorktree.d.ts.map +1 -0
- package/dist/esm/internal/GitWorktree.js +352 -0
- package/dist/esm/internal/GitWorktree.js.map +1 -0
- package/dist/esm/internal/Grouping.d.ts +51 -0
- package/dist/esm/internal/Grouping.d.ts.map +1 -0
- package/dist/esm/internal/Grouping.js +99 -0
- package/dist/esm/internal/Grouping.js.map +1 -0
- package/dist/esm/internal/Html.d.ts +20 -0
- package/dist/esm/internal/Html.d.ts.map +1 -0
- package/dist/esm/internal/Html.js +70 -0
- package/dist/esm/internal/Html.js.map +1 -0
- package/dist/esm/internal/Http.d.ts +95 -0
- package/dist/esm/internal/Http.d.ts.map +1 -0
- package/dist/esm/internal/Http.js +154 -0
- package/dist/esm/internal/Http.js.map +1 -0
- package/dist/esm/internal/HttpNetwork.d.ts +27 -0
- package/dist/esm/internal/HttpNetwork.d.ts.map +1 -0
- package/dist/esm/internal/HttpNetwork.js +114 -0
- package/dist/esm/internal/HttpNetwork.js.map +1 -0
- package/dist/esm/internal/Ignore.d.ts +37 -0
- package/dist/esm/internal/Ignore.d.ts.map +1 -0
- package/dist/esm/internal/Ignore.js +128 -0
- package/dist/esm/internal/Ignore.js.map +1 -0
- package/dist/esm/internal/LinearRegex.d.ts +19 -0
- package/dist/esm/internal/LinearRegex.d.ts.map +1 -0
- package/dist/esm/internal/LinearRegex.js +176 -0
- package/dist/esm/internal/LinearRegex.js.map +1 -0
- package/dist/esm/internal/Match.d.ts +85 -0
- package/dist/esm/internal/Match.d.ts.map +1 -0
- package/dist/esm/internal/Match.js +142 -0
- package/dist/esm/internal/Match.js.map +1 -0
- package/dist/esm/internal/Paths.d.ts +23 -0
- package/dist/esm/internal/Paths.d.ts.map +1 -0
- package/dist/esm/internal/Paths.js +40 -0
- package/dist/esm/internal/Paths.js.map +1 -0
- package/dist/esm/internal/Preserve.d.ts +25 -0
- package/dist/esm/internal/Preserve.d.ts.map +1 -0
- package/dist/esm/internal/Preserve.js +70 -0
- package/dist/esm/internal/Preserve.js.map +1 -0
- package/dist/esm/internal/Prune.d.ts +35 -0
- package/dist/esm/internal/Prune.d.ts.map +1 -0
- package/dist/esm/internal/Prune.js +60 -0
- package/dist/esm/internal/Prune.js.map +1 -0
- package/dist/esm/internal/SearchContract.d.ts +63 -0
- package/dist/esm/internal/SearchContract.d.ts.map +1 -0
- package/dist/esm/internal/SearchContract.js +66 -0
- package/dist/esm/internal/SearchContract.js.map +1 -0
- package/dist/esm/internal/Symbols.d.ts +39 -0
- package/dist/esm/internal/Symbols.d.ts.map +1 -0
- package/dist/esm/internal/Symbols.js +79 -0
- package/dist/esm/internal/Symbols.js.map +1 -0
- package/dist/esm/internal/TestReport.d.ts +52 -0
- package/dist/esm/internal/TestReport.d.ts.map +1 -0
- package/dist/esm/internal/TestReport.js +172 -0
- package/dist/esm/internal/TestReport.js.map +1 -0
- package/dist/esm/internal/Text.d.ts +114 -0
- package/dist/esm/internal/Text.d.ts.map +1 -0
- package/dist/esm/internal/Text.js +130 -0
- package/dist/esm/internal/Text.js.map +1 -0
- package/dist/esm/internal/Url.d.ts +13 -0
- package/dist/esm/internal/Url.d.ts.map +1 -0
- package/dist/esm/internal/Url.js +27 -0
- package/dist/esm/internal/Url.js.map +1 -0
- package/dist/esm/internal/Walk.d.ts +72 -0
- package/dist/esm/internal/Walk.d.ts.map +1 -0
- package/dist/esm/internal/Walk.js +126 -0
- package/dist/esm/internal/Walk.js.map +1 -0
- package/docs/README.md +117 -0
- package/docs/api.md +472 -0
- package/docs/concepts/effects-and-capabilities.md +136 -0
- package/docs/concepts/flows-and-handlers.md +115 -0
- package/docs/concepts/limits-and-disclosure.md +102 -0
- package/docs/concepts/search-contract.md +182 -0
- package/docs/guides/bind-the-standard-flows.md +114 -0
- package/docs/guides/implement-a-search-peer.md +133 -0
- package/docs/guides/pin-a-checkpoint.md +141 -0
- package/docs/guides/query-a-language-server.md +257 -0
- package/docs/guides/reach-the-network.md +141 -0
- package/docs/guides/read-and-edit-a-file.md +240 -0
- package/docs/guides/run-a-shell-command.md +215 -0
- package/docs/guides/run-the-test-suite.md +154 -0
- package/docs/guides/search-a-workspace.md +148 -0
- package/docs/installation.md +111 -0
- package/docs/quickstart.md +125 -0
- package/docs/reference/flows.md +556 -0
- package/docs/troubleshooting.md +322 -0
- package/package.json +439 -3
- package/src/ApplyPatch.ts +458 -0
- package/src/Bash.ts +607 -0
- package/src/Checkpoints.ts +422 -0
- package/src/Container.ts +212 -0
- package/src/Edit.ts +366 -0
- package/src/ExaWebSearch.ts +145 -0
- package/src/Explore.ts +139 -0
- package/src/Fetch.ts +117 -0
- package/src/Glob.ts +200 -0
- package/src/Grep.ts +320 -0
- package/src/HttpPost.ts +120 -0
- package/src/LanguageServer.ts +110 -0
- package/src/Ls.ts +228 -0
- package/src/Lsp.ts +184 -0
- package/src/Manifest.ts +162 -0
- package/src/NativeSearch.ts +457 -0
- package/src/NodeLanguageServer.ts +1148 -0
- package/src/PortableSearch.ts +264 -0
- package/src/Probe.ts +284 -0
- package/src/Read.ts +359 -0
- package/src/Relocate.ts +166 -0
- package/src/Search.ts +185 -0
- package/src/SearchConformance.ts +288 -0
- package/src/SearchContract.ts +489 -0
- package/src/ShellCommand.ts +201 -0
- package/src/StdError.ts +80 -0
- package/src/TestRun.ts +401 -0
- package/src/TestRunner.ts +119 -0
- package/src/TreeFingerprint.ts +200 -0
- package/src/UpdatePlan.ts +171 -0
- package/src/WebFetch.ts +194 -0
- package/src/WebSearch.ts +165 -0
- package/src/Write.ts +195 -0
- package/src/index.ts +154 -0
- package/src/internal/ApplyPatch.ts +601 -0
- package/src/internal/CodexText.ts +182 -0
- package/src/internal/Declaration.ts +60 -0
- package/src/internal/Diagnostics.ts +134 -0
- package/src/internal/EnvelopePrecheck.ts +233 -0
- package/src/internal/Exec.ts +314 -0
- package/src/internal/FileMutation.ts +231 -0
- package/src/internal/FsFailure.ts +51 -0
- package/src/internal/GitWorktree.ts +491 -0
- package/src/internal/Grouping.ts +106 -0
- package/src/internal/Html.ts +87 -0
- package/src/internal/Http.ts +209 -0
- package/src/internal/HttpNetwork.ts +153 -0
- package/src/internal/Ignore.ts +135 -0
- package/src/internal/LinearRegex.ts +173 -0
- package/src/internal/Match.ts +172 -0
- package/src/internal/Paths.ts +42 -0
- package/src/internal/Preserve.ts +108 -0
- package/src/internal/Prune.ts +62 -0
- package/src/internal/SearchContract.ts +77 -0
- package/src/internal/Symbols.ts +88 -0
- package/src/internal/TestReport.ts +194 -0
- package/src/internal/Text.ts +170 -0
- package/src/internal/Url.ts +23 -0
- package/src/internal/Walk.ts +176 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The implementation seam for the ripgrep search contract.
|
|
3
|
+
*
|
|
4
|
+
* Both implementations answer the same normalized calls. `PortableSearch`
|
|
5
|
+
* performs the work in-process; `NativeSearch` drives the `rg` executable.
|
|
6
|
+
* Callers select an implementation by Layer and cannot observe which one was
|
|
7
|
+
* selected from the result.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
import { Context, Effect, Layer } from "effect";
|
|
12
|
+
import * as StdError from "./StdError.ts";
|
|
13
|
+
/**
|
|
14
|
+
* Normalized grep input shared by both implementations.
|
|
15
|
+
*
|
|
16
|
+
* @category models
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
export interface GrepInput {
|
|
20
|
+
readonly pattern: string;
|
|
21
|
+
readonly root: string;
|
|
22
|
+
readonly fixedStrings: boolean;
|
|
23
|
+
readonly ignoreCase: boolean;
|
|
24
|
+
readonly smartCase: boolean;
|
|
25
|
+
readonly globs: ReadonlyArray<string>;
|
|
26
|
+
readonly beforeContext: number;
|
|
27
|
+
readonly afterContext: number;
|
|
28
|
+
readonly maxCount?: number | undefined;
|
|
29
|
+
readonly filesWithMatches: boolean;
|
|
30
|
+
/** Opt out of root-scoped .gitignore rules; defaults to false. */
|
|
31
|
+
readonly noIgnore?: boolean | undefined;
|
|
32
|
+
readonly hidden: boolean;
|
|
33
|
+
readonly symbols: boolean;
|
|
34
|
+
readonly limit: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* One matching or context line, as a peer produces it before grouping.
|
|
38
|
+
*
|
|
39
|
+
* @category models
|
|
40
|
+
* @since 1.0.0
|
|
41
|
+
*/
|
|
42
|
+
export interface GrepLine {
|
|
43
|
+
readonly file: string;
|
|
44
|
+
readonly line: number;
|
|
45
|
+
readonly text: string;
|
|
46
|
+
readonly kind: "match" | "context";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One context line carried inside the match it belongs to.
|
|
50
|
+
*
|
|
51
|
+
* @category models
|
|
52
|
+
* @since 1.0.0
|
|
53
|
+
*/
|
|
54
|
+
export interface ContextLine {
|
|
55
|
+
readonly line: number;
|
|
56
|
+
readonly text: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The definition enclosing a hit, when the file's shape says so plainly.
|
|
60
|
+
*
|
|
61
|
+
* @category models
|
|
62
|
+
* @since 1.0.0
|
|
63
|
+
*/
|
|
64
|
+
export interface Symbol {
|
|
65
|
+
readonly kind: string;
|
|
66
|
+
readonly name: string;
|
|
67
|
+
readonly startLine: number;
|
|
68
|
+
readonly endLine: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* One hit: the matching line, the context that belongs to it, and the
|
|
72
|
+
* definition it sits in.
|
|
73
|
+
*
|
|
74
|
+
* @category models
|
|
75
|
+
* @since 1.0.0
|
|
76
|
+
*/
|
|
77
|
+
export interface GrepMatch {
|
|
78
|
+
readonly file: string;
|
|
79
|
+
readonly line: number;
|
|
80
|
+
readonly text: string;
|
|
81
|
+
readonly before: ReadonlyArray<ContextLine>;
|
|
82
|
+
readonly after: ReadonlyArray<ContextLine>;
|
|
83
|
+
readonly symbol?: Symbol | undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Normalized grep output.
|
|
87
|
+
*
|
|
88
|
+
* @category models
|
|
89
|
+
* @since 1.0.0
|
|
90
|
+
*/
|
|
91
|
+
export interface GrepOutput {
|
|
92
|
+
readonly matches: ReadonlyArray<GrepMatch>;
|
|
93
|
+
readonly files: ReadonlyArray<string>;
|
|
94
|
+
readonly filesSearched: number;
|
|
95
|
+
readonly skippedBinary: number;
|
|
96
|
+
readonly truncated: boolean;
|
|
97
|
+
readonly notice?: string | undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Normalized glob input.
|
|
101
|
+
*
|
|
102
|
+
* @category models
|
|
103
|
+
* @since 1.0.0
|
|
104
|
+
*/
|
|
105
|
+
export interface GlobInput {
|
|
106
|
+
readonly pattern: string;
|
|
107
|
+
readonly root: string;
|
|
108
|
+
/** Opt out of root-scoped .gitignore rules; defaults to false. */
|
|
109
|
+
readonly noIgnore?: boolean | undefined;
|
|
110
|
+
readonly hidden: boolean;
|
|
111
|
+
readonly limit: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Normalized glob output.
|
|
115
|
+
*
|
|
116
|
+
* @category models
|
|
117
|
+
* @since 1.0.0
|
|
118
|
+
*/
|
|
119
|
+
export interface GlobOutput {
|
|
120
|
+
readonly paths: ReadonlyArray<string>;
|
|
121
|
+
readonly total: number;
|
|
122
|
+
readonly truncated: boolean;
|
|
123
|
+
readonly notice?: string | undefined;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The one search contract implemented by native and portable peers.
|
|
127
|
+
*
|
|
128
|
+
* @category services
|
|
129
|
+
* @since 1.0.0
|
|
130
|
+
*/
|
|
131
|
+
export interface Search {
|
|
132
|
+
readonly grep: (input: GrepInput) => Effect.Effect<GrepOutput, StdError.StdError>;
|
|
133
|
+
readonly glob: (input: GlobInput) => Effect.Effect<GlobOutput, StdError.StdError>;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The {@link Search} service tag.
|
|
137
|
+
*
|
|
138
|
+
* @category services
|
|
139
|
+
* @since 1.0.0
|
|
140
|
+
*/
|
|
141
|
+
export declare const Search: Context.Service<Search, Search>;
|
|
142
|
+
/**
|
|
143
|
+
* Builds a search service from its two operations.
|
|
144
|
+
*
|
|
145
|
+
* @category constructors
|
|
146
|
+
* @since 1.0.0
|
|
147
|
+
*/
|
|
148
|
+
export declare const make: (service: Search) => Search;
|
|
149
|
+
/**
|
|
150
|
+
* Builds an unavailable search service for compositions that deliberately omit search.
|
|
151
|
+
*
|
|
152
|
+
* @category constructors
|
|
153
|
+
* @since 1.0.0
|
|
154
|
+
*/
|
|
155
|
+
export declare const makeNoop: () => Search;
|
|
156
|
+
/**
|
|
157
|
+
* Provides {@link makeNoop}.
|
|
158
|
+
*
|
|
159
|
+
* @category layers
|
|
160
|
+
* @since 1.0.0
|
|
161
|
+
*/
|
|
162
|
+
export declare const layerNoop: Layer.Layer<Search>;
|
|
163
|
+
//# sourceMappingURL=Search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Search.d.ts","sourceRoot":"","sources":["../../src/Search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The implementation seam for the ripgrep search contract.
|
|
3
|
+
*
|
|
4
|
+
* Both implementations answer the same normalized calls. `PortableSearch`
|
|
5
|
+
* performs the work in-process; `NativeSearch` drives the `rg` executable.
|
|
6
|
+
* Callers select an implementation by Layer and cannot observe which one was
|
|
7
|
+
* selected from the result.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
import { Context, Effect, Layer } from "effect";
|
|
12
|
+
import * as StdError from "./StdError.js";
|
|
13
|
+
/**
|
|
14
|
+
* The {@link Search} service tag.
|
|
15
|
+
*
|
|
16
|
+
* @category services
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
export const Search = Context.Service("@smthrs/std/Search");
|
|
20
|
+
/**
|
|
21
|
+
* Builds a search service from its two operations.
|
|
22
|
+
*
|
|
23
|
+
* @category constructors
|
|
24
|
+
* @since 1.0.0
|
|
25
|
+
*/
|
|
26
|
+
export const make = (service) => Search.of(service);
|
|
27
|
+
/**
|
|
28
|
+
* Builds an unavailable search service for compositions that deliberately omit search.
|
|
29
|
+
*
|
|
30
|
+
* @category constructors
|
|
31
|
+
* @since 1.0.0
|
|
32
|
+
*/
|
|
33
|
+
export const makeNoop = () => {
|
|
34
|
+
const unavailable = () => Effect.fail(new StdError.StdError({
|
|
35
|
+
code: "provider_unavailable",
|
|
36
|
+
message: "No search implementation is configured"
|
|
37
|
+
}));
|
|
38
|
+
return make({ grep: unavailable, glob: unavailable });
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Provides {@link makeNoop}.
|
|
42
|
+
*
|
|
43
|
+
* @category layers
|
|
44
|
+
* @since 1.0.0
|
|
45
|
+
*/
|
|
46
|
+
export const layerNoop = Layer.succeed(Search, makeNoop());
|
|
47
|
+
//# sourceMappingURL=Search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Search.js","sourceRoot":"","sources":["../../src/Search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAqIzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAoC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;AAE5F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAA;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAW,EAAE;IACnC,MAAM,WAAW,GAAG,GAAG,EAAE,CACvB,MAAM,CAAC,IAAI,CACT,IAAI,QAAQ,CAAC,QAAQ,CAAC;QACpB,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,wCAAwC;KAClD,CAAC,CACH,CAAA;IACH,OAAO,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAA;AACvD,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAwB,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA","sourcesContent":["/**\n * The implementation seam for the ripgrep search contract.\n *\n * Both implementations answer the same normalized calls. `PortableSearch`\n * performs the work in-process; `NativeSearch` drives the `rg` executable.\n * Callers select an implementation by Layer and cannot observe which one was\n * selected from the result.\n *\n * @since 1.0.0\n */\n\nimport { Context, Effect, Layer } from \"effect\"\nimport * as StdError from \"./StdError.ts\"\n\n/**\n * Normalized grep input shared by both implementations.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GrepInput {\n readonly pattern: string\n readonly root: string\n readonly fixedStrings: boolean\n readonly ignoreCase: boolean\n readonly smartCase: boolean\n readonly globs: ReadonlyArray<string>\n readonly beforeContext: number\n readonly afterContext: number\n readonly maxCount?: number | undefined\n readonly filesWithMatches: boolean\n /** Opt out of root-scoped .gitignore rules; defaults to false. */\n readonly noIgnore?: boolean | undefined\n readonly hidden: boolean\n readonly symbols: boolean\n readonly limit: number\n}\n\n/**\n * One matching or context line, as a peer produces it before grouping.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GrepLine {\n readonly file: string\n readonly line: number\n readonly text: string\n readonly kind: \"match\" | \"context\"\n}\n\n/**\n * One context line carried inside the match it belongs to.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface ContextLine {\n readonly line: number\n readonly text: string\n}\n\n/**\n * The definition enclosing a hit, when the file's shape says so plainly.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Symbol {\n readonly kind: string\n readonly name: string\n readonly startLine: number\n readonly endLine: number\n}\n\n/**\n * One hit: the matching line, the context that belongs to it, and the\n * definition it sits in.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GrepMatch {\n readonly file: string\n readonly line: number\n readonly text: string\n readonly before: ReadonlyArray<ContextLine>\n readonly after: ReadonlyArray<ContextLine>\n readonly symbol?: Symbol | undefined\n}\n\n/**\n * Normalized grep output.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GrepOutput {\n readonly matches: ReadonlyArray<GrepMatch>\n readonly files: ReadonlyArray<string>\n readonly filesSearched: number\n readonly skippedBinary: number\n readonly truncated: boolean\n readonly notice?: string | undefined\n}\n\n/**\n * Normalized glob input.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GlobInput {\n readonly pattern: string\n readonly root: string\n /** Opt out of root-scoped .gitignore rules; defaults to false. */\n readonly noIgnore?: boolean | undefined\n readonly hidden: boolean\n readonly limit: number\n}\n\n/**\n * Normalized glob output.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GlobOutput {\n readonly paths: ReadonlyArray<string>\n readonly total: number\n readonly truncated: boolean\n readonly notice?: string | undefined\n}\n\n/**\n * The one search contract implemented by native and portable peers.\n *\n * @category services\n * @since 1.0.0\n */\nexport interface Search {\n readonly grep: (input: GrepInput) => Effect.Effect<GrepOutput, StdError.StdError>\n readonly glob: (input: GlobInput) => Effect.Effect<GlobOutput, StdError.StdError>\n}\n\n/**\n * The {@link Search} service tag.\n *\n * @category services\n * @since 1.0.0\n */\nexport const Search: Context.Service<Search, Search> = Context.Service(\"@smthrs/std/Search\")\n\n/**\n * Builds a search service from its two operations.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const make = (service: Search): Search => Search.of(service)\n\n/**\n * Builds an unavailable search service for compositions that deliberately omit search.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const makeNoop = (): Search => {\n const unavailable = () =>\n Effect.fail(\n new StdError.StdError({\n code: \"provider_unavailable\",\n message: \"No search implementation is configured\"\n })\n )\n return make({ grep: unavailable, glob: unavailable })\n}\n\n/**\n * Provides {@link makeNoop}.\n *\n * @category layers\n * @since 1.0.0\n */\nexport const layerNoop: Layer.Layer<Search> = Layer.succeed(Search, makeNoop())\n"]}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A differential conformance kit for {@link Search} implementations.
|
|
3
|
+
*
|
|
4
|
+
* `Search` is a public extension seam: a host binds its own implementation and
|
|
5
|
+
* every `grep` and `glob` call in the package goes through it. Two peers ship
|
|
6
|
+
* here, and the contract they are held to used to live only in
|
|
7
|
+
* `test/SearchConformance.test.ts` — a file `package.json` does not publish, so
|
|
8
|
+
* a third-party peer had the seam and no way to prove it filled it. Worse, the
|
|
9
|
+
* cases there are hand-picked: they pin the divergences somebody already
|
|
10
|
+
* found. A literal `?` matched `fo` in one peer and `foo?` in the other for as
|
|
11
|
+
* long as nobody thought to write that case down.
|
|
12
|
+
*
|
|
13
|
+
* This module is the other half. It generates a tree and a batch of calls from
|
|
14
|
+
* a seed, runs them through two implementations, and reports every answer that
|
|
15
|
+
* differs. Nothing here knows which peer is right: a divergence is the finding,
|
|
16
|
+
* and the reference peer to compare against is the caller's choice —
|
|
17
|
+
* `PortableSearch` is the obvious one, because it needs no external binary.
|
|
18
|
+
*
|
|
19
|
+
* The generator deliberately stays inside the ground both peers claim to
|
|
20
|
+
* share: no symlinks, no unreadable directories, no CRLF, no NUL bytes, no
|
|
21
|
+
* filename a shell would have to quote. Those are the cases the hand-written
|
|
22
|
+
* table pins one by one, with an expected value that says which behaviour is
|
|
23
|
+
* intended. A generator cannot say that; it can only say the two disagree.
|
|
24
|
+
*
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
import * as Effect from "effect/Effect";
|
|
28
|
+
import * as FileSystem from "effect/FileSystem";
|
|
29
|
+
import * as Path from "effect/Path";
|
|
30
|
+
import type * as Search from "./Search.ts";
|
|
31
|
+
/**
|
|
32
|
+
* One file the generated tree contains.
|
|
33
|
+
*
|
|
34
|
+
* @category models
|
|
35
|
+
* @since 1.0.0
|
|
36
|
+
*/
|
|
37
|
+
export interface GeneratedFile {
|
|
38
|
+
/** Path relative to the tree root, always with `/` separators. */
|
|
39
|
+
readonly path: string;
|
|
40
|
+
readonly content: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A generated tree plus the calls to make against it.
|
|
44
|
+
*
|
|
45
|
+
* @category models
|
|
46
|
+
* @since 1.0.0
|
|
47
|
+
*/
|
|
48
|
+
export interface Plan {
|
|
49
|
+
readonly seed: number;
|
|
50
|
+
readonly root: string;
|
|
51
|
+
readonly files: ReadonlyArray<GeneratedFile>;
|
|
52
|
+
readonly grep: ReadonlyArray<Search.GrepInput>;
|
|
53
|
+
readonly glob: ReadonlyArray<Search.GlobInput>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* One call two implementations answered differently.
|
|
57
|
+
*
|
|
58
|
+
* `subject` and `reference` are the rendered answers, so a report names the
|
|
59
|
+
* bytes that differ rather than saying only that they did.
|
|
60
|
+
*
|
|
61
|
+
* @category models
|
|
62
|
+
* @since 1.0.0
|
|
63
|
+
*/
|
|
64
|
+
export interface Divergence {
|
|
65
|
+
readonly call: "grep" | "glob";
|
|
66
|
+
readonly input: Search.GrepInput | Search.GlobInput;
|
|
67
|
+
readonly subject: string;
|
|
68
|
+
readonly reference: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Builds a reproducible tree and call batch from a seed.
|
|
72
|
+
*
|
|
73
|
+
* The same seed and root always produce the same plan, so a divergence a run
|
|
74
|
+
* reports can be replayed exactly by rerunning that seed.
|
|
75
|
+
*
|
|
76
|
+
* @category generators
|
|
77
|
+
* @since 1.0.0
|
|
78
|
+
*/
|
|
79
|
+
export declare const plan: (options: {
|
|
80
|
+
readonly seed: number;
|
|
81
|
+
readonly root: string;
|
|
82
|
+
readonly files?: number | undefined;
|
|
83
|
+
readonly calls?: number | undefined;
|
|
84
|
+
}) => Plan;
|
|
85
|
+
/**
|
|
86
|
+
* Writes a plan's tree under its root.
|
|
87
|
+
*
|
|
88
|
+
* @category generators
|
|
89
|
+
* @since 1.0.0
|
|
90
|
+
*/
|
|
91
|
+
export declare const materialize: (target: Plan) => Effect.Effect<void, never, FileSystem.FileSystem | Path.Path>;
|
|
92
|
+
/**
|
|
93
|
+
* Runs every call in a plan through two implementations and reports the
|
|
94
|
+
* answers that differ.
|
|
95
|
+
*
|
|
96
|
+
* A failure is compared like any other answer: two peers that refuse the same
|
|
97
|
+
* call with the same code agree, and one that refuses where the other answers
|
|
98
|
+
* has diverged.
|
|
99
|
+
*
|
|
100
|
+
* @category conformance
|
|
101
|
+
* @since 1.0.0
|
|
102
|
+
*/
|
|
103
|
+
export declare const compare: (options: {
|
|
104
|
+
readonly plan: Plan;
|
|
105
|
+
readonly subject: Search.Search;
|
|
106
|
+
readonly reference: Search.Search;
|
|
107
|
+
}) => Effect.Effect<ReadonlyArray<Divergence>>;
|
|
108
|
+
/**
|
|
109
|
+
* Renders divergences as the report a failing conformance run should print.
|
|
110
|
+
*
|
|
111
|
+
* @category conformance
|
|
112
|
+
* @since 1.0.0
|
|
113
|
+
*/
|
|
114
|
+
export declare const report: (divergences: ReadonlyArray<Divergence>) => string;
|
|
115
|
+
//# sourceMappingURL=SearchConformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchConformance.d.ts","sourceRoot":"","sources":["../../src/SearchConformance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,MAAM,aAAa,CAAA;AAG1C;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IAC5C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;CAC/C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;IACnD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAiDD;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,GAAI,SAAS;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC,KAAG,IAyEH,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,IAAI,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAW3D,CAAA;AAaJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,GAAI,SAAS;IAC/B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAA;CAClC,KAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAcvC,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GAAI,aAAa,aAAa,CAAC,UAAU,CAAC,KAAG,MAOhD,CAAA"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A differential conformance kit for {@link Search} implementations.
|
|
3
|
+
*
|
|
4
|
+
* `Search` is a public extension seam: a host binds its own implementation and
|
|
5
|
+
* every `grep` and `glob` call in the package goes through it. Two peers ship
|
|
6
|
+
* here, and the contract they are held to used to live only in
|
|
7
|
+
* `test/SearchConformance.test.ts` — a file `package.json` does not publish, so
|
|
8
|
+
* a third-party peer had the seam and no way to prove it filled it. Worse, the
|
|
9
|
+
* cases there are hand-picked: they pin the divergences somebody already
|
|
10
|
+
* found. A literal `?` matched `fo` in one peer and `foo?` in the other for as
|
|
11
|
+
* long as nobody thought to write that case down.
|
|
12
|
+
*
|
|
13
|
+
* This module is the other half. It generates a tree and a batch of calls from
|
|
14
|
+
* a seed, runs them through two implementations, and reports every answer that
|
|
15
|
+
* differs. Nothing here knows which peer is right: a divergence is the finding,
|
|
16
|
+
* and the reference peer to compare against is the caller's choice —
|
|
17
|
+
* `PortableSearch` is the obvious one, because it needs no external binary.
|
|
18
|
+
*
|
|
19
|
+
* The generator deliberately stays inside the ground both peers claim to
|
|
20
|
+
* share: no symlinks, no unreadable directories, no CRLF, no NUL bytes, no
|
|
21
|
+
* filename a shell would have to quote. Those are the cases the hand-written
|
|
22
|
+
* table pins one by one, with an expected value that says which behaviour is
|
|
23
|
+
* intended. A generator cannot say that; it can only say the two disagree.
|
|
24
|
+
*
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
import * as Effect from "effect/Effect";
|
|
28
|
+
import * as FileSystem from "effect/FileSystem";
|
|
29
|
+
import * as Path from "effect/Path";
|
|
30
|
+
/**
|
|
31
|
+
* mulberry32: 32 bits of state, uniform enough for fixture generation and
|
|
32
|
+
* reproducible from a seed on every host, which a shared `Math.random` is not.
|
|
33
|
+
*/
|
|
34
|
+
const random = (seed) => {
|
|
35
|
+
let state = seed >>> 0;
|
|
36
|
+
return () => {
|
|
37
|
+
state = (state + 0x6D2B79F5) >>> 0;
|
|
38
|
+
let value = Math.imul(state ^ (state >>> 15), 1 | state);
|
|
39
|
+
value = (value + Math.imul(value ^ (value >>> 7), 61 | value)) ^ value;
|
|
40
|
+
return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
const pick = (next, values) => values[Math.floor(next() * values.length)];
|
|
44
|
+
const chance = (next, probability) => next() < probability;
|
|
45
|
+
// Names both peers walk identically: no separator, no dot prefix outside the
|
|
46
|
+
// two deliberate hidden entries, no name a directory skip list contains, and
|
|
47
|
+
// no character that would need quoting on a command line.
|
|
48
|
+
const stems = ["alpha", "beta", "gamma", "Delta", "e-psilon", "ze_ta", "eta2", "th.eta", "iota", "kappa"];
|
|
49
|
+
const extensions = [".ts", ".js", ".txt", ".py", ".md"];
|
|
50
|
+
const directories = ["", "one", "one/two", "three", "three/four/five"];
|
|
51
|
+
// Lines drawn from a vocabulary that mixes the needle, near misses, regex
|
|
52
|
+
// metacharacters that must survive `fixedStrings`, and definition headers the
|
|
53
|
+
// `symbols` option reads.
|
|
54
|
+
const lines = [
|
|
55
|
+
"needle",
|
|
56
|
+
"a needle in the line",
|
|
57
|
+
"Needle capitalised",
|
|
58
|
+
"no match here",
|
|
59
|
+
"needle? with a question mark",
|
|
60
|
+
"a+b and x*y and [z]",
|
|
61
|
+
"def widen(value):",
|
|
62
|
+
"class Widget:",
|
|
63
|
+
" needle = value",
|
|
64
|
+
"function widen(value) {",
|
|
65
|
+
"",
|
|
66
|
+
"trailing needle"
|
|
67
|
+
];
|
|
68
|
+
const patterns = ["needle", "Needle", "needle?", "a+b", "[z]", "^needle$", "widen", "no match at all"];
|
|
69
|
+
const globPatterns = ["**/*.ts", "*.ts", "**/*", "one/**/*.ts", "**/*.{ts,js}", "**/alpha*"];
|
|
70
|
+
/**
|
|
71
|
+
* Builds a reproducible tree and call batch from a seed.
|
|
72
|
+
*
|
|
73
|
+
* The same seed and root always produce the same plan, so a divergence a run
|
|
74
|
+
* reports can be replayed exactly by rerunning that seed.
|
|
75
|
+
*
|
|
76
|
+
* @category generators
|
|
77
|
+
* @since 1.0.0
|
|
78
|
+
*/
|
|
79
|
+
export const plan = (options) => {
|
|
80
|
+
const next = random(options.seed);
|
|
81
|
+
const fileCount = options.files ?? 12;
|
|
82
|
+
const callCount = options.calls ?? 12;
|
|
83
|
+
const files = [];
|
|
84
|
+
for (let index = 0; index < fileCount; index++) {
|
|
85
|
+
const directory = pick(next, directories);
|
|
86
|
+
// The index makes every generated path unique, including repeated random picks.
|
|
87
|
+
const name = `${pick(next, stems)}${index}${pick(next, extensions)}`;
|
|
88
|
+
const path = directory === "" ? name : `${directory}/${name}`;
|
|
89
|
+
const body = [];
|
|
90
|
+
for (let line = 0; line < 1 + Math.floor(next() * 8); line++)
|
|
91
|
+
body.push(pick(next, lines));
|
|
92
|
+
files.push({ path, content: `${body.join("\n")}${chance(next, 0.8) ? "\n" : ""}` });
|
|
93
|
+
}
|
|
94
|
+
// Always exercise precedence, anchoring, directory pruning and nested
|
|
95
|
+
// negation alongside each seed's generated content (without a git repo).
|
|
96
|
+
if (fileCount > 0) {
|
|
97
|
+
files.push({ path: ".gitignore", content: "*.ignored\n!keep.ignored\n/root-only.ts\ncache/\n" }, { path: "drop.ignored", content: "needle\n" }, { path: "keep.ignored", content: "needle\n" }, { path: "root-only.ts", content: "needle\n" }, { path: "cache/a.ts", content: "needle\n" }, { path: "nested/.gitignore", content: "!keep.ignored\n/anchored.ts\nframes/\n" }, { path: "nested/keep.ignored", content: "needle\n" }, { path: "nested/drop.ignored", content: "needle\n" }, { path: "nested/anchored.ts", content: "needle\n" }, { path: "nested/deep/anchored.ts", content: "needle\n" }, { path: "nested/root-only.ts", content: "needle\n" }, { path: "nested/frames/a.ts", content: "needle\n" }, { path: "other/frames", content: "needle\n" });
|
|
98
|
+
}
|
|
99
|
+
const roots = [options.root, ...files.map((entry) => `${options.root}/${entry.path}`)];
|
|
100
|
+
const grep = [];
|
|
101
|
+
for (let index = 0; index < callCount; index++) {
|
|
102
|
+
const fixedStrings = chance(next, 0.4);
|
|
103
|
+
// `Grep.run` refuses `ignoreCase` together with `smartCase` as mutually
|
|
104
|
+
// exclusive, so a generated call carrying both would be exploring ground
|
|
105
|
+
// the contract does not describe.
|
|
106
|
+
const ignoreCase = chance(next, 0.25);
|
|
107
|
+
grep.push({
|
|
108
|
+
pattern: pick(next, patterns),
|
|
109
|
+
root: chance(next, 0.75) ? options.root : pick(next, roots),
|
|
110
|
+
fixedStrings,
|
|
111
|
+
ignoreCase,
|
|
112
|
+
smartCase: !ignoreCase && chance(next, 0.3),
|
|
113
|
+
globs: chance(next, 0.4) ? [pick(next, ["*.ts", "*.txt", "!*.js", "**/*.ts"])] : [],
|
|
114
|
+
beforeContext: Math.floor(next() * 3),
|
|
115
|
+
afterContext: Math.floor(next() * 3),
|
|
116
|
+
...(chance(next, 0.3) ? { maxCount: 1 + Math.floor(next() * 2) } : {}),
|
|
117
|
+
filesWithMatches: chance(next, 0.25),
|
|
118
|
+
hidden: chance(next, 0.5),
|
|
119
|
+
noIgnore: chance(next, 0.25),
|
|
120
|
+
symbols: chance(next, 0.3),
|
|
121
|
+
limit: 1 + Math.floor(next() * 40)
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const glob = [];
|
|
125
|
+
for (let index = 0; index < callCount; index++) {
|
|
126
|
+
glob.push({
|
|
127
|
+
pattern: pick(next, globPatterns),
|
|
128
|
+
root: options.root,
|
|
129
|
+
hidden: chance(next, 0.5),
|
|
130
|
+
noIgnore: chance(next, 0.25),
|
|
131
|
+
limit: 1 + Math.floor(next() * 20)
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return { seed: options.seed, root: options.root, files, grep, glob };
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Writes a plan's tree under its root.
|
|
138
|
+
*
|
|
139
|
+
* @category generators
|
|
140
|
+
* @since 1.0.0
|
|
141
|
+
*/
|
|
142
|
+
export const materialize = (target) => Effect.gen(function* () {
|
|
143
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
144
|
+
const path = yield* Path.Path;
|
|
145
|
+
yield* Effect.forEach(target.files, (entry) => {
|
|
146
|
+
const absolute = path.join(target.root, ...entry.path.split("/"));
|
|
147
|
+
return fileSystem.makeDirectory(path.dirname(absolute), { recursive: true }).pipe(Effect.andThen(fileSystem.writeFileString(absolute, entry.content)), Effect.orDie);
|
|
148
|
+
}, { discard: true });
|
|
149
|
+
});
|
|
150
|
+
/** A typed answer rendered so two of them can be compared as text. */
|
|
151
|
+
const rendered = (effect) => effect.pipe(Effect.match({
|
|
152
|
+
onSuccess: (value) => JSON.stringify(value),
|
|
153
|
+
onFailure: (error) => JSON.stringify({ failure: error.code })
|
|
154
|
+
}));
|
|
155
|
+
/**
|
|
156
|
+
* Runs every call in a plan through two implementations and reports the
|
|
157
|
+
* answers that differ.
|
|
158
|
+
*
|
|
159
|
+
* A failure is compared like any other answer: two peers that refuse the same
|
|
160
|
+
* call with the same code agree, and one that refuses where the other answers
|
|
161
|
+
* has diverged.
|
|
162
|
+
*
|
|
163
|
+
* @category conformance
|
|
164
|
+
* @since 1.0.0
|
|
165
|
+
*/
|
|
166
|
+
export const compare = (options) => Effect.gen(function* () {
|
|
167
|
+
const divergences = [];
|
|
168
|
+
for (const input of options.plan.grep) {
|
|
169
|
+
const subject = yield* rendered(options.subject.grep(input));
|
|
170
|
+
const reference = yield* rendered(options.reference.grep(input));
|
|
171
|
+
if (subject !== reference)
|
|
172
|
+
divergences.push({ call: "grep", input, subject, reference });
|
|
173
|
+
}
|
|
174
|
+
for (const input of options.plan.glob) {
|
|
175
|
+
const subject = yield* rendered(options.subject.glob(input));
|
|
176
|
+
const reference = yield* rendered(options.reference.glob(input));
|
|
177
|
+
if (subject !== reference)
|
|
178
|
+
divergences.push({ call: "glob", input, subject, reference });
|
|
179
|
+
}
|
|
180
|
+
return divergences;
|
|
181
|
+
});
|
|
182
|
+
/**
|
|
183
|
+
* Renders divergences as the report a failing conformance run should print.
|
|
184
|
+
*
|
|
185
|
+
* @category conformance
|
|
186
|
+
* @since 1.0.0
|
|
187
|
+
*/
|
|
188
|
+
export const report = (divergences) => divergences.map((divergence) => [
|
|
189
|
+
`${divergence.call}(${JSON.stringify(divergence.input)})`,
|
|
190
|
+
` subject: ${divergence.subject}`,
|
|
191
|
+
` reference: ${divergence.reference}`
|
|
192
|
+
].join("\n")).join("\n\n");
|
|
193
|
+
//# sourceMappingURL=SearchConformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchConformance.js","sourceRoot":"","sources":["../../src/SearchConformance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A differential conformance kit for {@link Search} implementations.\n *\n * `Search` is a public extension seam: a host binds its own implementation and\n * every `grep` and `glob` call in the package goes through it. Two peers ship\n * here, and the contract they are held to used to live only in\n * `test/SearchConformance.test.ts` — a file `package.json` does not publish, so\n * a third-party peer had the seam and no way to prove it filled it. Worse, the\n * cases there are hand-picked: they pin the divergences somebody already\n * found. A literal `?` matched `fo` in one peer and `foo?` in the other for as\n * long as nobody thought to write that case down.\n *\n * This module is the other half. It generates a tree and a batch of calls from\n * a seed, runs them through two implementations, and reports every answer that\n * differs. Nothing here knows which peer is right: a divergence is the finding,\n * and the reference peer to compare against is the caller's choice —\n * `PortableSearch` is the obvious one, because it needs no external binary.\n *\n * The generator deliberately stays inside the ground both peers claim to\n * share: no symlinks, no unreadable directories, no CRLF, no NUL bytes, no\n * filename a shell would have to quote. Those are the cases the hand-written\n * table pins one by one, with an expected value that says which behaviour is\n * intended. A generator cannot say that; it can only say the two disagree.\n *\n * @since 1.0.0\n */\n\nimport * as Effect from \"effect/Effect\"\nimport * as FileSystem from \"effect/FileSystem\"\nimport * as Path from \"effect/Path\"\nimport type * as Search from \"./Search.ts\"\nimport type * as StdError from \"./StdError.ts\"\n\n/**\n * One file the generated tree contains.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface GeneratedFile {\n /** Path relative to the tree root, always with `/` separators. */\n readonly path: string\n readonly content: string\n}\n\n/**\n * A generated tree plus the calls to make against it.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Plan {\n readonly seed: number\n readonly root: string\n readonly files: ReadonlyArray<GeneratedFile>\n readonly grep: ReadonlyArray<Search.GrepInput>\n readonly glob: ReadonlyArray<Search.GlobInput>\n}\n\n/**\n * One call two implementations answered differently.\n *\n * `subject` and `reference` are the rendered answers, so a report names the\n * bytes that differ rather than saying only that they did.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Divergence {\n readonly call: \"grep\" | \"glob\"\n readonly input: Search.GrepInput | Search.GlobInput\n readonly subject: string\n readonly reference: string\n}\n\n/**\n * mulberry32: 32 bits of state, uniform enough for fixture generation and\n * reproducible from a seed on every host, which a shared `Math.random` is not.\n */\nconst random = (seed: number): () => number => {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6D2B79F5) >>> 0\n let value = Math.imul(state ^ (state >>> 15), 1 | state)\n value = (value + Math.imul(value ^ (value >>> 7), 61 | value)) ^ value\n return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296\n }\n}\n\nconst pick = <A>(next: () => number, values: ReadonlyArray<A>): A => values[Math.floor(next() * values.length)]!\n\nconst chance = (next: () => number, probability: number): boolean => next() < probability\n\n// Names both peers walk identically: no separator, no dot prefix outside the\n// two deliberate hidden entries, no name a directory skip list contains, and\n// no character that would need quoting on a command line.\nconst stems = [\"alpha\", \"beta\", \"gamma\", \"Delta\", \"e-psilon\", \"ze_ta\", \"eta2\", \"th.eta\", \"iota\", \"kappa\"] as const\nconst extensions = [\".ts\", \".js\", \".txt\", \".py\", \".md\"] as const\nconst directories = [\"\", \"one\", \"one/two\", \"three\", \"three/four/five\"] as const\n\n// Lines drawn from a vocabulary that mixes the needle, near misses, regex\n// metacharacters that must survive `fixedStrings`, and definition headers the\n// `symbols` option reads.\nconst lines = [\n \"needle\",\n \"a needle in the line\",\n \"Needle capitalised\",\n \"no match here\",\n \"needle? with a question mark\",\n \"a+b and x*y and [z]\",\n \"def widen(value):\",\n \"class Widget:\",\n \" needle = value\",\n \"function widen(value) {\",\n \"\",\n \"trailing needle\"\n] as const\n\nconst patterns = [\"needle\", \"Needle\", \"needle?\", \"a+b\", \"[z]\", \"^needle$\", \"widen\", \"no match at all\"] as const\n\nconst globPatterns = [\"**/*.ts\", \"*.ts\", \"**/*\", \"one/**/*.ts\", \"**/*.{ts,js}\", \"**/alpha*\"] as const\n\n/**\n * Builds a reproducible tree and call batch from a seed.\n *\n * The same seed and root always produce the same plan, so a divergence a run\n * reports can be replayed exactly by rerunning that seed.\n *\n * @category generators\n * @since 1.0.0\n */\nexport const plan = (options: {\n readonly seed: number\n readonly root: string\n readonly files?: number | undefined\n readonly calls?: number | undefined\n}): Plan => {\n const next = random(options.seed)\n const fileCount = options.files ?? 12\n const callCount = options.calls ?? 12\n const files: Array<GeneratedFile> = []\n for (let index = 0; index < fileCount; index++) {\n const directory = pick(next, directories)\n // The index makes every generated path unique, including repeated random picks.\n const name = `${pick(next, stems)}${index}${pick(next, extensions)}`\n const path = directory === \"\" ? name : `${directory}/${name}`\n const body: Array<string> = []\n for (let line = 0; line < 1 + Math.floor(next() * 8); line++) body.push(pick(next, lines))\n files.push({ path, content: `${body.join(\"\\n\")}${chance(next, 0.8) ? \"\\n\" : \"\"}` })\n }\n\n // Always exercise precedence, anchoring, directory pruning and nested\n // negation alongside each seed's generated content (without a git repo).\n if (fileCount > 0) {\n files.push(\n { path: \".gitignore\", content: \"*.ignored\\n!keep.ignored\\n/root-only.ts\\ncache/\\n\" },\n { path: \"drop.ignored\", content: \"needle\\n\" },\n { path: \"keep.ignored\", content: \"needle\\n\" },\n { path: \"root-only.ts\", content: \"needle\\n\" },\n { path: \"cache/a.ts\", content: \"needle\\n\" },\n { path: \"nested/.gitignore\", content: \"!keep.ignored\\n/anchored.ts\\nframes/\\n\" },\n { path: \"nested/keep.ignored\", content: \"needle\\n\" },\n { path: \"nested/drop.ignored\", content: \"needle\\n\" },\n { path: \"nested/anchored.ts\", content: \"needle\\n\" },\n { path: \"nested/deep/anchored.ts\", content: \"needle\\n\" },\n { path: \"nested/root-only.ts\", content: \"needle\\n\" },\n { path: \"nested/frames/a.ts\", content: \"needle\\n\" },\n { path: \"other/frames\", content: \"needle\\n\" }\n )\n }\n\n const roots = [options.root, ...files.map((entry) => `${options.root}/${entry.path}`)]\n const grep: Array<Search.GrepInput> = []\n for (let index = 0; index < callCount; index++) {\n const fixedStrings = chance(next, 0.4)\n // `Grep.run` refuses `ignoreCase` together with `smartCase` as mutually\n // exclusive, so a generated call carrying both would be exploring ground\n // the contract does not describe.\n const ignoreCase = chance(next, 0.25)\n grep.push({\n pattern: pick(next, patterns),\n root: chance(next, 0.75) ? options.root : pick(next, roots),\n fixedStrings,\n ignoreCase,\n smartCase: !ignoreCase && chance(next, 0.3),\n globs: chance(next, 0.4) ? [pick(next, [\"*.ts\", \"*.txt\", \"!*.js\", \"**/*.ts\"])] : [],\n beforeContext: Math.floor(next() * 3),\n afterContext: Math.floor(next() * 3),\n ...(chance(next, 0.3) ? { maxCount: 1 + Math.floor(next() * 2) } : {}),\n filesWithMatches: chance(next, 0.25),\n hidden: chance(next, 0.5),\n noIgnore: chance(next, 0.25),\n symbols: chance(next, 0.3),\n limit: 1 + Math.floor(next() * 40)\n })\n }\n\n const glob: Array<Search.GlobInput> = []\n for (let index = 0; index < callCount; index++) {\n glob.push({\n pattern: pick(next, globPatterns),\n root: options.root,\n hidden: chance(next, 0.5),\n noIgnore: chance(next, 0.25),\n limit: 1 + Math.floor(next() * 20)\n })\n }\n\n return { seed: options.seed, root: options.root, files, grep, glob }\n}\n\n/**\n * Writes a plan's tree under its root.\n *\n * @category generators\n * @since 1.0.0\n */\nexport const materialize = (\n target: Plan\n): Effect.Effect<void, never, FileSystem.FileSystem | Path.Path> =>\n Effect.gen(function*() {\n const fileSystem = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n yield* Effect.forEach(target.files, (entry) => {\n const absolute = path.join(target.root, ...entry.path.split(\"/\"))\n return fileSystem.makeDirectory(path.dirname(absolute), { recursive: true }).pipe(\n Effect.andThen(fileSystem.writeFileString(absolute, entry.content)),\n Effect.orDie\n )\n }, { discard: true })\n })\n\n/** A typed answer rendered so two of them can be compared as text. */\nconst rendered = <A>(\n effect: Effect.Effect<A, StdError.StdError>\n): Effect.Effect<string> =>\n effect.pipe(\n Effect.match({\n onSuccess: (value) => JSON.stringify(value),\n onFailure: (error) => JSON.stringify({ failure: error.code })\n })\n )\n\n/**\n * Runs every call in a plan through two implementations and reports the\n * answers that differ.\n *\n * A failure is compared like any other answer: two peers that refuse the same\n * call with the same code agree, and one that refuses where the other answers\n * has diverged.\n *\n * @category conformance\n * @since 1.0.0\n */\nexport const compare = (options: {\n readonly plan: Plan\n readonly subject: Search.Search\n readonly reference: Search.Search\n}): Effect.Effect<ReadonlyArray<Divergence>> =>\n Effect.gen(function*() {\n const divergences: Array<Divergence> = []\n for (const input of options.plan.grep) {\n const subject = yield* rendered(options.subject.grep(input))\n const reference = yield* rendered(options.reference.grep(input))\n if (subject !== reference) divergences.push({ call: \"grep\", input, subject, reference })\n }\n for (const input of options.plan.glob) {\n const subject = yield* rendered(options.subject.glob(input))\n const reference = yield* rendered(options.reference.glob(input))\n if (subject !== reference) divergences.push({ call: \"glob\", input, subject, reference })\n }\n return divergences\n })\n\n/**\n * Renders divergences as the report a failing conformance run should print.\n *\n * @category conformance\n * @since 1.0.0\n */\nexport const report = (divergences: ReadonlyArray<Divergence>): string =>\n divergences.map((divergence) =>\n [\n `${divergence.call}(${JSON.stringify(divergence.input)})`,\n ` subject: ${divergence.subject}`,\n ` reference: ${divergence.reference}`\n ].join(\"\\n\")\n ).join(\"\\n\\n\")\n"]}
|