diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..7e766c36 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.x86_64-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.i686-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] diff --git a/.gitattributes b/.gitattributes index 097f9f98..5dedfe12 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,9 +1 @@ -# -# https://help.github.com/articles/dealing-with-line-endings/ -# -# Linux start script should use lf -/gradlew text eol=lf - -# These are Windows script files and should use crlf -*.bat text eol=crlf - +examples/wiktionary.xml filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/cli-build.yml b/.github/workflows/cli-build.yml new file mode 100644 index 00000000..7a2de6d1 --- /dev/null +++ b/.github/workflows/cli-build.yml @@ -0,0 +1,45 @@ +name: Run Tests + +on: + push: + branches: [v2] + pull_request: + branches: [v2] + +jobs: + test: + name: Build + runs-on: ${{ matrix.runner }} + strategy: + matrix: + include: + - name: linux-amd64 + runner: ubuntu-latest + target: x86_64-unknown-linux-gnu + - name: win-amd64 + runner: windows-latest + target: x86_64-pc-windows-msvc + - name: macos-amd64 + runner: macos-latest + target: x86_64-apple-darwin + - name: macos-arm64 + runner: macos-latest + target: aarch64-apple-darwin + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: "${{ matrix.target }}" + - name: Add Rust target + run: rustup target add ${{ matrix.target }} + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + - name: Build CLI + run: cargo build --verbose --locked --release --target ${{ matrix.target }} + - uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: code + path: /home/runner/work/odict diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml new file mode 100644 index 00000000..afe44e1a --- /dev/null +++ b/.github/workflows/cli-release.yml @@ -0,0 +1,327 @@ +# This file was autogenerated by dist: https://opensource.axo.dev/cargo-dist/ +# +# Copyright 2022-2024, axodotdev +# SPDX-License-Identifier: MIT or Apache-2.0 +# +# CI that: +# +# * checks for a Git Tag that looks like a release +# * builds artifacts with dist (archives, installers, hashes) +# * uploads those artifacts to temporary workflow zip +# * on success, uploads the artifacts to a GitHub Release +# +# Note that a GitHub Release with this tag is assumed to exist as a draft +# with the appropriate title/body, and will be undrafted for you. + +name: Release +permissions: + "contents": "write" + +# This task will run whenever you push a git tag that looks like a version +# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. +# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where +# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION +# must be a Cargo-style SemVer Version (must have at least major.minor.patch). +# +# If PACKAGE_NAME is specified, then the announcement will be for that +# package (erroring out if it doesn't have the given version or isn't dist-able). +# +# If PACKAGE_NAME isn't specified, then the announcement will be for all +# (dist-able) packages in the workspace with that version (this mode is +# intended for workspaces with only one dist-able package, or with all dist-able +# packages versioned/released in lockstep). +# +# If you push multiple tags at once, separate instances of this workflow will +# spin up, creating an independent announcement for each one. However, GitHub +# will hard limit this to 3 tags per commit, as it will assume more tags is a +# mistake. +# +# If there's a prerelease-style suffix to the version, then the release(s) +# will be marked as a prerelease. +on: + pull_request: + push: + tags: + - 'cli**[0-9]+.[0-9]+.[0-9]+*' + +jobs: + # Run 'dist plan' (or host) to determine what tasks we need to do + plan: + runs-on: "ubuntu-20.04" + outputs: + val: ${{ steps.plan.outputs.manifest }} + tag: ${{ !github.event.pull_request && github.ref_name || '' }} + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} + publishing: ${{ !github.event.pull_request }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install dist + # we specify bash to get pipefail; it guards against the `curl` command + # failing. otherwise `sh` won't catch that `curl` returned non-0 + shell: bash + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.25.1/cargo-dist-installer.sh | sh" + - name: Cache dist + uses: actions/upload-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/dist + # sure would be cool if github gave us proper conditionals... + # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible + # functionality based on whether this is a pull_request, and whether it's from a fork. + # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* + # but also really annoying to build CI around when it needs secrets to work right.) + - id: plan + run: | + dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json + echo "dist ran successfully" + cat plan-dist-manifest.json + echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + name: artifacts-plan-dist-manifest + path: plan-dist-manifest.json + + # Build and packages all the platform-specific things + build-local-artifacts: + name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) + # Let the initial task tell us to not run (currently very blunt) + needs: + - plan + if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} + strategy: + fail-fast: false + # Target platforms/runners are computed by dist in create-release. + # Each member of the matrix has the following arguments: + # + # - runner: the github runner + # - dist-args: cli flags to pass to dist + # - install-dist: expression to run to install dist on the runner + # + # Typically there will be: + # - 1 "global" task that builds universal installers + # - N "local" tasks that build each platform's binaries and platform-specific installers + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} + runs-on: ${{ matrix.runner }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json + steps: + - name: enable windows longpaths + run: | + git config --global core.longpaths true + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install dist + run: ${{ matrix.install_dist }} + # Get the dist-manifest + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - name: Install dependencies + run: | + ${{ matrix.packages_install }} + - name: Build artifacts + run: | + # Actually do builds and make zips and whatnot + dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "dist ran successfully" + - id: cargo-dist + name: Post-build + # We force bash here just because github makes it really hard to get values up + # to "real" actions without writing to env-vars, and writing to env-vars has + # inconsistent syntax between shell and powershell. + shell: bash + run: | + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-local-${{ join(matrix.targets, '_') }} + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + + # Build and package all the platform-agnostic(ish) things + build-global-artifacts: + needs: + - plan + - build-local-artifacts + runs-on: "ubuntu-20.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Get all the local artifacts for the global tasks to use (for e.g. checksums) + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: cargo-dist + shell: bash + run: | + dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json + echo "dist ran successfully" + + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-global + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + # Determines if we should publish/announce + host: + needs: + - plan + - build-local-artifacts + - build-global-artifacts + # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) + if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + runs-on: "ubuntu-20.04" + outputs: + val: ${{ steps.host.outputs.manifest }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Fetch artifacts from scratch-storage + - name: Fetch artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: host + shell: bash + run: | + dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json + echo "artifacts uploaded and released successfully" + cat dist-manifest.json + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + # Overwrite the previous copy + name: artifacts-dist-manifest + path: dist-manifest.json + # Create a GitHub Release while uploading all files to it + - name: "Download GitHub Artifacts" + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: artifacts + merge-multiple: true + - name: Cleanup + run: | + # Remove the granular manifests + rm -f artifacts/*-dist-manifest.json + - name: Create GitHub Release + env: + PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" + RELEASE_COMMIT: "${{ github.sha }}" + run: | + # If we're editing a release in place, we need to upload things ahead of time + gh release upload "${{ needs.plan.outputs.tag }}" artifacts/* + + gh release edit "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --draft=false + + publish-homebrew-formula: + needs: + - plan + - host + runs-on: "ubuntu-20.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PLAN: ${{ needs.plan.outputs.val }} + GITHUB_USER: "axo bot" + GITHUB_EMAIL: "admin+bot@axo.dev" + if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} + steps: + - uses: actions/checkout@v4 + with: + repository: "TheOpenDictionary/homebrew-odict" + token: ${{ secrets.HOMEBREW_TAP_TOKEN }} + # So we have access to the formula + - name: Fetch homebrew formulae + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: Formula/ + merge-multiple: true + # This is extra complex because you can make your Formula name not match your app name + # so we need to find releases with a *.rb file, and publish with that filename. + - name: Commit formula files + run: | + git config --global user.name "${GITHUB_USER}" + git config --global user.email "${GITHUB_EMAIL}" + + for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do + filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output) + name=$(echo "$filename" | sed "s/\.rb$//") + version=$(echo "$release" | jq .app_version --raw-output) + + export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" + brew update + # We avoid reformatting user-provided data such as the app description and homepage. + brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true + + git add "Formula/${filename}" + git commit -m "${name} ${version}" + done + git push + + announce: + needs: + - plan + - host + - publish-homebrew-formula + # use "always() && ..." to allow us to wait for all publish jobs while + # still allowing individual publish jobs to skip themselves (for prereleases). + # "host" however must run to completion, no skipping allowed! + if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') }} + runs-on: "ubuntu-20.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 04904899..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Deploy - -on: - workflow_dispatch: - inputs: - version: - description: 'Semantic version number' - required: true - changes: - description: 'Description of changes' - required: true - -env: - GO_VERSION: "^1.18" - JAVA_VERSION: 11 - -jobs: - deploy: - name: Deploy - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Java - uses: actions/setup-java@v3 - with: - java-version: ${{ env.JAVA_VERSION }} - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Setup Bazelisk - run: | - go get github.com/bazelbuild/bazelisk - export PATH=$PATH:$(go env GOPATH)/bin - - - name: Import GPG key - id: import_gpg - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.MAVEN_KEY }} - passphrase: ${{ secrets.MAVEN_KEY_PASSPHRASE }} - - - name: Update version number - run: echo 'version="${{ github.event.inputs.version }}"' > version.bzl - - - name: Tag & commit version number - uses: EndBug/add-and-commit@v9 # You can change this to use a specific version. - with: - add: 'version.bzl' - message: 'chore(*): Bump version number to ${{ github.event.inputs.version }}' - push: true - tag: "${{ github.event.inputs.version }} --force" - tag_push: '--force' - - - name: Deploy to Maven - run: | - export GPG_TTY=$(tty) - bazelisk run --stamp --define "maven_repo=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2" --define "maven_user=${{ secrets.MAVEN_USERNAME }}" --define "maven_password=${{ secrets.MAVEN_PASSWORD }}" --define gpg_sign=true //java/main/java/org/odict:odict.publish - \ No newline at end of file diff --git a/.github/workflows/lib-release.yml b/.github/workflows/lib-release.yml new file mode 100644 index 00000000..b623fdef --- /dev/null +++ b/.github/workflows/lib-release.yml @@ -0,0 +1,29 @@ +name: Release crate + +permissions: + "contents": "write" + +on: + workflow_dispatch: + push: + tags: + - 'lib**[0-9]+.[0-9]+.[0-9]' + +jobs: + release: + name: Run release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + - name: Build CLI + run: cargo publish -p odict + - uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: code + path: /home/runner/work/odict diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml new file mode 100644 index 00000000..7aef947f --- /dev/null +++ b/.github/workflows/node.yml @@ -0,0 +1,331 @@ +name: Node bindings +env: + DEBUG: napi:* + APP_NAME: node + MACOSX_DEPLOYMENT_TARGET: '10.13' + CARGO_INCREMENTAL: '1' +permissions: + contents: write + id-token: write +'on': + workflow_dispatch: + push: + tags: + - "node-*" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + build: + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: x86_64-apple-darwin + build: pnpm --filter "@odict/node" build --target x86_64-apple-darwin + - host: windows-latest + build: pnpm --filter "@odict/node" build --target x86_64-pc-windows-msvc + target: x86_64-pc-windows-msvc + - host: windows-latest + build: pnpm --filter "@odict/node" build --target i686-pc-windows-msvc + target: i686-pc-windows-msvc + - host: ubuntu-latest + target: x86_64-unknown-linux-gnu + build: pnpm --filter "@odict/node" build --target x86_64-unknown-linux-gnu --use-napi-cross + - host: ubuntu-latest + target: x86_64-unknown-linux-musl + build: pnpm --filter "@odict/node" build --target x86_64-unknown-linux-musl -x + - host: macos-latest + target: aarch64-apple-darwin + build: pnpm --filter "@odict/node" build --target aarch64-apple-darwin + - host: ubuntu-latest + target: aarch64-unknown-linux-gnu + build: pnpm --filter "@odict/node" build --target aarch64-unknown-linux-gnu --use-napi-cross + - host: ubuntu-latest + target: armv7-unknown-linux-gnueabihf + build: pnpm --filter "@odict/node" build --target armv7-unknown-linux-gnueabihf --use-napi-cross + - host: ubuntu-latest + target: aarch64-linux-android + build: pnpm --filter "@odict/node" build --target aarch64-linux-android + - host: ubuntu-latest + target: armv7-linux-androideabi + build: pnpm --filter "@odict/node" build --target armv7-linux-androideabi + - host: ubuntu-latest + target: aarch64-unknown-linux-musl + build: pnpm --filter "@odict/node" build --target aarch64-unknown-linux-musl -x + - host: windows-latest + target: aarch64-pc-windows-msvc + build: pnpm --filter "@odict/node" build --target aarch64-pc-windows-msvc + name: stable - ${{ matrix.settings.target }} - node@20 + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - name: setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - name: Install + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.settings.target }} + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + ~/.napi-rs + .cargo-cache + target/ + key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }} + - uses: goto-bus-stop/setup-zig@v2 + if: ${{ contains(matrix.settings.target, 'musl') }} + with: + version: 0.13.0 + - name: Install cargo-zigbuild + uses: taiki-e/install-action@v2 + if: ${{ contains(matrix.settings.target, 'musl') }} + env: + GITHUB_TOKEN: ${{ github.token }} + with: + tool: cargo-zigbuild + - name: Setup toolchain + run: ${{ matrix.settings.setup }} + if: ${{ matrix.settings.setup }} + shell: bash + - name: Install dependencies + run: pnpm install + - name: Setup node x86 + uses: actions/setup-node@v4 + if: matrix.settings.target == 'i686-pc-windows-msvc' + with: + node-version: 20 + cache: pnpm + architecture: x86 + - name: Build + run: ${{ matrix.settings.build }} + shell: bash + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: bindings-${{ matrix.settings.target }} + path: bindings/node/*.node + if-no-files-found: error + + build-freebsd: + runs-on: ubuntu-latest + name: Build FreeBSD + steps: + - uses: actions/checkout@v4 + - name: Build + id: build + uses: cross-platform-actions/action@v0.25.0 + env: + DEBUG: napi:* + RUSTUP_IO_THREADS: 1 + with: + operating_system: freebsd + version: '14.1' + memory: 8G + cpu_count: 3 + environment_variables: 'DEBUG RUSTUP_IO_THREADS' + shell: bash + run: | + sudo pkg install -y -f curl node libnghttp2 npm + sudo npm install -g corepack + curl https://sh.rustup.rs -sSf --output rustup.sh + sh rustup.sh -y --profile minimal --default-toolchain beta + corepack prepare + corepack enable + source "$HOME/.cargo/env" + echo "~~~~ rustc --version ~~~~" + rustc --version + echo "~~~~ node -v ~~~~" + node -v + echo "~~~~ pnpm --version ~~~~" + pnpm --version + pwd + ls -lah + whoami + env + freebsd-version + pnpm install + pnpm --filter "@odict/node" build + rm -rf node_modules + rm -rf target + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: bindings-freebsd + path: bindings/node/*.node + if-no-files-found: error + test-macOS-windows-binding: + name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }} + needs: + - build + strategy: + fail-fast: false + matrix: + settings: + - host: windows-latest + target: x86_64-pc-windows-msvc + architecture: x64 + - host: macos-latest + target: x86_64-apple-darwin + architecture: x64 + - host: macos-latest + target: aarch64-apple-darwin + architecture: arm64 + node: + - '18' + - '20' + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - name: setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: pnpm + architecture: ${{ matrix.settings.architecture }} + - name: Install dependencies + run: pnpm install + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: bindings-${{ matrix.settings.target }} + path: bindings/node + - name: List packages + run: ls -R . + shell: bash + - name: Test bindings + run: pnpm --filter "@odict/node" test + test-linux-binding: + name: Test ${{ matrix.target }} - node@${{ matrix.node }} + needs: + - build + strategy: + fail-fast: false + matrix: + target: + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + - aarch64-unknown-linux-gnu + - aarch64-unknown-linux-musl + - armv7-unknown-linux-gnueabihf + node: + - '18' + - '20' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: pnpm + - name: Output docker params + id: docker + run: | + node -e " + if ('${{ matrix.target }}'.startsWith('aarch64')) { + console.log('PLATFORM=linux/arm64') + } else if ('${{ matrix.target }}'.startsWith('armv7')) { + console.log('PLATFORM=linux/arm/v7') + } else { + console.log('PLATFORM=linux/amd64') + } + " >> $GITHUB_OUTPUT + node -e " + if ('${{ matrix.target }}'.endsWith('-musl')) { + console.log('IMAGE=node:${{ matrix.node }}-alpine') + } else { + console.log('IMAGE=node:${{ matrix.node }}-slim') + } + " >> $GITHUB_OUTPUT + echo "PNPM_STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + # use --force to download the all platform/arch dependencies + - name: Install dependencies + run: pnpm install --force + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: bindings-${{ matrix.target }} + path: bindings/node + - name: List packages + run: ls -R . + shell: bash + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: all + - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + - name: Test bindings + uses: addnab/docker-run-action@v3 + with: + image: ${{ steps.docker.outputs.IMAGE }} + options: -v ${{ steps.docker.outputs.PNPM_STORE_PATH }}:${{ steps.docker.outputs.PNPM_STORE_PATH }} -v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }} --platform ${{ steps.docker.outputs.PLATFORM }} + run: cd bindings/node && npm run test + publish: + name: Publish + runs-on: ubuntu-latest + needs: + - build-freebsd + - test-macOS-windows-binding + - test-linux-binding + steps: + - uses: actions/checkout@v4 + - name: setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - name: Install dependencies + run: pnpm install + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: bindings/node/artifacts + - name: create npm dirs + run: pnpm --filter="@odict/node" create-dirs + - name: Move artifacts + run: pnpm --filter="@odict/node" artifacts + - name: List packages + run: ls -R ./bindings/node/npm + shell: bash + - uses: olegtarasov/get-tag@v2.1.3 + id: tagName + with: + tagRegex: "node-(.*)" + - name: Print tag name + run: echo $GIT_TAG_NAME + - name: Publish + shell: bash + run: | + npm config set provenance true + if [[ $GIT_TAG_NAME =~ "^v?[0-9]+.[0-9]+.[0-9]+$" ]]; + then + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + pnpm --filter="@odict/node" publish --no-git-checks --access public + elif [[ $GIT_TAG_NAME =~ "^v?[0-9]+.[0-9]+.[0-9]+" ]]; + then + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + pnpm --filter="@odict/node" publish --tag next --no-git-checks --access public + else + echo "Not a release, skipping publish" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 08e814c9..76c130ee 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -1,10 +1,11 @@ -name: Release Please +name: Release Please on: - push: - branches: - - main - + push: + branches: + - main + - v2 + permissions: contents: write pull-requests: write @@ -16,51 +17,11 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v4 with: fetch-depth: 0 - id: release name: Release please - uses: google-github-actions/release-please-action@v3.7.6 - with: - command: manifest - token: ${{ secrets.GITHUB_TOKEN }} - monorepo-tags: true - bump-patch-for-minor-pre-major: true - - name: Setup asdf - uses: asdf-vm/actions/setup@v2 - - name: Cache asdf - id: cache-asdf - uses: actions/cache@v3 - with: - path: | - /home/runner/.asdf - key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} - restore-keys: | - ${{ runner.os }}-asdf- - - name: Install dependencies in .tool-versions - uses: asdf-vm/actions/install@v2 - - name: Fetch tags - run: git fetch --force --tags - - name: Publish CLI - uses: goreleaser/goreleaser-action@v5 - if: steps.release.outputs.release_created - env: - HOMEBREW_GH_TOKEN: ${{ secrets.HOMEBREW_GH_TOKEN }} + uses: googleapis/release-please-action@v4 with: - args: release --clean - - name: Publish Node library to NPM - if: steps.release.outputs.js--release_created - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: just js publish - - name: Publish WASM library to NPM - if: steps.release.outputs.wasm--release_created - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: just wasm publish - - name: Publish to Pypi - if: steps.release.outputs.python--release_created - env: - POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }} - run: just python publish \ No newline at end of file + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f92b7789..91772b55 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,9 @@ -name: Build & Test +name: Run Tests on: - push: - branches: [main] pull_request: - branches: [main] + push: + branches: [v2] jobs: test: @@ -13,33 +12,12 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Setup asdf - uses: asdf-vm/actions/setup@v2 - - name: Cache asdf - id: cache-asdf - uses: actions/cache@v3 - with: - path: | - /home/runner/.asdf - key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} - restore-keys: | - ${{ runner.os }}-asdf- - - name: Cache Poetry dependencies - uses: actions/cache@v3 - with: - path: | - /home/runner/.venv - key: ${{ runner.os }}-poetry-${{ hashFiles('**/python/poetry.lock') }} - restore-keys: | - ${{ runner.os }}-poetry- - - name: Install dependencies in .tool-versions - uses: asdf-vm/actions/install@v2 - - name: Run build - run: just build-all --snapshot + - name: Setup Mise + uses: jdx/mise-action@v2 + - name: Setup dependencies + run: mise run setup - name: Run tests - env: - POETRY_VIRTUALENVS_IN_PROJECT: true - run: just test + run: RUST_BACKTRACE=1 mise run test-all --interleave - uses: actions/upload-artifact@v4 if: ${{ failure() }} with: diff --git a/.gitignore b/.gitignore index 290a6f30..07cef639 100644 --- a/.gitignore +++ b/.gitignore @@ -755,4 +755,12 @@ TSWLatexianTemp* *.wasm # WASM preview -.preview \ No newline at end of file +.preview + +# Node bindings +*.node + +.cargo +!.cargo/config.toml +.pnpm-store +semicolon_delimited_script \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index b8b9f439..00000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,48 +0,0 @@ -before: - hooks: - - go work sync - -dist: bin - -project_name: odict - -git: - ignore_tags: - - js-* - - python-* - - jvm-* - - wasm-* - -builds: - - id: odict - main: ./odict.go - ldflags: - - -X 'github.com/TheOpenDictionary/odict/cli.version={{.Version}}' - goos: - - linux - - darwin - - windows - env: - - CGO_ENABLED=0 - - id: single - main: ./odict.go - binary: odict - ldflags: - - -X 'github.com/TheOpenDictionary/odict/cli.version={{.Version}}' - no_unique_dist_dir: true - env: - - CGO_ENABLED=0 - -archives: - - builds: - - odict - -brews: - - name: odict - homepage: "https://odict.org/" - description: "A lightning-fast dictionary compiler and toolchain" - folder: Formula - repository: - owner: TheOpenDictionary - name: homebrew-odict - token: "{{ .Env.HOMEBREW_GH_TOKEN }}" \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 9e26dfee..00000000 --- a/.prettierrc.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/.release-please-manifest.json b/.release-please-manifest.json index eb654e6f..095c2400 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,6 @@ { - "js": "0.12.0", - "python": "0.11.0", - ".": "1.23.0", - "jvm": "0.0.1", - "wasm": "0.0.1-rc1" + "bindings/node": "0.0.0", + "cli": "0.0.0", + "lib": "0.0.0", + "bindings/java": "0.0.0" } \ No newline at end of file diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 6b304705..00000000 --- a/.tool-versions +++ /dev/null @@ -1,11 +0,0 @@ -golang 1.22.2 -python 3.12.1 -poetry 1.7.1 -gradle 7.5.1 -kotlin 1.9.22 -java adoptopenjdk-17.0.10+7 -nodejs 20.11.1 -just 1.25.2 -flatc 23.3.3 -goreleaser 1.21.1 -make 4.4.1 diff --git a/.vscode/settings.json b/.vscode/settings.json index 0ca4d0be..2d87260f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "java.compile.nullAnalysis.mode": "automatic" + "java.compile.nullAnalysis.mode": "automatic", + "rust-analyzer.procMacro.ignored": { "napi-derive": ["napi"] } } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..96a567a8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4335 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags 2.6.0", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64", + "bitflags 2.6.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.87", +] + +[[package]] +name = "actix-router" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" +dependencies = [ + "bytestring", + "cfg-if", + "http", + "regex", + "regex-lite", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca2549781d8dd6d75c40cf6b6051260a2cc2f3c62343d761a969a0640646894" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "impl-more", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "regex-lite", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611cc2ae7d2e242c457e4be7f97036b8ad9ca152b499f53faf99b1ed8fc2553f" + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.87", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitpacking" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c1d3e2bfd8d06048a179f7b17afc3188effa10385e7b00dc65af6aae732ea92" +dependencies = [ + "crunchy", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytecheck" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c8f430744b23b54ad15161fcbc22d82a29b73eacbe425fea23ec822600bc6f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523363cbe1df49b68215efdf500b103ac3b0fb4836aed6d15689a076eadb8fff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "bytestring" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +dependencies = [ + "bytes", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cedarwood" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d910bedd62c24733263d0bed247460853c9d22e8956bd4cd964302095e04e90" +dependencies = [ + "smallvec", +] + +[[package]] +name = "census" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "charabia" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8921fe4d53ab8f9e8f9b72ce6f91726cfc40fffab1243d27db406b5e2e9cc2" +dependencies = [ + "aho-corasick", + "csv", + "either", + "fst", + "irg-kvariants", + "jieba-rs", + "lindera", + "once_cell", + "serde", + "slice-group-by", + "unicode-normalization", + "wana_kana", + "whatlang", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "cli" +version = "2.0.0-beta.0" +dependencies = [ + "actix-web", + "clap", + "console", + "derive_more", + "env_logger", + "humansize", + "indicatif", + "num-format", + "odict", + "pulldown-cmark", + "serde", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width 0.1.14", + "windows-sys 0.52.0", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "ctor" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +dependencies = [ + "quote", + "syn 2.0.87", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.87", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.87", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.87", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "encoding_rs_io" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83" +dependencies = [ + "encoding_rs", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastdivide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" + +[[package]] +name = "fastrand" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + +[[package]] +name = "fs4" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e180ac76c23b45e767bd7ae9579bc0bb458618c4bc71835926e098e61d15f8" +dependencies = [ + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width 0.1.14", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-more" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", +] + +[[package]] +name = "indicatif" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width 0.2.0", + "web-time", +] + +[[package]] +name = "inherent" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "insta" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "similar", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "irg-kvariants" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2af7c331f2536964a32b78a7d2e0963d78b42f4a76323b16cc7d94b1ddce26" +dependencies = [ + "csv", + "once_cell", + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jieba-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e2b0210dc78b49337af9e49d7ae41a39dceac6e5985613f1cf7763e2f76a25" +dependencies = [ + "cedarwood", + "derive_builder", + "fxhash", + "lazy_static", + "phf", + "phf_codegen", + "regex", +] + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kanaria" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f9d9652540055ac4fded998a73aca97d965899077ab1212587437da44196ff" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" + +[[package]] +name = "libc" +version = "0.2.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.48.5", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "lindera" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cbc1aad631a7da0a7e9bc4b8669fa92ac9ca8eeb7b35a807376dd3034443ff" +dependencies = [ + "lindera-analyzer", + "lindera-core", + "lindera-dictionary", + "lindera-filter", + "lindera-tokenizer", +] + +[[package]] +name = "lindera-analyzer" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74508ffbb24e36905d1718b261460e378a748029b07bcd7e06f0d18500b8194c" +dependencies = [ + "anyhow", + "bincode", + "byteorder", + "encoding", + "kanaria", + "lindera-cc-cedict-builder", + "lindera-core", + "lindera-dictionary", + "lindera-filter", + "lindera-ipadic-builder", + "lindera-ko-dic-builder", + "lindera-tokenizer", + "lindera-unidic-builder", + "once_cell", + "regex", + "serde", + "serde_json", + "thiserror", + "unicode-blocks", + "unicode-normalization", + "unicode-segmentation", + "yada", +] + +[[package]] +name = "lindera-assets" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a677c371ecb3bd02b751be306ea09876cd47cf426303ad5f10a3fd6f9a4ded6" +dependencies = [ + "encoding", + "flate2", + "lindera-core", + "tar", + "ureq", +] + +[[package]] +name = "lindera-cc-cedict" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35944000d05a177e981f037b5f0805f283b32f05a0c35713003bef136ca8cb4" +dependencies = [ + "bincode", + "byteorder", + "lindera-cc-cedict-builder", + "lindera-core", + "lindera-decompress", + "once_cell", +] + +[[package]] +name = "lindera-cc-cedict-builder" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b8f642bc9c9130682569975772a17336c6aab26d11fc0f823f3e663167ace6" +dependencies = [ + "anyhow", + "lindera-core", + "lindera-decompress", + "lindera-dictionary-builder", +] + +[[package]] +name = "lindera-compress" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7825d8d63592aa5727d67bd209170ac82df56c369533efbf0ddbac277bb68ec" +dependencies = [ + "anyhow", + "flate2", + "lindera-decompress", +] + +[[package]] +name = "lindera-core" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c28191456debc98af6aa5f7db77872471983e9fa2a737b1c232b6ef543aed62" +dependencies = [ + "anyhow", + "bincode", + "byteorder", + "encoding_rs", + "log", + "once_cell", + "serde", + "thiserror", + "yada", +] + +[[package]] +name = "lindera-decompress" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4788a1ead2f63f3fc2888109272921dedd86a87b7d0bf05e9daab46600daac51" +dependencies = [ + "anyhow", + "flate2", + "serde", +] + +[[package]] +name = "lindera-dictionary" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf5f91725e32b9a21b1656baa7030766c9bafc4de4b4ddeb8ffdde7224dd2f6" +dependencies = [ + "anyhow", + "bincode", + "byteorder", + "lindera-cc-cedict", + "lindera-cc-cedict-builder", + "lindera-core", + "lindera-ipadic", + "lindera-ipadic-builder", + "lindera-ipadic-neologd", + "lindera-ipadic-neologd-builder", + "lindera-ko-dic", + "lindera-ko-dic-builder", + "lindera-unidic", + "lindera-unidic-builder", + "serde", + "strum", + "strum_macros", +] + +[[package]] +name = "lindera-dictionary-builder" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e41f00ba7ac541b0ffd8c30e7a73f2dd197546cc5780462ec4f2e4782945a780" +dependencies = [ + "anyhow", + "bincode", + "byteorder", + "csv", + "derive_builder", + "encoding", + "encoding_rs", + "encoding_rs_io", + "glob", + "lindera-compress", + "lindera-core", + "lindera-decompress", + "log", + "yada", +] + +[[package]] +name = "lindera-filter" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273d27e01e1377e2647314a4a5b9bdca4b52a867b319069ebae8c10191146eca" +dependencies = [ + "anyhow", + "csv", + "kanaria", + "lindera-cc-cedict-builder", + "lindera-core", + "lindera-dictionary", + "lindera-ipadic-builder", + "lindera-ko-dic-builder", + "lindera-unidic-builder", + "once_cell", + "regex", + "serde", + "serde_json", + "unicode-blocks", + "unicode-normalization", + "unicode-segmentation", + "yada", +] + +[[package]] +name = "lindera-ipadic" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97a52ff0af5acb700093badaf7078051ab9ffd9071859724445a60193995f1f" +dependencies = [ + "bincode", + "byteorder", + "lindera-core", + "lindera-decompress", + "lindera-ipadic-builder", + "once_cell", +] + +[[package]] +name = "lindera-ipadic-builder" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf5031c52686128db13f774b2c5a8abfd52b4cc1f904041d8411aa19d630ce4d" +dependencies = [ + "anyhow", + "lindera-core", + "lindera-decompress", + "lindera-dictionary-builder", +] + +[[package]] +name = "lindera-ipadic-neologd" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b36764b27b169aa11d24888141f206a6c246a5b195c1e67127485bac512fb6" +dependencies = [ + "bincode", + "byteorder", + "lindera-core", + "lindera-decompress", + "lindera-ipadic-neologd-builder", + "once_cell", +] + +[[package]] +name = "lindera-ipadic-neologd-builder" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf36e40ace904741efdd883ed5c4dba6425f65156a0fb5d3f73a386335950dc" +dependencies = [ + "anyhow", + "lindera-core", + "lindera-decompress", + "lindera-dictionary-builder", +] + +[[package]] +name = "lindera-ko-dic" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c92a1a3564b531953f0238cbcea392f2905f7b27b449978cf9e702a80e1086d" +dependencies = [ + "bincode", + "byteorder", + "lindera-assets", + "lindera-core", + "lindera-decompress", + "lindera-ko-dic-builder", + "once_cell", +] + +[[package]] +name = "lindera-ko-dic-builder" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2c60425abc1548570c2568858f74a1f042105ecd89faa39c651b4315350fd9" +dependencies = [ + "anyhow", + "lindera-core", + "lindera-decompress", + "lindera-dictionary-builder", +] + +[[package]] +name = "lindera-tokenizer" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903e558981bcb6f59870aa7d6b4bcb09e8f7db778886a6a70f67fd74c9fa2ca3" +dependencies = [ + "bincode", + "lindera-core", + "lindera-dictionary", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "lindera-unidic" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d227c3ce9cbd905f865c46c65a0470fd04e89b71104d7f92baa71a212ffe1d4b" +dependencies = [ + "bincode", + "byteorder", + "lindera-assets", + "lindera-core", + "lindera-decompress", + "lindera-unidic-builder", + "once_cell", +] + +[[package]] +name = "lindera-unidic-builder" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e2c50015c242e02c451acb6748667ac6fd1d3d667cd7db48cd89e2f2d2377e" +dependencies = [ + "anyhow", + "lindera-core", + "lindera-decompress", + "lindera-dictionary-builder", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.1", +] + +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "map-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb950a42259642e5a3483115aca87eebed2a64886993463af9c9739c205b8d3a" + +[[package]] +name = "measure_time" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbefd235b0aadd181626f281e1d684e116972988c14c264e42069d5e8a5775cc" +dependencies = [ + "instant", + "log", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "merge" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" +dependencies = [ + "merge_derive", + "num-traits", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "log", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "munge" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "murmurhash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" + +[[package]] +name = "napi" +version = "2.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214f07a80874bb96a8433b3cdfc84980d56c7b02e1a0d7ba4ba0db5cef785e2b" +dependencies = [ + "bitflags 2.6.0", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", +] + +[[package]] +name = "napi-build" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" + +[[package]] +name = "napi-derive" +version = "2.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" +dependencies = [ + "cfg-if", + "convert_case 0.6.0", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" +dependencies = [ + "convert_case 0.6.0", + "once_cell", + "proc-macro2", + "quote", + "regex", + "semver", + "syn 2.0.87", +] + +[[package]] +name = "napi-sys" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" +dependencies = [ + "libloading", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "odict" +version = "2.0.0-beta.0" +dependencies = [ + "byteorder", + "charabia", + "criterion", + "dirs", + "insta", + "lz4_flex", + "map-macro", + "pulldown-cmark", + "quick-xml", + "rayon", + "regex", + "rkyv", + "sea-query", + "serde", + "serde_json", + "tantivy", + "tempfile", + "uniffi", + "uuid", + "validation", +] + +[[package]] +name = "odict_node" +version = "0.0.0" +dependencies = [ + "merge", + "napi", + "napi-build", + "napi-derive", + "odict", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "oneshot" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" + +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ownedbytes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a059efb063b8f425b948e042e6b9bd85edfe60e913630ed727b23e2dfcc558" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pulldown-cmark" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +dependencies = [ + "bitflags 2.6.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + +[[package]] +name = "quick-xml" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f22f29bdff3987b4d8632ef95fd6424ec7e4e0a57e2f4fc63e489e75357f6a03" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +dependencies = [ + "bytecheck", + "bytes", + "hashbrown 0.15.1", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "sea-query" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085e94f7d7271c0393ac2d164a39994b1dff1b06bc40cd9a0da04f3d672b0fee" +dependencies = [ + "inherent", + "sea-query-derive", +] + +[[package]] +name = "sea-query-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" +dependencies = [ + "darling", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.87", + "thiserror", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "sketches-ddsketch" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" +dependencies = [ + "serde", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "tantivy" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8d0582f186c0a6d55655d24543f15e43607299425c5ad8352c242b914b31856" +dependencies = [ + "aho-corasick", + "arc-swap", + "base64", + "bitpacking", + "byteorder", + "census", + "crc32fast", + "crossbeam-channel", + "downcast-rs", + "fastdivide", + "fnv", + "fs4", + "htmlescape", + "itertools 0.12.1", + "levenshtein_automata", + "log", + "lru", + "lz4_flex", + "measure_time", + "memmap2", + "num_cpus", + "once_cell", + "oneshot", + "rayon", + "regex", + "rust-stemmers", + "rustc-hash", + "serde", + "serde_json", + "sketches-ddsketch", + "smallvec", + "tantivy-bitpacker", + "tantivy-columnar", + "tantivy-common", + "tantivy-fst", + "tantivy-query-grammar", + "tantivy-stacker", + "tantivy-tokenizer-api", + "tempfile", + "thiserror", + "time", + "uuid", + "winapi", +] + +[[package]] +name = "tantivy-bitpacker" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284899c2325d6832203ac6ff5891b297fc5239c3dc754c5bc1977855b23c10df" +dependencies = [ + "bitpacking", +] + +[[package]] +name = "tantivy-columnar" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12722224ffbe346c7fec3275c699e508fd0d4710e629e933d5736ec524a1f44e" +dependencies = [ + "downcast-rs", + "fastdivide", + "itertools 0.12.1", + "serde", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-sstable", + "tantivy-stacker", +] + +[[package]] +name = "tantivy-common" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8019e3cabcfd20a1380b491e13ff42f57bb38bf97c3d5fa5c07e50816e0621f4" +dependencies = [ + "async-trait", + "byteorder", + "ownedbytes", + "serde", + "time", +] + +[[package]] +name = "tantivy-fst" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18" +dependencies = [ + "byteorder", + "regex-syntax", + "utf8-ranges", +] + +[[package]] +name = "tantivy-query-grammar" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "847434d4af57b32e309f4ab1b4f1707a6c566656264caa427ff4285c4d9d0b82" +dependencies = [ + "nom", +] + +[[package]] +name = "tantivy-sstable" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c69578242e8e9fc989119f522ba5b49a38ac20f576fc778035b96cc94f41f98e" +dependencies = [ + "tantivy-bitpacker", + "tantivy-common", + "tantivy-fst", + "zstd", +] + +[[package]] +name = "tantivy-stacker" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56d6ff5591fc332739b3ce7035b57995a3ce29a93ffd6012660e0949c956ea8" +dependencies = [ + "murmurhash32", + "rand_distr", + "tantivy-common", +] + +[[package]] +name = "tantivy-tokenizer-api" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0dcade25819a89cfe6f17d932c9cedff11989936bf6dd4f336d50392053b04" +dependencies = [ + "serde", +] + +[[package]] +name = "tar" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", +] + +[[package]] +name = "thiserror" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" + +[[package]] +name = "unicode-blocks" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b12e05d9e06373163a9bb6bb8c263c261b396643a99445fe6b9811fd376581b" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "uniffi" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cb08c58c7ed7033150132febe696bef553f891b1ede57424b40d87a89e3c170" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi-bindgen" +version = "0.1.0" +dependencies = [ + "uniffi", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cade167af943e189a55020eda2c314681e223f1e42aca7c4e52614c2b627698f" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err", + "glob", + "goblin", + "heck 0.5.0", + "once_cell", + "paste", + "serde", + "textwrap", + "toml", + "uniffi_meta", + "uniffi_udl", +] + +[[package]] +name = "uniffi_build" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7cf32576e08104b7dc2a6a5d815f37616e66c6866c2a639fe16e6d2286b75b" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" +dependencies = [ + "quote", + "syn 2.0.87", +] + +[[package]] +name = "uniffi_core" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f" +dependencies = [ + "anyhow", + "bytes", + "log", + "once_cell", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c65a5b12ec544ef136693af8759fb9d11aefce740fb76916721e876639033b" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.87", + "toml", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a74ed96c26882dac1ca9b93ca23c827e284bacbd7ec23c6f0b0372f747d59e4" +dependencies = [ + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6f984f0781f892cc864a62c3a5c60361b1ccbd68e538e6c9fbced5d82268ac" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037820a4cfc4422db1eaa82f291a3863c92c7d1789dc513489c36223f9b4cdfc" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "url", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", + "rand", + "serde", + "uuid-macro-internal", +] + +[[package]] +name = "uuid-macro-internal" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b91f57fe13a38d0ce9e28a03463d8d3c2468ed03d75375110ec71d93b449a08" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "validation" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb8044f0b8a3e94bc8cd089c6a2e42e435553093800b76762418d4bbc3289cc" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wana_kana" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74666202acfcb4f9b995be2e3e9f7f530deb65e05a1407b8d0b30c9c451238a" +dependencies = [ + "fnv", + "itertools 0.10.5", + "lazy_static", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom", +] + +[[package]] +name = "whatlang" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471d1c1645d361eb782a1650b1786a8fb58dd625e681a04c09f5ff7c8764a7b0" +dependencies = [ + "hashbrown 0.14.5", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "yada" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aed111bd9e48a802518765906cbdadf0b45afb72b9c81ab049a3b86252adffdd" + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..bcf18e0a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +resolver = "2" +members = ["cli", "lib", "bindings/node", "uniffi-bindgen"] + +[profile.release] +codegen-units = 1 +lto = true +panic = "abort" +strip = "symbols" + +[profile.dev.package] +insta.opt-level = 3 + +# The profile that 'dist' will build with +[profile.dist] +inherits = "release" +lto = "thin" + +[workspace.dependencies] +uniffi = "0.28.0" diff --git a/jvm/.gitattributes b/bindings/java/.gitattributes similarity index 100% rename from jvm/.gitattributes rename to bindings/java/.gitattributes diff --git a/jvm/.gitignore b/bindings/java/.gitignore similarity index 100% rename from jvm/.gitignore rename to bindings/java/.gitignore diff --git a/jvm/lib/build.gradle b/bindings/java/lib/build.gradle similarity index 78% rename from jvm/lib/build.gradle rename to bindings/java/lib/build.gradle index a60db107..2630c315 100644 --- a/jvm/lib/build.gradle +++ b/bindings/java/lib/build.gradle @@ -8,12 +8,12 @@ plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - id "org.jetbrains.kotlin.jvm" version "1.9.23" + id "org.jetbrains.kotlin.jvm" version "2.1.0" // Apply the java-library plugin for API and implementation separation. id "java-library" - id("com.google.devtools.ksp").version("1.9.23-1.0.19") + id("com.google.devtools.ksp").version("2.1.0-1.0.29") } repositories { @@ -26,7 +26,7 @@ dependencies { implementation platform("org.jetbrains.kotlin:kotlin-bom") // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation "com.google.guava:guava:33.1.0-jre" + implementation "com.google.guava:guava:33.3.1-jre" // Use the Kotlin test library. testImplementation "org.jetbrains.kotlin:kotlin-test" @@ -38,7 +38,7 @@ dependencies { api "org.apache.commons:commons-math3:3.6.1" // For parsing JSON - implementation "com.squareup.moshi:moshi:1.15.1" - implementation("com.squareup.moshi:moshi-kotlin:1.15.1") - ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.1") + implementation "com.squareup.moshi:moshi:1.15.2" + implementation("com.squareup.moshi:moshi-kotlin:1.15.2") + ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.2") } diff --git a/jvm/lib/src/main/kotlin/org/odict/Dictionary.kt b/bindings/java/lib/src/main/kotlin/org/odict/Dictionary.kt similarity index 89% rename from jvm/lib/src/main/kotlin/org/odict/Dictionary.kt rename to bindings/java/lib/src/main/kotlin/org/odict/Dictionary.kt index fc6467ea..7be25b64 100644 --- a/jvm/lib/src/main/kotlin/org/odict/Dictionary.kt +++ b/bindings/java/lib/src/main/kotlin/org/odict/Dictionary.kt @@ -12,15 +12,13 @@ import kotlin.io.path.writeText class Dictionary constructor(private val path: String) { - fun lookup(vararg queries: String, follow: Boolean = false, split: Int = 0, markdownStrategy: String = "html"): List> { + fun lookup(vararg queries: String, follow: Boolean = false, split: Int = 0): List> { var args = arrayOf("lookup", "-f", "json") if (follow) { args += "-F" } - args += arrayOf("--markdown", markdownStrategy) - args += arrayOf("-s", split.toString(), path) val resultJson = execute(*args, *queries) @@ -37,7 +35,7 @@ class Dictionary constructor(private val path: String) { return lexicon?.trim()?.split("\n") ?: emptyList() } - fun search(vararg queries: String, index: Boolean = false): List { + fun search(vararg queries: String, index: Boolean = false): List> { var args = arrayOf("search", this.path, *queries) if (index) { @@ -45,6 +43,7 @@ class Dictionary constructor(private val path: String) { } val output = execute(*args) + return output?.let { searchAdapter.fromJson(it) } ?: emptyList() } @@ -55,8 +54,10 @@ class Dictionary constructor(private val path: String) { private val outerLookupType = Types.newParameterizedType(MutableList::class.java, innerLookupType) private val lookupAdapter: JsonAdapter>> = moshi.adapter(outerLookupType) + private val innerSearchType = Types.newParameterizedType(MutableList::class.java, Entry::class.java) + private val outerSearchType = Types.newParameterizedType(MutableList::class.java, innerSearchType) private val searchType = Types.newParameterizedType(List::class.java, Entry::class.java) - private val searchAdapter = moshi.adapter>(searchType) + private val searchAdapter = moshi.adapter>>(outerSearchType) fun compile(path: String) { this.execute("compile", path) @@ -71,7 +72,7 @@ class Dictionary constructor(private val path: String) { private fun execute(vararg args: String): String? { return try { - val baseArgs = arrayOf(if (System.getenv("RUNTIME_ENV") == "test") "../../bin/odict" else "odict", "--quiet") + val baseArgs = arrayOf(if (System.getenv("RUNTIME_ENV") == "test") "../../../target/debug/odict" else "odict", "--quiet") val proc = ProcessBuilder(*(baseArgs + args)) .redirectOutput(ProcessBuilder.Redirect.PIPE) .start() diff --git a/bindings/java/lib/src/test/kotlin/org/odict/DictionaryTest.kt b/bindings/java/lib/src/test/kotlin/org/odict/DictionaryTest.kt new file mode 100644 index 00000000..391f73a0 --- /dev/null +++ b/bindings/java/lib/src/test/kotlin/org/odict/DictionaryTest.kt @@ -0,0 +1,53 @@ +package org.odict + +import kotlin.test.Test +import kotlin.test.assertEquals + +class DictionaryTest { + @Test fun testLookup() { + Dictionary.compile("../../../examples/example2.xml") + + val dict = Dictionary("../../../examples/example2.odict") + val entry = dict.lookup("markdown") + + assertEquals("This **is** a _markdown_ test", entry[0][0].etymologies?.get(0)?.senses?.get("v")?.definitions?.get(0)?.value); + } + + @Test fun testLexicon() { + Dictionary.compile("../../../examples/example1.xml") + + val dict = Dictionary("../../../examples/example1.odict") + val lexicon = dict.lexicon() + + assertEquals(lexicon, listOf("cat", "dog", "poo", "ran", "run")) + } + + @Test + @Throws(Exception::class) + fun testSearch() { + Dictionary.compile("../../../examples/example1.xml") + + val dict = Dictionary("../../../examples/example1.odict") + + dict.index() + + val json = dict.search("run") + + assertEquals(1, json.count()) + assertEquals("run", json[0][0].term) + } + + @Test + @Throws(Exception::class) + fun testWrite() { + Dictionary.write( + "", + "test.odict") + + val dict = Dictionary("test.odict") + val entries = dict.lookup("hello") + + assertEquals("hello", entries[0][0].term) + assertEquals("hello world", entries[0][0].etymologies?.get(0)?.senses?.get("v")?.definitions?.get(0)?.value) + } +} diff --git a/jvm/settings.gradle b/bindings/java/settings.gradle similarity index 100% rename from jvm/settings.gradle rename to bindings/java/settings.gradle diff --git a/bindings/java/tasks.toml b/bindings/java/tasks.toml new file mode 100644 index 00000000..0d6ca6ae --- /dev/null +++ b/bindings/java/tasks.toml @@ -0,0 +1,13 @@ +["clean:java"] +run = "gradle clean" +dir = "bindings/java" + +["build:java"] +run = "gradle assemble" +dir = "bindings/java" +depends = ["build:cli"] + +["test:java"] +dir = "bindings/java" +run = ["RUNTIME_ENV=test gradle test --info", "gradle clean"] +depends = ["build:cli"] diff --git a/bindings/node/.gitignore b/bindings/node/.gitignore new file mode 100644 index 00000000..03256f04 --- /dev/null +++ b/bindings/node/.gitignore @@ -0,0 +1,198 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node +# Edit at https://www.toptal.com/developers/gitignore?templates=node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# End of https://www.toptal.com/developers/gitignore/api/node + +# Created by https://www.toptal.com/developers/gitignore/api/macos +# Edit at https://www.toptal.com/developers/gitignore?templates=macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +# End of https://www.toptal.com/developers/gitignore/api/macos + +# Created by https://www.toptal.com/developers/gitignore/api/windows +# Edit at https://www.toptal.com/developers/gitignore?templates=windows + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/windows + +#Added by cargo + +/target +Cargo.lock + +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +artifacts +*.node \ No newline at end of file diff --git a/bindings/node/.npmignore b/bindings/node/.npmignore new file mode 100644 index 00000000..ec144db2 --- /dev/null +++ b/bindings/node/.npmignore @@ -0,0 +1,13 @@ +target +Cargo.lock +.cargo +.github +npm +.eslintrc +.prettierignore +rustfmt.toml +yarn.lock +*.node +.yarn +__test__ +renovate.json diff --git a/bindings/node/Cargo.toml b/bindings/node/Cargo.toml new file mode 100644 index 00000000..f7e9252c --- /dev/null +++ b/bindings/node/Cargo.toml @@ -0,0 +1,18 @@ +[package] +edition = "2021" +name = "odict_node" +version = "0.0.0" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +merge = "0.1.0" +# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix +napi = { version = "2.12.2", default-features = false, features = ["napi4"] } +napi-derive = "2.12.2" +odict = { path = "../../lib", features = ["config", "sql", "search", "json"] } + +[build-dependencies] +napi-build = "2.0.1" diff --git a/bindings/node/build.rs b/bindings/node/build.rs new file mode 100644 index 00000000..1f866b6a --- /dev/null +++ b/bindings/node/build.rs @@ -0,0 +1,5 @@ +extern crate napi_build; + +fn main() { + napi_build::setup(); +} diff --git a/bindings/node/index.d.ts b/bindings/node/index.d.ts new file mode 100644 index 00000000..115ed3a0 --- /dev/null +++ b/bindings/node/index.d.ts @@ -0,0 +1,117 @@ +/* auto-generated by NAPI-RS */ +/* eslint-disable */ +export declare class Dictionary { + constructor( + pathOrAlias: string, + options?: DictionaryOptions | undefined | null, + ); + static write( + xmlStr: string, + outPath: string, + options?: DictionaryOptions | undefined | null, + ): Dictionary; + static compile( + xmlPath: string, + outPath?: string | undefined | null, + options?: DictionaryOptions | undefined | null, + ): Dictionary; + get path(): string; + lookup( + query: LookupQuery | string | Array, + options?: LookupOptions | undefined | null, + ): Array>; + lexicon(): Array; + split(query: string, options?: SplitOptions | undefined | null): Array; + index(options?: IndexOptions | undefined | null): void; + search( + query: string, + options?: SearchOptions | undefined | null, + ): Array; +} + +export declare class MdString { + constructor(value: string); + get value(): string; + parse(strategy: MarkdownStrategy): string; +} +export type MDString = MdString; + +export interface Definition { + id?: string; + value: MDString; + examples: Array; + notes: Array; +} + +export interface DictionaryOptions { + split?: SplitOptions; + index?: IndexOptions; + search?: SearchOptions; +} + +export interface Entry { + term: string; + seeAlso?: string; + etymologies: Array; +} + +export interface Etymology { + id?: string; + pronunciation?: string; + description?: MDString; + senses: Record; +} + +export interface Example { + value: MDString; +} + +export interface Group { + id?: string; + description: MDString; + definitions: Array; +} + +export interface IndexOptions { + directory?: string; + memory?: number; + overwrite?: boolean; +} + +export interface LookupOptions { + split?: number; + follow?: boolean; +} + +export interface LookupQuery { + term: string; + fallback: string; +} + +export declare const enum MarkdownStrategy { + Disabled = 0, + HTML = 1, + Text = 2, +} + +export interface Note { + id?: string; + value: MdString; + examples: Array; +} + +export interface SearchOptions { + directory?: string; + threshold?: number; + autoindex?: boolean; + limit?: number; +} + +export interface Sense { + pos: string; + definitions: Array; +} + +export interface SplitOptions { + threshold?: number; +} diff --git a/bindings/node/index.js b/bindings/node/index.js new file mode 100644 index 00000000..3ebdbfd0 --- /dev/null +++ b/bindings/node/index.js @@ -0,0 +1,370 @@ +// prettier-ignore +/* eslint-disable */ +// @ts-nocheck +/* auto-generated by NAPI-RS */ + +const { createRequire } = require('node:module') +require = createRequire(__filename); + +const { readFileSync } = require("node:fs"); +let nativeBinding = null; +const loadErrors = []; + +const isMusl = () => { + let musl = false; + if (process.platform === "linux") { + musl = isMuslFromFilesystem(); + if (musl === null) { + musl = isMuslFromReport(); + } + if (musl === null) { + musl = isMuslFromChildProcess(); + } + } + return musl; +}; + +const isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-"); + +const isMuslFromFilesystem = () => { + try { + return readFileSync("/usr/bin/ldd", "utf-8").includes("musl"); + } catch { + return null; + } +}; + +const isMuslFromReport = () => { + const report = + typeof process.report.getReport === "function" + ? process.report.getReport() + : null; + if (!report) { + return null; + } + if (report.header && report.header.glibcVersionRuntime) { + return false; + } + if (Array.isArray(report.sharedObjects)) { + if (report.sharedObjects.some(isFileMusl)) { + return true; + } + } + return false; +}; + +const isMuslFromChildProcess = () => { + try { + return require("child_process") + .execSync("ldd --version", { encoding: "utf8" }) + .includes("musl"); + } catch (e) { + // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false + return false; + } +}; + +function requireNative() { + if (process.platform === "android") { + if (process.arch === "arm64") { + try { + return require("./node.android-arm64.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-android-arm64"); + } catch (e) { + loadErrors.push(e); + } + } else if (process.arch === "arm") { + try { + return require("./node.android-arm-eabi.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-android-arm-eabi"); + } catch (e) { + loadErrors.push(e); + } + } else { + loadErrors.push( + new Error(`Unsupported architecture on Android ${process.arch}`), + ); + } + } else if (process.platform === "win32") { + if (process.arch === "x64") { + try { + return require("./node.win32-x64-msvc.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-win32-x64-msvc"); + } catch (e) { + loadErrors.push(e); + } + } else if (process.arch === "ia32") { + try { + return require("./node.win32-ia32-msvc.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-win32-ia32-msvc"); + } catch (e) { + loadErrors.push(e); + } + } else if (process.arch === "arm64") { + try { + return require("./node.win32-arm64-msvc.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-win32-arm64-msvc"); + } catch (e) { + loadErrors.push(e); + } + } else { + loadErrors.push( + new Error(`Unsupported architecture on Windows: ${process.arch}`), + ); + } + } else if (process.platform === "darwin") { + try { + return require("./node.darwin-universal.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-darwin-universal"); + } catch (e) { + loadErrors.push(e); + } + + if (process.arch === "x64") { + try { + return require("./node.darwin-x64.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-darwin-x64"); + } catch (e) { + loadErrors.push(e); + } + } else if (process.arch === "arm64") { + try { + return require("./node.darwin-arm64.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-darwin-arm64"); + } catch (e) { + loadErrors.push(e); + } + } else { + loadErrors.push( + new Error(`Unsupported architecture on macOS: ${process.arch}`), + ); + } + } else if (process.platform === "freebsd") { + if (process.arch === "x64") { + try { + return require("./node.freebsd-x64.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-freebsd-x64"); + } catch (e) { + loadErrors.push(e); + } + } else if (process.arch === "arm64") { + try { + return require("./node.freebsd-arm64.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-freebsd-arm64"); + } catch (e) { + loadErrors.push(e); + } + } else { + loadErrors.push( + new Error(`Unsupported architecture on FreeBSD: ${process.arch}`), + ); + } + } else if (process.platform === "linux") { + if (process.arch === "x64") { + if (isMusl()) { + try { + return require("./node.linux-x64-musl.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-x64-musl"); + } catch (e) { + loadErrors.push(e); + } + } else { + try { + return require("./node.linux-x64-gnu.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-x64-gnu"); + } catch (e) { + loadErrors.push(e); + } + } + } else if (process.arch === "arm64") { + if (isMusl()) { + try { + return require("./node.linux-arm64-musl.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-arm64-musl"); + } catch (e) { + loadErrors.push(e); + } + } else { + try { + return require("./node.linux-arm64-gnu.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-arm64-gnu"); + } catch (e) { + loadErrors.push(e); + } + } + } else if (process.arch === "arm") { + if (isMusl()) { + try { + return require("./node.linux-arm-musleabihf.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-arm-musleabihf"); + } catch (e) { + loadErrors.push(e); + } + } else { + try { + return require("./node.linux-arm-gnueabihf.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-arm-gnueabihf"); + } catch (e) { + loadErrors.push(e); + } + } + } else if (process.arch === "riscv64") { + if (isMusl()) { + try { + return require("./node.linux-riscv64-musl.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-riscv64-musl"); + } catch (e) { + loadErrors.push(e); + } + } else { + try { + return require("./node.linux-riscv64-gnu.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-riscv64-gnu"); + } catch (e) { + loadErrors.push(e); + } + } + } else if (process.arch === "ppc64") { + try { + return require("./node.linux-ppc64-gnu.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-ppc64-gnu"); + } catch (e) { + loadErrors.push(e); + } + } else if (process.arch === "s390x") { + try { + return require("./node.linux-s390x-gnu.node"); + } catch (e) { + loadErrors.push(e); + } + try { + return require("@odict/node-linux-s390x-gnu"); + } catch (e) { + loadErrors.push(e); + } + } else { + loadErrors.push( + new Error(`Unsupported architecture on Linux: ${process.arch}`), + ); + } + } else { + loadErrors.push( + new Error( + `Unsupported OS: ${process.platform}, architecture: ${process.arch}`, + ), + ); + } +} + +nativeBinding = requireNative(); + +if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { + try { + nativeBinding = require("./node.wasi.cjs"); + } catch (err) { + if (process.env.NAPI_RS_FORCE_WASI) { + loadErrors.push(err); + } + } + if (!nativeBinding) { + try { + nativeBinding = require("@odict/node-wasm32-wasi"); + } catch (err) { + if (process.env.NAPI_RS_FORCE_WASI) { + loadErrors.push(err); + } + } + } +} + +if (!nativeBinding) { + if (loadErrors.length > 0) { + // TODO Link to documentation with potential fixes + // - The package owner could build/publish bindings for this arch + // - The user may need to bundle the correct files + // - The user may need to re-install node_modules to get new packages + throw new Error("Failed to load native binding", { cause: loadErrors }); + } + throw new Error(`Failed to load native binding`); +} + +module.exports.Dictionary = nativeBinding.Dictionary; +module.exports.MdString = nativeBinding.MdString; +module.exports.MDString = nativeBinding.MDString; +module.exports.MarkdownStrategy = nativeBinding.MarkdownStrategy; diff --git a/js/jest.config.cjs b/bindings/node/jest.config.cjs similarity index 100% rename from js/jest.config.cjs rename to bindings/node/jest.config.cjs diff --git a/bindings/node/package.json b/bindings/node/package.json new file mode 100644 index 00000000..11186362 --- /dev/null +++ b/bindings/node/package.json @@ -0,0 +1,49 @@ +{ + "name": "@odict/node", + "version": "0.0.1-beta.0", + "main": "index.js", + "types": "index.d.ts", + "files": [ + "index.js", + "index.d.ts" + ], + "napi": { + "binaryName": "node", + "targets": [ + "x86_64-apple-darwin", + "aarch64-apple-darwin", + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-musl", + "aarch64-unknown-linux-gnu", + "i686-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "aarch64-linux-android", + "x86_64-unknown-freebsd", + "aarch64-unknown-linux-musl", + "aarch64-pc-windows-msvc", + "armv7-linux-androideabi" + ] + }, + "license": "MIT", + "devDependencies": { + "@emnapi/core": "^1.3.1", + "@napi-rs/cli": "3.0.0-alpha.64", + "@types/node": "^22.0.0", + "prettier": "^3.3.2", + "vitest": "^2.1.5" + }, + "engines": { + "node": ">= 10" + }, + "scripts": { + "create-dirs": "napi create-npm-dirs", + "build": "napi build --release --platform --pipe \"prettier -w\"", + "build:debug": "napi build --platform --pipe \"prettier -w\"", + "test": "vitest --no-watch", + "universal": "napi universal", + "artifacts": "napi artifacts", + "version": "napi version", + "prepublishOnly": "napi prepublish -t npm" + } +} diff --git a/bindings/node/pnpm-lock.yaml b/bindings/node/pnpm-lock.yaml new file mode 100644 index 00000000..588ec2cc --- /dev/null +++ b/bindings/node/pnpm-lock.yaml @@ -0,0 +1,849 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@napi-rs/cli': + specifier: ^2.18.0 + version: 2.18.3 + '@types/node': + specifier: ^22.0.0 + version: 22.9.0 + prettier: + specifier: ^3.3.2 + version: 3.3.3 + vitest: + specifier: ^2.1.5 + version: 2.1.5(@types/node@22.9.0) + +packages: + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@napi-rs/cli@2.18.3': + resolution: {integrity: sha512-L0f4kP0dyG8W5Qtc7MtP73VvLLrOLyRcUEBzknIfu8Jk4Jfhrsx1ItMHgyalYqMSslWdY3ojEfAaU5sx1VyeQQ==} + engines: {node: '>= 10'} + hasBin: true + + '@rollup/rollup-android-arm-eabi@4.27.2': + resolution: {integrity: sha512-Tj+j7Pyzd15wAdSJswvs5CJzJNV+qqSUcr/aCD+jpQSBtXvGnV0pnrjoc8zFTe9fcKCatkpFpOO7yAzpO998HA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.27.2': + resolution: {integrity: sha512-xsPeJgh2ThBpUqlLgRfiVYBEf/P1nWlWvReG+aBWfNv3XEBpa6ZCmxSVnxJgLgkNz4IbxpLy64h2gCmAAQLneQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.27.2': + resolution: {integrity: sha512-KnXU4m9MywuZFedL35Z3PuwiTSn/yqRIhrEA9j+7OSkji39NzVkgxuxTYg5F8ryGysq4iFADaU5osSizMXhU2A==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.27.2': + resolution: {integrity: sha512-Hj77A3yTvUeCIx/Vi+4d4IbYhyTwtHj07lVzUgpUq9YpJSEiGJj4vXMKwzJ3w5zp5v3PFvpJNgc/J31smZey6g==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.27.2': + resolution: {integrity: sha512-RjgKf5C3xbn8gxvCm5VgKZ4nn0pRAIe90J0/fdHUsgztd3+Zesb2lm2+r6uX4prV2eUByuxJNdt647/1KPRq5g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.27.2': + resolution: {integrity: sha512-duq21FoXwQtuws+V9H6UZ+eCBc7fxSpMK1GQINKn3fAyd9DFYKPJNcUhdIKOrMFjLEJgQskoMoiuizMt+dl20g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.27.2': + resolution: {integrity: sha512-6npqOKEPRZkLrMcvyC/32OzJ2srdPzCylJjiTJT2c0bwwSGm7nz2F9mNQ1WrAqCBZROcQn91Fno+khFhVijmFA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.27.2': + resolution: {integrity: sha512-V9Xg6eXtgBtHq2jnuQwM/jr2mwe2EycnopO8cbOvpzFuySCGtKlPCI3Hj9xup/pJK5Q0388qfZZy2DqV2J8ftw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.27.2': + resolution: {integrity: sha512-uCFX9gtZJoQl2xDTpRdseYuNqyKkuMDtH6zSrBTA28yTfKyjN9hQ2B04N5ynR8ILCoSDOrG/Eg+J2TtJ1e/CSA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.27.2': + resolution: {integrity: sha512-/PU9P+7Rkz8JFYDHIi+xzHabOu9qEWR07L5nWLIUsvserrxegZExKCi2jhMZRd0ATdboKylu/K5yAXbp7fYFvA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.27.2': + resolution: {integrity: sha512-eCHmol/dT5odMYi/N0R0HC8V8QE40rEpkyje/ZAXJYNNoSfrObOvG/Mn+s1F/FJyB7co7UQZZf6FuWnN6a7f4g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.27.2': + resolution: {integrity: sha512-DEP3Njr9/ADDln3kNi76PXonLMSSMiCir0VHXxmGSHxCxDfQ70oWjHcJGfiBugzaqmYdTC7Y+8Int6qbnxPBIQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.27.2': + resolution: {integrity: sha512-NHGo5i6IE/PtEPh5m0yw5OmPMpesFnzMIS/lzvN5vknnC1sXM5Z/id5VgcNPgpD+wHmIcuYYgW+Q53v+9s96lQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.27.2': + resolution: {integrity: sha512-PaW2DY5Tan+IFvNJGHDmUrORadbe/Ceh8tQxi8cmdQVCCYsLoQo2cuaSj+AU+YRX8M4ivS2vJ9UGaxfuNN7gmg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.27.2': + resolution: {integrity: sha512-dOlWEMg2gI91Qx5I/HYqOD6iqlJspxLcS4Zlg3vjk1srE67z5T2Uz91yg/qA8sY0XcwQrFzWWiZhMNERylLrpQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.27.2': + resolution: {integrity: sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.27.2': + resolution: {integrity: sha512-RsnE6LQkUHlkC10RKngtHNLxb7scFykEbEwOFDjr3CeCMG+Rr+cKqlkKc2/wJ1u4u990urRHCbjz31x84PBrSQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.27.2': + resolution: {integrity: sha512-foJM5vv+z2KQmn7emYdDLyTbkoO5bkHZE1oth2tWbQNGW7mX32d46Hz6T0MqXdWS2vBZhaEtHqdy9WYwGfiliA==} + cpu: [x64] + os: [win32] + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/node@22.9.0': + resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + + '@vitest/expect@2.1.5': + resolution: {integrity: sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==} + + '@vitest/mocker@2.1.5': + resolution: {integrity: sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.5': + resolution: {integrity: sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==} + + '@vitest/runner@2.1.5': + resolution: {integrity: sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==} + + '@vitest/snapshot@2.1.5': + resolution: {integrity: sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==} + + '@vitest/spy@2.1.5': + resolution: {integrity: sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==} + + '@vitest/utils@2.1.5': + resolution: {integrity: sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + + magic-string@0.30.12: + resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + + rollup@4.27.2: + resolution: {integrity: sha512-KreA+PzWmk2yaFmZVwe6GB2uBD86nXl86OsDkt1bJS9p3vqWuEQ6HnJJ+j/mZi/q0920P99/MVRlB4L3crpF5w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.1: + resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + + tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + vite-node@2.1.5: + resolution: {integrity: sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.11: + resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.5: + resolution: {integrity: sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.5 + '@vitest/ui': 2.1.5 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + +snapshots: + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@napi-rs/cli@2.18.3': {} + + '@rollup/rollup-android-arm-eabi@4.27.2': + optional: true + + '@rollup/rollup-android-arm64@4.27.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.27.2': + optional: true + + '@rollup/rollup-darwin-x64@4.27.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.27.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.27.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.27.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.27.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.27.2': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.27.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.27.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.27.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.27.2': + optional: true + + '@types/estree@1.0.6': {} + + '@types/node@22.9.0': + dependencies: + undici-types: 6.19.8 + + '@vitest/expect@2.1.5': + dependencies: + '@vitest/spy': 2.1.5 + '@vitest/utils': 2.1.5 + chai: 5.1.2 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.5(vite@5.4.11(@types/node@22.9.0))': + dependencies: + '@vitest/spy': 2.1.5 + estree-walker: 3.0.3 + magic-string: 0.30.12 + optionalDependencies: + vite: 5.4.11(@types/node@22.9.0) + + '@vitest/pretty-format@2.1.5': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.5': + dependencies: + '@vitest/utils': 2.1.5 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.5': + dependencies: + '@vitest/pretty-format': 2.1.5 + magic-string: 0.30.12 + pathe: 1.1.2 + + '@vitest/spy@2.1.5': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.5': + dependencies: + '@vitest/pretty-format': 2.1.5 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + + assertion-error@2.0.1: {} + + cac@6.7.14: {} + + chai@5.1.2: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + + check-error@2.1.1: {} + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + es-module-lexer@1.5.4: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + expect-type@1.1.0: {} + + fsevents@2.3.3: + optional: true + + loupe@3.1.2: {} + + magic-string@0.30.12: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + ms@2.1.3: {} + + nanoid@3.3.7: {} + + pathe@1.1.2: {} + + pathval@2.0.0: {} + + picocolors@1.1.1: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.3.3: {} + + rollup@4.27.2: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.27.2 + '@rollup/rollup-android-arm64': 4.27.2 + '@rollup/rollup-darwin-arm64': 4.27.2 + '@rollup/rollup-darwin-x64': 4.27.2 + '@rollup/rollup-freebsd-arm64': 4.27.2 + '@rollup/rollup-freebsd-x64': 4.27.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.27.2 + '@rollup/rollup-linux-arm-musleabihf': 4.27.2 + '@rollup/rollup-linux-arm64-gnu': 4.27.2 + '@rollup/rollup-linux-arm64-musl': 4.27.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.27.2 + '@rollup/rollup-linux-riscv64-gnu': 4.27.2 + '@rollup/rollup-linux-s390x-gnu': 4.27.2 + '@rollup/rollup-linux-x64-gnu': 4.27.2 + '@rollup/rollup-linux-x64-musl': 4.27.2 + '@rollup/rollup-win32-arm64-msvc': 4.27.2 + '@rollup/rollup-win32-ia32-msvc': 4.27.2 + '@rollup/rollup-win32-x64-msvc': 4.27.2 + fsevents: 2.3.3 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.8.0: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.1: {} + + tinypool@1.0.2: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + + undici-types@6.19.8: {} + + vite-node@2.1.5(@types/node@22.9.0): + dependencies: + cac: 6.7.14 + debug: 4.3.7 + es-module-lexer: 1.5.4 + pathe: 1.1.2 + vite: 5.4.11(@types/node@22.9.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.11(@types/node@22.9.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.49 + rollup: 4.27.2 + optionalDependencies: + '@types/node': 22.9.0 + fsevents: 2.3.3 + + vitest@2.1.5(@types/node@22.9.0): + dependencies: + '@vitest/expect': 2.1.5 + '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@22.9.0)) + '@vitest/pretty-format': 2.1.5 + '@vitest/runner': 2.1.5 + '@vitest/snapshot': 2.1.5 + '@vitest/spy': 2.1.5 + '@vitest/utils': 2.1.5 + chai: 5.1.2 + debug: 4.3.7 + expect-type: 1.1.0 + magic-string: 0.30.12 + pathe: 1.1.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.1 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.4.11(@types/node@22.9.0) + vite-node: 2.1.5(@types/node@22.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.9.0 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 diff --git a/bindings/node/rustfmt.toml b/bindings/node/rustfmt.toml new file mode 100644 index 00000000..cab5731e --- /dev/null +++ b/bindings/node/rustfmt.toml @@ -0,0 +1,2 @@ +tab_spaces = 2 +edition = "2021" diff --git a/bindings/node/src/dictionary.rs b/bindings/node/src/dictionary.rs new file mode 100644 index 00000000..c9db2d93 --- /dev/null +++ b/bindings/node/src/dictionary.rs @@ -0,0 +1,260 @@ +use std::{borrow::BorrowMut, path::PathBuf, vec}; + +use napi::bindgen_prelude::*; + +use merge::Merge; + +use crate::{ + types::{ + self, DictionaryOptions, Entry, IndexOptions, LookupOptions, LookupQuery, SearchOptions, + SplitOptions, + }, + utils::{cast_error, resolve_options, to_lookup_query}, +}; + +#[napi] +pub struct Dictionary { + options: Option, + file: odict::DictionaryFile, +} + +#[napi] +impl Dictionary { + #[napi(constructor)] + pub fn new(path_or_alias: String, options: Option) -> Result { + let reader = odict::DictionaryReader::default(); + + let file = reader + .read_from_path_or_alias(&path_or_alias) + .map_err(cast_error)?; + + let dict = Dictionary { options, file }; + + Ok(dict) + } + + #[napi(factory)] + pub fn write( + xml_str: String, + out_path: String, + options: Option, + ) -> Result { + let dict = odict::Dictionary::from(&xml_str).map_err(cast_error)?; + let reader = odict::DictionaryReader::default(); + let writer = odict::DictionaryWriter::default(); + + writer.write_to_path(&dict, &out_path).map_err(cast_error)?; + + let file = reader.read_from_path(&out_path).map_err(cast_error)?; + + let dict = Dictionary { options, file }; + + Ok(dict) + } + + #[napi(factory)] + pub fn compile( + xml_path: String, + out_path: Option, + options: Option, + ) -> Result { + let in_file = PathBuf::from(xml_path.to_owned()); + + let out_file = out_path.unwrap_or_else(|| { + odict::fs::infer_path(&xml_path) + .to_string_lossy() + .to_string() + }); + + let reader = odict::DictionaryReader::default(); + let writer = odict::DictionaryWriter::default(); + + writer + .compile_xml(&in_file, &out_file) + .map_err(cast_error)?; + + let file = reader.read_from_path(&out_file).map_err(cast_error)?; + + let dict = Dictionary { options, file }; + + Ok(dict) + } + + pub fn options(&self) -> DictionaryOptions { + resolve_options(&self.options) + } + + #[napi(getter)] + pub fn path(&self) -> napi::Result { + let path = self + .file + .path + .as_ref() + .map(|p| p.to_string_lossy().to_string()) + .unwrap(); + + Ok(path) + } + + pub fn _lookup( + &self, + env: napi::Env, + queries: &Vec, + options: Option, + ) -> Result>> { + let dict = self.file.to_archive().map_err(cast_error)?; + + let mut opts = options.unwrap_or(LookupOptions::default()); + + if let Some(split) = opts + .split + .or(self.options().split.map(|s| s.threshold).flatten()) + { + opts.split = Some(split); + } + + let entries = dict + .lookup::(queries, &opts.into()) + .map_err(|e| cast_error(e))?; + + let mapped = entries + .iter() + .map(|i| { + i.iter() + .map(|e| Entry::from_archive(env, e)) + .collect::, _>>() + }) + .collect::>, _>>()?; + + Ok(mapped) + } + + #[napi] + pub fn lookup( + &self, + env: Env, + query: Either3>>, + options: Option, + ) -> Result>> { + let mut queries: Vec = vec![]; + + match query { + Either3::A(a) => queries.push(a.into()), + Either3::B(b) => queries.push(b.into()), + Either3::C(c) => queries.append( + c.into_iter() + .map(to_lookup_query) + .collect::>() + .borrow_mut(), + ), + } + + self._lookup(env, &queries, options) + } + + #[napi] + pub fn lexicon(&self) -> Result> { + let dict = self.file.to_archive().map_err(cast_error)?; + let lexicon = dict.lexicon(); + + Ok(lexicon) + } + + #[napi] + pub fn split( + &self, + env: Env, + query: String, + options: Option, + ) -> Result> { + let dict = self.file.to_archive().map_err(cast_error)?; + + let mut opts = options; + + opts.merge(self.options().split); + + let result = dict + .split::<&odict::split::SplitOptions>(&query, &opts.unwrap().into()) + .map_err(|e| cast_error(e))?; + + Ok( + result + .iter() + .map(|e| Entry::from_archive(env, e)) + .collect::, _>>()?, + ) + } + + #[napi] + pub fn index(&self, options: Option) -> Result<()> { + let dict = self.file.to_archive().map_err(cast_error)?; + let mut opts = options; + + opts.merge(self.options().index); + + dict + .index::<&odict::search::IndexOptions>(&opts.unwrap().into()) + .map_err(cast_error)?; + + Ok(()) + } + + #[napi] + pub fn search( + &self, + env: Env, + query: String, + options: Option, + ) -> Result> { + let dict = self.file.to_archive().map_err(cast_error)?; + let mut opts = options; + + opts.merge(self.options().search); + + let results = dict + .search::<&odict::search::SearchOptions>(query.as_str(), &opts.unwrap().into()) + .map_err(cast_error)?; + + let entries = results + .iter() + .map(|e| Entry::from_entry(env, e.clone())) + .collect::, _>>()?; + + Ok(entries) + } +} + +#[cfg(test)] +mod test { + use merge::Merge; + + #[test] + fn test_options_merging() { + let opts1 = crate::types::DictionaryOptions { + search: None, + index: Some(crate::types::IndexOptions { + directory: Some("test".to_string()), + memory: Some(1234), + overwrite: Some(false), + }), + split: { Some(crate::types::SplitOptions { threshold: Some(5) }) }, + }; + + let mut opts2: Option = None; + + let mut opts3: Option = Some(crate::types::SplitOptions { + threshold: Some(10), + }); + + opts2.merge(opts1.index); + opts3.merge(opts1.split); + + let result1 = opts2.unwrap(); + let result2 = opts3.unwrap(); + + assert_eq!(result1.directory.unwrap(), "test".to_string()); + assert_eq!(result1.memory.unwrap(), 1234); + assert_eq!(result1.overwrite.unwrap(), false); + assert_eq!(result2.threshold.unwrap(), 10); + } +} diff --git a/bindings/node/src/lib.rs b/bindings/node/src/lib.rs new file mode 100644 index 00000000..6e78d7fb --- /dev/null +++ b/bindings/node/src/lib.rs @@ -0,0 +1,8 @@ +#![deny(clippy::all)] + +#[macro_use] +extern crate napi_derive; + +mod dictionary; +mod types; +mod utils; diff --git a/bindings/node/src/types/definition.rs b/bindings/node/src/types/definition.rs new file mode 100644 index 00000000..8a053b46 --- /dev/null +++ b/bindings/node/src/types/definition.rs @@ -0,0 +1,35 @@ +use napi::bindgen_prelude::*; + +use super::{mdstring::MDString, note::Note, Example}; + +#[napi(object)] +pub struct Definition { + pub id: Option, + pub value: ClassInstance, + pub examples: Vec, + pub notes: Vec, +} + +impl Definition { + pub fn from(env: napi::Env, definition: odict::Definition) -> Result { + let odict::Definition { + id, + value, + examples, + notes, + } = definition; + + Ok(Self { + id, + value: MDString::from(value).into_instance(env)?, + examples: examples + .into_iter() + .map(|e| Example::from(env, e).unwrap()) + .collect::>(), + notes: notes + .into_iter() + .map(|n| Note::from(env, n).unwrap()) + .collect(), + }) + } +} diff --git a/bindings/node/src/types/dictionary.rs b/bindings/node/src/types/dictionary.rs new file mode 100644 index 00000000..6212872c --- /dev/null +++ b/bindings/node/src/types/dictionary.rs @@ -0,0 +1,21 @@ +use merge::Merge; + +use super::{IndexOptions, SearchOptions, SplitOptions}; + +#[napi(object)] +#[derive(PartialEq, Merge, Clone, Eq)] +pub struct DictionaryOptions { + pub split: Option, + pub index: Option, + pub search: Option, +} + +impl Default for DictionaryOptions { + fn default() -> Self { + DictionaryOptions { + split: Some(SplitOptions::default()), + index: Some(IndexOptions::default()), + search: Some(SearchOptions::default()), + } + } +} diff --git a/bindings/node/src/types/entry.rs b/bindings/node/src/types/entry.rs new file mode 100644 index 00000000..cb9b228e --- /dev/null +++ b/bindings/node/src/types/entry.rs @@ -0,0 +1,35 @@ +use napi::bindgen_prelude::*; + +use crate::utils::cast_error; + +use super::etymology::Etymology; + +#[napi(object)] +pub struct Entry { + pub term: String, + pub see_also: Option, + pub etymologies: Vec, +} + +impl Entry { + pub fn from_entry(env: napi::Env, entry: odict::Entry) -> Result { + let odict::Entry { + term, + see_also, + etymologies, + } = entry; + + Ok(Self { + term, + see_also, + etymologies: etymologies + .into_iter() + .map(|e| Etymology::from(env, e)) + .collect::, _>>()?, + }) + } + + pub fn from_archive(env: napi::Env, entry: &odict::ArchivedEntry) -> Result { + Entry::from_entry(env, entry.to_entry().map_err(cast_error)?) + } +} diff --git a/bindings/node/src/types/etymology.rs b/bindings/node/src/types/etymology.rs new file mode 100644 index 00000000..86fdbbfa --- /dev/null +++ b/bindings/node/src/types/etymology.rs @@ -0,0 +1,39 @@ +use std::collections::HashMap; + +use napi::bindgen_prelude::*; + +use super::{mdstring::MDString, sense::Sense}; + +#[napi(object)] +pub struct Etymology { + pub id: Option, + pub pronunciation: Option, + pub description: Option>, + pub senses: HashMap, +} + +impl Etymology { + pub fn from(env: napi::Env, etymology: odict::Etymology) -> Result { + let odict::Etymology { + id, + pronunciation, + description, + senses, + } = etymology; + + Ok(Self { + id, + pronunciation, + description: description + .map(|d| MDString::from(d).into_instance(env)) + .transpose()?, + senses: senses + .into_iter() + .map(|(k, v)| -> Result<(String, Sense), _> { + let sense = Sense::from(env, v)?; + Ok((k.to_string(), sense)) + }) + .collect::, _>>()?, + }) + } +} diff --git a/bindings/node/src/types/example.rs b/bindings/node/src/types/example.rs new file mode 100644 index 00000000..bd7ad81a --- /dev/null +++ b/bindings/node/src/types/example.rs @@ -0,0 +1,18 @@ +use napi::bindgen_prelude::*; + +use super::mdstring::MDString; + +#[napi(object)] +pub struct Example { + pub value: ClassInstance, +} + +impl Example { + pub fn from(env: napi::Env, note: odict::Example) -> Result { + let odict::Example { value } = note; + + Ok(Self { + value: MDString::from(value).into_instance(env).unwrap(), + }) + } +} diff --git a/bindings/node/src/types/group.rs b/bindings/node/src/types/group.rs new file mode 100644 index 00000000..2116cb00 --- /dev/null +++ b/bindings/node/src/types/group.rs @@ -0,0 +1,29 @@ +use napi::bindgen_prelude::*; + +use super::{definition::Definition, MDString}; + +#[napi(object)] +pub struct Group { + pub id: Option, + pub description: ClassInstance, + pub definitions: Vec, +} + +impl Group { + pub fn from(env: napi::Env, group: odict::Group) -> Result { + let odict::Group { + id, + description, + definitions, + } = group; + + Ok(Self { + id, + description: MDString::from(description).into_instance(env)?, + definitions: definitions + .into_iter() + .map(|d| Definition::from(env, d)) + .collect::, _>>()?, + }) + } +} diff --git a/bindings/node/src/types/index.rs b/bindings/node/src/types/index.rs new file mode 100644 index 00000000..05012347 --- /dev/null +++ b/bindings/node/src/types/index.rs @@ -0,0 +1,39 @@ +use merge::Merge; + +#[napi(object)] +#[derive(PartialEq, Merge, Clone, Eq)] +pub struct IndexOptions { + pub directory: Option, + pub memory: Option, + pub overwrite: Option, +} + +impl Default for IndexOptions { + fn default() -> Self { + IndexOptions { + overwrite: None, + directory: None, + memory: None, + } + } +} + +impl From for odict::search::IndexOptions { + fn from(opts: IndexOptions) -> Self { + let mut s = odict::search::IndexOptions::default(); + + if let Some(memory) = opts.memory { + s = s.memory(memory.try_into().unwrap()); + } + + if let Some(directory) = opts.directory { + s = s.dir(&directory); + } + + if let Some(overwrite) = opts.overwrite { + s = s.overwrite(overwrite); + } + + s + } +} diff --git a/bindings/node/src/types/lookup.rs b/bindings/node/src/types/lookup.rs new file mode 100644 index 00000000..566513f9 --- /dev/null +++ b/bindings/node/src/types/lookup.rs @@ -0,0 +1,48 @@ +use merge::Merge; + +#[napi(object)] +#[derive(Merge)] +pub struct LookupOptions { + pub split: Option, + pub follow: Option, +} + +impl Default for LookupOptions { + fn default() -> Self { + LookupOptions { + split: None, + follow: None, + } + } +} + +impl From for odict::lookup::LookupOptions { + fn from(opts: LookupOptions) -> Self { + let mut s = odict::lookup::LookupOptions::default(); + + if let Some(split) = opts.split { + s = s.split(split.try_into().unwrap()); + } + + if let Some(follow) = opts.follow { + s = s.follow(follow); + } + + s + } +} + +#[napi(object)] +pub struct LookupQuery { + pub term: String, + pub fallback: String, +} + +impl From for odict::lookup::LookupQuery { + fn from(q: LookupQuery) -> Self { + odict::lookup::LookupQuery { + term: q.term, + fallback: q.fallback, + } + } +} diff --git a/bindings/node/src/types/mdstring.rs b/bindings/node/src/types/mdstring.rs new file mode 100644 index 00000000..51f18ae4 --- /dev/null +++ b/bindings/node/src/types/mdstring.rs @@ -0,0 +1,60 @@ +use napi::bindgen_prelude::*; + +#[napi] +pub enum MarkdownStrategy { + Disabled, + HTML, + Text, +} + +impl From for odict::MarkdownStrategy { + fn from(strategy: MarkdownStrategy) -> Self { + match strategy { + MarkdownStrategy::Disabled => odict::MarkdownStrategy::Disabled, + MarkdownStrategy::HTML => odict::MarkdownStrategy::HTML, + MarkdownStrategy::Text => odict::MarkdownStrategy::Text, + } + } +} + +impl From<&str> for MarkdownStrategy { + fn from(strategy: &str) -> Self { + match strategy { + "html" => MarkdownStrategy::HTML, + "text" => MarkdownStrategy::Text, + _ => MarkdownStrategy::Disabled, + } + } +} + +#[napi] +pub struct MDString { + mds: odict::MDString, +} + +#[napi] +impl MDString { + #[napi(constructor)] + pub fn new(value: String) -> Result { + Ok(Self { + mds: odict::MDString::from(value.as_str()), + }) + } + + #[napi(getter)] + pub fn value(&self) -> String { + self.mds.value().to_string() + } + + #[napi] + pub fn parse(&self, strategy: MarkdownStrategy) -> String { + let s: odict::MarkdownStrategy = strategy.into(); + self.mds.parse(s) + } +} + +impl From for MDString { + fn from(mds: odict::MDString) -> Self { + Self { mds } + } +} diff --git a/bindings/node/src/types/mod.rs b/bindings/node/src/types/mod.rs new file mode 100644 index 00000000..e2032eb9 --- /dev/null +++ b/bindings/node/src/types/mod.rs @@ -0,0 +1,22 @@ +mod definition; +mod dictionary; +mod entry; +mod etymology; +mod example; +mod group; +mod index; +mod lookup; +mod mdstring; +mod note; +mod search; +mod sense; +mod split; + +pub use dictionary::*; +pub use entry::*; +pub use example::*; +pub use index::*; +pub use lookup::*; +pub use mdstring::*; +pub use search::*; +pub use split::*; diff --git a/bindings/node/src/types/note.rs b/bindings/node/src/types/note.rs new file mode 100644 index 00000000..5f577d93 --- /dev/null +++ b/bindings/node/src/types/note.rs @@ -0,0 +1,29 @@ +use napi::bindgen_prelude::*; + +use super::{mdstring::MDString, Example}; + +#[napi(object)] +pub struct Note { + pub id: Option, + pub value: ClassInstance, + pub examples: Vec, +} + +impl Note { + pub fn from(env: napi::Env, note: odict::Note) -> Result { + let odict::Note { + id, + value, + examples, + } = note; + + Ok(Self { + id, + value: MDString::from(value).into_instance(env)?, + examples: examples + .into_iter() + .map(|e| Example::from(env, e)) + .collect::, _>>()?, + }) + } +} diff --git a/bindings/node/src/types/search.rs b/bindings/node/src/types/search.rs new file mode 100644 index 00000000..b764e93c --- /dev/null +++ b/bindings/node/src/types/search.rs @@ -0,0 +1,45 @@ +use merge::Merge; + +#[napi(object)] +#[derive(PartialEq, Merge, Clone, Eq)] +pub struct SearchOptions { + pub directory: Option, + pub threshold: Option, + pub autoindex: Option, + pub limit: Option, +} + +impl Default for SearchOptions { + fn default() -> Self { + SearchOptions { + threshold: None, + directory: None, + autoindex: None, + limit: None, + } + } +} + +impl From for odict::search::SearchOptions { + fn from(opts: SearchOptions) -> Self { + let mut s = odict::search::SearchOptions::default(); + + if let Some(threshold) = opts.threshold { + s = s.threshold(threshold); + } + + if let Some(directory) = opts.directory { + s = s.dir(&directory); + } + + if let Some(limit) = opts.limit { + s = s.limit(limit.try_into().unwrap()); + } + + if let Some(autoindex) = opts.autoindex { + s = s.autoindex(autoindex); + } + + s + } +} diff --git a/bindings/node/src/types/sense.rs b/bindings/node/src/types/sense.rs new file mode 100644 index 00000000..940c2712 --- /dev/null +++ b/bindings/node/src/types/sense.rs @@ -0,0 +1,28 @@ +use napi::bindgen_prelude::*; + +use super::{definition::Definition, group::Group}; + +#[napi(object)] +pub struct Sense { + pub pos: String, + pub definitions: Vec>, +} + +impl Sense { + pub fn from(env: napi::Env, sense: odict::Sense) -> Result { + let odict::Sense { pos, definitions } = sense; + + Ok(Self { + pos: pos.to_string(), + definitions: definitions + .into_iter() + .map(|d| -> Result> { + match d { + odict::DefinitionType::Definition(d) => Ok(Either::A(Definition::from(env, d)?)), + odict::DefinitionType::Group(g) => Ok(Either::B(Group::from(env, g)?)), + } + }) + .collect::>, _>>()?, + }) + } +} diff --git a/bindings/node/src/types/split.rs b/bindings/node/src/types/split.rs new file mode 100644 index 00000000..4d182548 --- /dev/null +++ b/bindings/node/src/types/split.rs @@ -0,0 +1,25 @@ +use merge::Merge; + +#[napi(object)] +#[derive(PartialEq, Merge, Clone, Eq)] +pub struct SplitOptions { + pub threshold: Option, +} + +impl Default for SplitOptions { + fn default() -> Self { + SplitOptions { threshold: None } + } +} + +impl From for odict::split::SplitOptions { + fn from(opts: SplitOptions) -> Self { + let mut s = odict::split::SplitOptions::default(); + + if let Some(threshold) = opts.threshold { + s = s.threshold(threshold.try_into().unwrap()); + } + + s + } +} diff --git a/bindings/node/src/utils.rs b/bindings/node/src/utils.rs new file mode 100644 index 00000000..2604c45c --- /dev/null +++ b/bindings/node/src/utils.rs @@ -0,0 +1,26 @@ +use merge::Merge; +use napi::Either; + +use crate::types::{DictionaryOptions, LookupQuery}; + +pub fn cast_error(e: Box) -> napi::Error { + napi::Error::new(napi::Status::GenericFailure, format!("{}", e)) +} + +pub fn resolve_options(options: &Option) -> DictionaryOptions { + match options { + Some(opts) => { + let mut out = opts.clone(); + out.merge(DictionaryOptions::default()); + return out; + } + None => DictionaryOptions::default(), + } +} + +pub fn to_lookup_query(query: Either) -> odict::lookup::LookupQuery { + match query { + Either::A(wwf) => wwf.into(), + Either::B(s) => s.into(), + } +} diff --git a/bindings/node/tasks.toml b/bindings/node/tasks.toml new file mode 100644 index 00000000..3bc17f38 --- /dev/null +++ b/bindings/node/tasks.toml @@ -0,0 +1,16 @@ +["build:node"] +run = "pnpm --filter=\"@odict/node\" build" + +["publish:node"] +run = "pnpm --filter=\"@odict/node\" npm publish" + +["test:node"] +depends = ["build:node"] +run = "pnpm --filter=\"@odict/node\" test -- " + +["ci:node"] +run = 'act napi --container-architecture linux/amd64 --bind --job {{arg(name="job_id")}}' +hide = true + +["clean:node"] +run = "rm -f **/*.node" diff --git a/bindings/node/tests/__snapshots__/dictionary.spec.ts.snap b/bindings/node/tests/__snapshots__/dictionary.spec.ts.snap new file mode 100644 index 00000000..93f6c54a --- /dev/null +++ b/bindings/node/tests/__snapshots__/dictionary.spec.ts.snap @@ -0,0 +1,265 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Dictionary > can index and search a dictionary 1`] = ` +[ + { + "etymologies": [ + { + "description": "Latin root", + "senses": { + "n": { + "definitions": [ + { + "examples": [ + { + "value": "The dog runs after the cat.", + }, + { + "value": "The horse ran away.", + }, + ], + "notes": [], + "value": "(vertebrates) To move swiftly", + }, + { + "examples": [], + "notes": [], + "value": "Act or instance of hurrying (to or from a place) (not necessarily by foot); dash or errand, trip.", + }, + { + "examples": [], + "notes": [], + "value": "A pleasure trip.", + }, + { + "examples": [], + "notes": [], + "value": "Flight, instance or period of fleeing.", + }, + { + "examples": [], + "notes": [], + "value": "Migration (of fish).", + }, + { + "examples": [], + "notes": [], + "value": "A group of fish that migrate, or ascend a river for the purpose of spawning.", + }, + ], + "pos": "n", + }, + "v": { + "definitions": [ + { + "definitions": [ + { + "examples": [ + { + "value": "The dog runs after the cat.", + }, + { + "value": "The horse ran away.", + }, + ], + "notes": [], + "value": "(vertebrates) To move swiftly (figuratively)", + }, + { + "examples": [], + "notes": [], + "value": "(fluids) To flow.", + }, + { + "examples": [], + "notes": [], + "value": "(nautical, of a vessel) To sail before the wind, in distinction from reaching or sailing close-hauled.", + }, + { + "examples": [], + "notes": [], + "value": "(social) To carry out an activity.", + }, + { + "examples": [], + "notes": [], + "value": "To extend or persist, statically or dynamically, through space or time.", + }, + { + "examples": [], + "notes": [], + "value": "(transitive) To execute or carry out a plan, procedure or program.", + }, + ], + "description": "A number of verb senses", + }, + ], + "pos": "v", + }, + }, + }, + ], + "term": "run", + }, +] +`; + +exports[`Dictionary > can split terms properly 1`] = ` +[ + { + "etymologies": [ + { + "description": "Latin root", + "senses": { + "n": { + "definitions": [ + { + "examples": [ + { + "value": "There goes a cat!", + }, + ], + "notes": [ + { + "examples": [ + { + "value": "Some example", + }, + ], + "value": "Some definition note", + }, + ], + "value": "a cat", + }, + ], + "pos": "n", + }, + }, + }, + ], + "term": "cat", + }, + { + "etymologies": [ + { + "description": "Latin root", + "pronunciation": "dooooog", + "senses": { + "un": { + "definitions": [ + { + "examples": [], + "notes": [], + "value": "a dog", + }, + ], + "pos": "un", + }, + }, + }, + ], + "term": "dog", + }, +] +`; + +exports[`Dictionary > lookup > can split terms 1`] = ` +[ + [ + { + "etymologies": [ + { + "description": "Latin root", + "senses": { + "n": { + "definitions": [ + { + "examples": [ + { + "value": "There goes a cat!", + }, + ], + "notes": [ + { + "examples": [ + { + "value": "Some example", + }, + ], + "value": "Some definition note", + }, + ], + "value": "a cat", + }, + ], + "pos": "n", + }, + }, + }, + ], + "term": "cat", + }, + { + "etymologies": [ + { + "description": "Latin root", + "pronunciation": "dooooog", + "senses": { + "un": { + "definitions": [ + { + "examples": [], + "notes": [], + "value": "a dog", + }, + ], + "pos": "un", + }, + }, + }, + ], + "term": "dog", + }, + ], +] +`; + +exports[`Dictionary > lookup > looks up terms properly 1`] = ` +[ + [ + { + "etymologies": [ + { + "description": "Latin root", + "senses": { + "n": { + "definitions": [ + { + "examples": [ + { + "value": "There goes a cat!", + }, + ], + "notes": [ + { + "examples": [ + { + "value": "Some example", + }, + ], + "value": "Some definition note", + }, + ], + "value": "a cat", + }, + ], + "pos": "n", + }, + }, + }, + ], + "term": "cat", + }, + ], +] +`; diff --git a/bindings/node/tests/dictionary.spec.ts b/bindings/node/tests/dictionary.spec.ts new file mode 100644 index 00000000..2cf549d6 --- /dev/null +++ b/bindings/node/tests/dictionary.spec.ts @@ -0,0 +1,109 @@ +import { beforeAll, describe, expect, it } from "vitest"; + +import { existsSync } from "node:fs"; +import { rm, stat } from "node:fs/promises"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { Dictionary } from "../index.js"; + +describe("Dictionary", () => { + expect.addSnapshotSerializer({ + test: (t) => typeof t.value === "string", + serialize: (t) => `"${t.value}"`, + }); + + let dict1Path: string; + let dict2Path: string; + let dict1: Dictionary; + let dict2: Dictionary; + + beforeAll(async () => { + dict1Path = join( + fileURLToPath(new URL(import.meta.url)), + "../../../../examples/example1.xml" + ); + + dict1 = await Dictionary.compile(dict1Path); + + dict2Path = join( + fileURLToPath(new URL(import.meta.url)), + "../../../../examples/example2.xml" + ); + + dict2 = await Dictionary.compile(dict2Path); + + const stat1 = await stat(dict1.path); + const stat2 = await stat(dict2.path); + + expect(stat1.isFile).toBeTruthy(); + expect(stat2.isFile).toBeTruthy(); + }); + + it("returns the path correctly", () => { + // Needs toContain instead of toBe seeing Windows paths start with \\?\ + expect(dict1.path).toContain(dict1Path.replace(".xml", ".odict")); + expect(dict2.path).toContain(dict2Path.replace(".xml", ".odict")); + }); + + describe("lookup", () => { + it("looks up terms properly", async () => { + const result = await dict1.lookup({ term: "cat", fallback: "cat" }); + expect(result).toMatchSnapshot(); + }); + + it("doesn't split unless specified", async () => { + const result = await dict1.lookup("catdog"); + expect(result[0].length).toBe(0); + }); + + it("can split terms", async () => { + const result = await dict1.lookup("catdog", { split: 3 }); + expect(result).toMatchSnapshot(); + }); + }); + + it("can return the lexicon", async () => { + const result = await dict1.lexicon(); + expect(result).toStrictEqual(["cat", "dog", "poo", "ran", "run"]); + }); + + it("can write raw XML", async () => { + await Dictionary.write( + '" )', + "test.odict" + ); + + expect(existsSync("test.odict")).toBeTruthy(); + + const dict = new Dictionary("test.odict"); + + expect(dict.lookup("hello").length).toBe(1); + + await rm("test.odict"); + }); + + it("can split terms properly", async () => { + const result = await dict1.split("catdog", { threshold: 2 }); + expect(result).toMatchSnapshot(); + }); + + it("can index and search a dictionary", async () => { + await dict1.index(); + + const results = await dict1.search("run"); + + expect(results).toMatchSnapshot(); + }); + + it("throws errors inside JavaScript", async () => { + try { + const dict = new Dictionary("fake-alias"); + await dict.lookup("dog"); + } catch (e) { + expect((e as Error).message).toContain( + "(os error 2)" + ); + } + }); +}); diff --git a/js/tsconfig.json b/bindings/node/tsconfig.json similarity index 94% rename from js/tsconfig.json rename to bindings/node/tsconfig.json index 4d8ec534..14cf4e83 100644 --- a/js/tsconfig.json +++ b/bindings/node/tsconfig.json @@ -15,5 +15,5 @@ "declaration": true, "verbatimModuleSyntax": true }, - "include": ["src"] + "include": ["tests"] } diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 00000000..6a6679a3 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "cli" +version = "2.0.0-beta.0" +edition = "2021" +description = "A lightning-fast dictionary file format and toolchain" +homepage = "https://odict.org" +repository = "https://github.com/TheOpenDictionary/odict" + +[[bin]] +name = "odict" +path = "src/main.rs" + +[dependencies] +odict = { path = "../lib", features = [ + "config", + "charabia", + "sql", + "search", + "json", +] } +clap = { version = "4.5.4", features = ["derive", "cargo"] } +console = "0.15.8" +indicatif = "0.17.8" +pulldown-cmark = "0.12.0" +actix-web = "4.5.1" +serde = { version = "1.0.200", features = ["derive"] } +env_logger = "0.11.3" +derive_more = "0.99.17" +num-format = "0.4.4" +humansize = "2.1.3" diff --git a/cli/alias.go b/cli/alias.go deleted file mode 100644 index 603a63d5..00000000 --- a/cli/alias.go +++ /dev/null @@ -1,105 +0,0 @@ -package cli - -import ( - "fmt" - "os" - "text/tabwriter" - - "github.com/TheOpenDictionary/odict/lib/config" - "github.com/TheOpenDictionary/odict/lib/core" - _search "github.com/TheOpenDictionary/odict/lib/search" - "github.com/fatih/color" - cli "github.com/urfave/cli/v2" -) - -var bold = color.New(color.Bold) - -var faint = color.New(color.Faint) - -func listDictionaries(c *cli.Context) error { - dictionaries, err := config.ListDictionaries() - - if err != nil { - return err - } - - fmt.Println() - - w := tabwriter.NewWriter(os.Stdout, 4, 4, 4, ' ', 0) - - for _, dict := range dictionaries { - fmt.Fprintf(w, "%s\t%s\t%s\n", bold.Sprint(dict.Name), faint.Sprint("→"), faint.Sprint(dict.Path)) - } - - w.Flush() - - return nil -} - -func addDictionary(c *cli.Context) error { - name := c.Args().First() - path := c.Args().Get(1) - noIndex := c.Bool("no-index") - - if len(name) == 0 || len(path) == 0 { - cli.ShowSubcommandHelpAndExit(c, 1) - } - - dict, err := core.ReadDictionary(path) - - if err != nil { - return err - } - - if !noIndex { - _search.Index(_search.IndexRequest{Dictionary: dict}) - } - - if err := config.AddDictionaryAlias(name, path); err != nil { - return err - } - - fmt.Printf("Aliased \"%s\" to the dictionary at %s.\n", name, path) - - return nil -} - -func setDictionary(c *cli.Context) error { - name := c.Args().First() - path := c.Args().Get(1) - noIndex := c.Bool("no-index") - - if len(name) == 0 || len(path) == 0 { - cli.ShowSubcommandHelpAndExit(c, 1) - } - - dict, err := core.ReadDictionary(path) - - if err != nil { - return err - } - - if !noIndex { - _search.Index(_search.IndexRequest{Dictionary: dict}) - } - - config.SetDictionaryAlias(name, path) - - fmt.Printf("Aliased \"%s\" to the dictionary at %s.\n", name, path) - - return nil -} - -func removeDictionary(c *cli.Context) error { - name := c.Args().First() - - if len(name) == 0 { - cli.ShowSubcommandHelpAndExit(c, 1) - } - - if err := config.RemoveDictionaryAlias(name); err != nil { - return err - } - - return nil -} diff --git a/cli/app.go b/cli/app.go deleted file mode 100644 index 561c8f81..00000000 --- a/cli/app.go +++ /dev/null @@ -1,242 +0,0 @@ -package cli - -import ( - "fmt" - "strings" - - "github.com/TheOpenDictionary/odict/lib/types" - cli "github.com/urfave/cli/v2" -) - -var version string - -const ( - managing string = "Writing & Managing" - searching string = "Searching" - utilities string = "Utilities" -) - -var markdownFlag *cli.StringFlag = &cli.StringFlag{ - Name: "markdown", - Usage: "strategy for rendering Markdown strings", - Value: "html", - Action: func(c *cli.Context, value string) error { - if value != "text" && value != "html" && value != "disable" { - return fmt.Errorf("Invalid markdown strategy: %s. Must be one of: text, html, disable", value) - } - - types.SetMarkdownProcessingStrategy(types.MarkdownStrategy(value)) - - return nil - }, -} - -var App = &cli.App{ - Name: "odict", - Version: version, - HideHelp: true, - Usage: "lighting-fast open-source dictionary compiler", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "quiet", - Usage: "Silence any non-important output", - }, - }, - Commands: []*cli.Command{ - { - Name: "compile", - Aliases: []string{"c"}, - Category: managing, - Usage: "compiles a dictionary from ODXML", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "output", - Aliases: []string{"o"}, - Usage: "Path to generate dictionary", - }, - }, - Action: compile, - }, - { - Name: "service", - Action: service, - Hidden: true, - }, - { - Name: "index", - Category: searching, - Aliases: []string{"i"}, - Usage: "index a compiled dictionary", - Action: index, - }, - { - Name: "serve", - Aliases: []string{"w"}, - Category: utilities, - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "port", - Aliases: []string{"p"}, - Value: 5005, - Usage: "Port to listen on", - }, - }, - Usage: "start a local web server to serve one or several dictionaries", - Action: serve, - }, - { - Name: "lexicon", - Aliases: []string{"e"}, - Category: utilities, - Usage: "lists all words defined in a dictionary", - Action: lexicon, - }, - { - Name: "alias", - Aliases: []string{"a"}, - Category: managing, - Usage: "manage dictionary aliases", - Subcommands: []*cli.Command{ - { - Name: "add", - Usage: "add a new dictionary alias for quick access", - Description: "will fail if an alias with the same name already exists.", - Action: addDictionary, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "no-index", - Usage: "Don't index the dictionary when an alias is created", - }, - }, - ArgsUsage: "[name] [dictionary path]", - }, - { - Name: "remove", - Usage: "remove an aliased dictionary", - Action: removeDictionary, - ArgsUsage: "[name]", - }, - { - Name: "set", - Usage: "adds or updates an aliased dictionary", - Description: "differs from `add` in that it will overwrite an existing alias if it exists", - Action: setDictionary, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "no-index", - Usage: "Don't index the dictionary when an alias is created", - }, - }, - ArgsUsage: "[name] [dictionary path]", - }, - { - Name: "list", - Usage: "list dictionary aliases", - Action: listDictionaries, - }, - }, - }, - { - Name: "lookup", - Aliases: []string{"l"}, - Category: searching, - Usage: "looks up an entry in a compiled dictionary without indexing", - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "split", - Aliases: []string{"s"}, - Usage: "If a definition cannot be found, attempt to split the query into words of at least length S and look up each word separately. Can be relatively slow.", - Value: 0, - }, - markdownFlag, - &cli.StringFlag{ - Name: "format", - Aliases: []string{"f"}, - Usage: "Output format of the entries.", - Value: printFormat, - }, - &cli.BoolFlag{ - Name: "follow", - Aliases: []string{"F"}, - Usage: "Follows all \"see also\" attributes (\"see\") until it finds a root term.", - Value: false, - }, - }, - Action: lookup, - }, - { - Name: "search", - Aliases: []string{"s"}, - Category: searching, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "index", - Aliases: []string{"i"}, - Usage: "Forcibly creates a new index if one already exists", - Value: false, - }, - &cli.BoolFlag{ - Name: "exact", - Aliases: []string{"e"}, - Usage: "Match words exactly (works the same as `lookup`)", - Value: false, - }, - }, - Usage: "search a compiled dictionary using full-text search", - Action: search, - }, - { - Name: "split", - Aliases: []string{"x"}, - Category: searching, - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "threshold", - Aliases: []string{"t"}, - Usage: "Minimum length of each token", - Value: 2, - }, - }, - Usage: "split a query into its definable terms", - Action: split, - }, - { - Name: "dump", - Aliases: []string{"d"}, - Category: managing, - Usage: "dumps a previously compiled dictionary", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "format", - Aliases: []string{"f"}, - Usage: "output format of the dump (ODXML or SQL)", - Required: true, - }, - &cli.BoolFlag{ - Name: "no-schema", - Aliases: []string{"ns"}, - Usage: "skips generating schema scaffolding commands when dumping SQL files", - Required: false, - }, - markdownFlag, - }, - Before: cli.BeforeFunc(func(c *cli.Context) error { - s := c.String("format") - if s == XML || s == Postgres || s == SQLite || s == MySQL || s == SQLServer { - return nil - } else { - validFormats := strings.Join([]string{XML, Postgres, SQLite, MySQL, SQLServer}, " ") - return fmt.Errorf("invalid format: %s, valid formats are: %s", s, validFormats) - } - }), - Action: dump, - }, - { - Name: "merge", - Category: managing, - Aliases: []string{"m"}, - Usage: "merge two dictionaries", - Action: merge, - }, - }, -} diff --git a/cli/compile.go b/cli/compile.go deleted file mode 100644 index 7a348e30..00000000 --- a/cli/compile.go +++ /dev/null @@ -1,41 +0,0 @@ -package cli - -import ( - "errors" - "fmt" - "path/filepath" - "strings" - - "github.com/TheOpenDictionary/odict/lib/core" - cli "github.com/urfave/cli/v2" -) - -func compile(c *cli.Context) error { - inputFile := c.Args().Get(0) - outputFile := c.String("output") - quiet := c.Bool("quiet") - - if len(inputFile) == 0 { - return errors.New("input XML file required") - } - - if len(outputFile) == 0 { - base := filepath.Base(inputFile) - name := strings.TrimSuffix(base, filepath.Ext(base)) - outputFile = fmt.Sprintf("%s/%s.odict", filepath.Dir(inputFile), name) - } - - return t(c, func() error { - bytes, err := core.CompileDictionary(inputFile, outputFile) - - if err != nil { - return err - } - - if !quiet { - fmt.Printf("Wrote %d bytes to path: %s\n", bytes, outputFile) - } - - return nil - }) -} diff --git a/cli/dump.go b/cli/dump.go deleted file mode 100644 index ae6d484a..00000000 --- a/cli/dump.go +++ /dev/null @@ -1,70 +0,0 @@ -package cli - -import ( - "bufio" - "errors" - "os" - - "github.com/TheOpenDictionary/odict/lib/core" - dump_ "github.com/TheOpenDictionary/odict/lib/dump" - cli "github.com/urfave/cli/v2" -) - -type DumpFormat = string - -const ( - XML DumpFormat = "xml" - Postgres DumpFormat = "postgres" - SQLite DumpFormat = "sqlite" - MySQL DumpFormat = "mysql" - SQLServer DumpFormat = "sqlserver" -) - -func dump(c *cli.Context) error { - inputFile := c.Args().Get(0) - outputFile := c.Args().Get(1) - format := c.String("format") - includeSchema := !c.Bool("no-schema") - - if len(inputFile) == 0 || len(outputFile) == 0 { - return errors.New("usage: odict dump [input file] [output file]") - } - - return t(c, func() error { - dict, readErr := core.ReadDictionary(inputFile) - - if readErr != nil { - return readErr - } - - // All SQL formats and XML - var dumped string - var err error - - if format == XML { - dumped, err = dump_.AsXML(dict) - } else { - dumped, err = dump_.AsSQL(dict, format, includeSchema) - } - - if err != nil { - return err - } - - file, writeErr := os.Create(outputFile) - - if writeErr != nil { - return writeErr - } - - defer file.Close() - - writer := bufio.NewWriter(file) - - writer.Write([]byte(dumped)) - - writer.Flush() - - return nil - }) -} diff --git a/cli/enums_generated.go b/cli/enums_generated.go deleted file mode 100644 index 5ec82122..00000000 --- a/cli/enums_generated.go +++ /dev/null @@ -1,367 +0,0 @@ -// Code generated by the FlatBuffers compiler. DO NOT EDIT. - -package cli - -import ( - "strconv" -) - -type POS int8 - -const ( - POSun POS = 0 - POSadj POS = 1 - POSadv POS = 2 - POSart POS = 3 - POSconj POS = 4 - POSintj POS = 5 - POSn POS = 6 - POSpart POS = 7 - POSpref POS = 8 - POSprep POS = 9 - POSpostp POS = 10 - POSpron POS = 11 - POSsuff POS = 12 - POSv POS = 13 - POSabv POS = 14 - POSadf POS = 15 - POSaff POS = 16 - POSaux_adj POS = 17 - POSaux_v POS = 18 - POSaux POS = 19 - POSchr POS = 20 - POSconj_c POS = 21 - POSconj_s POS = 22 - POScop POS = 23 - POScf POS = 24 - POSctr POS = 25 - POSdet POS = 26 - POSexpr POS = 27 - POSinf POS = 28 - POSintf POS = 29 - POSname POS = 30 - POSnum POS = 31 - POSphr_adv POS = 32 - POSphr_adj POS = 33 - POSphr_prep POS = 34 - POSphr POS = 35 - POSpropn POS = 36 - POSprov POS = 37 - POSpunc POS = 38 - POSsym POS = 39 - POSvi POS = 40 - POSvt POS = 41 - POSadj_f POS = 42 - POSadj_ix POS = 43 - POSadj_kari POS = 44 - POSadj_ku POS = 45 - POSadj_na POS = 46 - POSadj_nari POS = 47 - POSadj_no POS = 48 - POSadj_pn POS = 49 - POSadj_shiku POS = 50 - POSadj_t POS = 51 - POSadv_to POS = 52 - POSn_adv POS = 53 - POSn_pref POS = 54 - POSn_suf POS = 55 - POSn_t POS = 56 - POSv_unspec POS = 57 - POSv1_s POS = 58 - POSv1 POS = 59 - POSv2a_s POS = 60 - POSv2b_k POS = 61 - POSv2b_s POS = 62 - POSv2d_k POS = 63 - POSv2d_s POS = 64 - POSv2g_k POS = 65 - POSv2g_s POS = 66 - POSv2h_k POS = 67 - POSv2h_s POS = 68 - POSv2k_k POS = 69 - POSv2k_s POS = 70 - POSv2m_k POS = 71 - POSv2m_s POS = 72 - POSv2n_s POS = 73 - POSv2r_k POS = 74 - POSv2r_s POS = 75 - POSv2s_s POS = 76 - POSv2t_k POS = 77 - POSv2t_s POS = 78 - POSv2w_s POS = 79 - POSv2y_k POS = 80 - POSv2y_s POS = 81 - POSv2z_s POS = 82 - POSv4b POS = 83 - POSv4g POS = 84 - POSv4h POS = 85 - POSv4k POS = 86 - POSv4m POS = 87 - POSv4n POS = 88 - POSv4r POS = 89 - POSv4s POS = 90 - POSv4t POS = 91 - POSv5aru POS = 92 - POSv5b POS = 93 - POSv5g POS = 94 - POSv5k_s POS = 95 - POSv5k POS = 96 - POSv5m POS = 97 - POSv5n POS = 98 - POSv5r_i POS = 99 - POSv5r POS = 100 - POSv5s POS = 101 - POSv5t POS = 102 - POSv5u_s POS = 103 - POSv5u POS = 104 - POSv5uru POS = 105 - POSvk POS = 106 - POSvn POS = 107 - POSvr POS = 108 - POSvs_c POS = 109 - POSvs_i POS = 110 - POSvs_s POS = 111 - POSvs POS = 112 - POSvz POS = 113 -) - -var EnumNamesPOS = map[POS]string{ - POSun: "un", - POSadj: "adj", - POSadv: "adv", - POSart: "art", - POSconj: "conj", - POSintj: "intj", - POSn: "n", - POSpart: "part", - POSpref: "pref", - POSprep: "prep", - POSpostp: "postp", - POSpron: "pron", - POSsuff: "suff", - POSv: "v", - POSabv: "abv", - POSadf: "adf", - POSaff: "aff", - POSaux_adj: "aux_adj", - POSaux_v: "aux_v", - POSaux: "aux", - POSchr: "chr", - POSconj_c: "conj_c", - POSconj_s: "conj_s", - POScop: "cop", - POScf: "cf", - POSctr: "ctr", - POSdet: "det", - POSexpr: "expr", - POSinf: "inf", - POSintf: "intf", - POSname: "name", - POSnum: "num", - POSphr_adv: "phr_adv", - POSphr_adj: "phr_adj", - POSphr_prep: "phr_prep", - POSphr: "phr", - POSpropn: "propn", - POSprov: "prov", - POSpunc: "punc", - POSsym: "sym", - POSvi: "vi", - POSvt: "vt", - POSadj_f: "adj_f", - POSadj_ix: "adj_ix", - POSadj_kari: "adj_kari", - POSadj_ku: "adj_ku", - POSadj_na: "adj_na", - POSadj_nari: "adj_nari", - POSadj_no: "adj_no", - POSadj_pn: "adj_pn", - POSadj_shiku: "adj_shiku", - POSadj_t: "adj_t", - POSadv_to: "adv_to", - POSn_adv: "n_adv", - POSn_pref: "n_pref", - POSn_suf: "n_suf", - POSn_t: "n_t", - POSv_unspec: "v_unspec", - POSv1_s: "v1_s", - POSv1: "v1", - POSv2a_s: "v2a_s", - POSv2b_k: "v2b_k", - POSv2b_s: "v2b_s", - POSv2d_k: "v2d_k", - POSv2d_s: "v2d_s", - POSv2g_k: "v2g_k", - POSv2g_s: "v2g_s", - POSv2h_k: "v2h_k", - POSv2h_s: "v2h_s", - POSv2k_k: "v2k_k", - POSv2k_s: "v2k_s", - POSv2m_k: "v2m_k", - POSv2m_s: "v2m_s", - POSv2n_s: "v2n_s", - POSv2r_k: "v2r_k", - POSv2r_s: "v2r_s", - POSv2s_s: "v2s_s", - POSv2t_k: "v2t_k", - POSv2t_s: "v2t_s", - POSv2w_s: "v2w_s", - POSv2y_k: "v2y_k", - POSv2y_s: "v2y_s", - POSv2z_s: "v2z_s", - POSv4b: "v4b", - POSv4g: "v4g", - POSv4h: "v4h", - POSv4k: "v4k", - POSv4m: "v4m", - POSv4n: "v4n", - POSv4r: "v4r", - POSv4s: "v4s", - POSv4t: "v4t", - POSv5aru: "v5aru", - POSv5b: "v5b", - POSv5g: "v5g", - POSv5k_s: "v5k_s", - POSv5k: "v5k", - POSv5m: "v5m", - POSv5n: "v5n", - POSv5r_i: "v5r_i", - POSv5r: "v5r", - POSv5s: "v5s", - POSv5t: "v5t", - POSv5u_s: "v5u_s", - POSv5u: "v5u", - POSv5uru: "v5uru", - POSvk: "vk", - POSvn: "vn", - POSvr: "vr", - POSvs_c: "vs_c", - POSvs_i: "vs_i", - POSvs_s: "vs_s", - POSvs: "vs", - POSvz: "vz", -} - -var EnumValuesPOS = map[string]POS{ - "un": POSun, - "adj": POSadj, - "adv": POSadv, - "art": POSart, - "conj": POSconj, - "intj": POSintj, - "n": POSn, - "part": POSpart, - "pref": POSpref, - "prep": POSprep, - "postp": POSpostp, - "pron": POSpron, - "suff": POSsuff, - "v": POSv, - "abv": POSabv, - "adf": POSadf, - "aff": POSaff, - "aux_adj": POSaux_adj, - "aux_v": POSaux_v, - "aux": POSaux, - "chr": POSchr, - "conj_c": POSconj_c, - "conj_s": POSconj_s, - "cop": POScop, - "cf": POScf, - "ctr": POSctr, - "det": POSdet, - "expr": POSexpr, - "inf": POSinf, - "intf": POSintf, - "name": POSname, - "num": POSnum, - "phr_adv": POSphr_adv, - "phr_adj": POSphr_adj, - "phr_prep": POSphr_prep, - "phr": POSphr, - "propn": POSpropn, - "prov": POSprov, - "punc": POSpunc, - "sym": POSsym, - "vi": POSvi, - "vt": POSvt, - "adj_f": POSadj_f, - "adj_ix": POSadj_ix, - "adj_kari": POSadj_kari, - "adj_ku": POSadj_ku, - "adj_na": POSadj_na, - "adj_nari": POSadj_nari, - "adj_no": POSadj_no, - "adj_pn": POSadj_pn, - "adj_shiku": POSadj_shiku, - "adj_t": POSadj_t, - "adv_to": POSadv_to, - "n_adv": POSn_adv, - "n_pref": POSn_pref, - "n_suf": POSn_suf, - "n_t": POSn_t, - "v_unspec": POSv_unspec, - "v1_s": POSv1_s, - "v1": POSv1, - "v2a_s": POSv2a_s, - "v2b_k": POSv2b_k, - "v2b_s": POSv2b_s, - "v2d_k": POSv2d_k, - "v2d_s": POSv2d_s, - "v2g_k": POSv2g_k, - "v2g_s": POSv2g_s, - "v2h_k": POSv2h_k, - "v2h_s": POSv2h_s, - "v2k_k": POSv2k_k, - "v2k_s": POSv2k_s, - "v2m_k": POSv2m_k, - "v2m_s": POSv2m_s, - "v2n_s": POSv2n_s, - "v2r_k": POSv2r_k, - "v2r_s": POSv2r_s, - "v2s_s": POSv2s_s, - "v2t_k": POSv2t_k, - "v2t_s": POSv2t_s, - "v2w_s": POSv2w_s, - "v2y_k": POSv2y_k, - "v2y_s": POSv2y_s, - "v2z_s": POSv2z_s, - "v4b": POSv4b, - "v4g": POSv4g, - "v4h": POSv4h, - "v4k": POSv4k, - "v4m": POSv4m, - "v4n": POSv4n, - "v4r": POSv4r, - "v4s": POSv4s, - "v4t": POSv4t, - "v5aru": POSv5aru, - "v5b": POSv5b, - "v5g": POSv5g, - "v5k_s": POSv5k_s, - "v5k": POSv5k, - "v5m": POSv5m, - "v5n": POSv5n, - "v5r_i": POSv5r_i, - "v5r": POSv5r, - "v5s": POSv5s, - "v5t": POSv5t, - "v5u_s": POSv5u_s, - "v5u": POSv5u, - "v5uru": POSv5uru, - "vk": POSvk, - "vn": POSvn, - "vr": POSvr, - "vs_c": POSvs_c, - "vs_i": POSvs_i, - "vs_s": POSvs_s, - "vs": POSvs, - "vz": POSvz, -} - -func (v POS) String() string { - if s, ok := EnumNamesPOS[v]; ok { - return s - } - return "POS(" + strconv.FormatInt(int64(v), 10) + ")" -} diff --git a/cli/go.mod b/cli/go.mod deleted file mode 100644 index a32d7b51..00000000 --- a/cli/go.mod +++ /dev/null @@ -1,67 +0,0 @@ -module github.com/TheOpenDictionary/odict/cli - -go 1.21.0 - -toolchain go1.21.6 - -require ( - github.com/TheOpenDictionary/odict/lib/config v0.0.0-20231024210539-d4e83ae7bfdc - github.com/TheOpenDictionary/odict/lib/core v0.0.0-20231024210539-d4e83ae7bfdc - github.com/TheOpenDictionary/odict/lib/dump v0.0.0-20231024210539-d4e83ae7bfdc - github.com/TheOpenDictionary/odict/lib/search v0.0.0-20231024210539-d4e83ae7bfdc - github.com/TheOpenDictionary/odict/lib/server v0.0.0-20231024210539-d4e83ae7bfdc - github.com/TheOpenDictionary/odict/lib/types v0.0.0-20231024210539-d4e83ae7bfdc - github.com/TheOpenDictionary/odict/lib/utils v0.0.0-20231024210539-d4e83ae7bfdc - github.com/fatih/color v1.16.0 - github.com/google/flatbuffers v24.3.7+incompatible - github.com/google/uuid v1.6.0 - github.com/samber/lo v1.39.0 - github.com/urfave/cli/v2 v2.27.1 -) - -require ( - github.com/RoaringBitmap/roaring v1.2.3 // indirect - github.com/bits-and-blooms/bitset v1.2.0 // indirect - github.com/blevesearch/bleve/v2 v2.4.0 // indirect - github.com/blevesearch/bleve_index_api v1.1.6 // indirect - github.com/blevesearch/geo v0.1.20 // indirect - github.com/blevesearch/go-faiss v1.0.13 // indirect - github.com/blevesearch/go-porterstemmer v1.0.3 // indirect - github.com/blevesearch/gtreap v0.1.1 // indirect - github.com/blevesearch/mmap-go v1.0.4 // indirect - github.com/blevesearch/scorch_segment_api/v2 v2.2.9 // indirect - github.com/blevesearch/segment v0.9.1 // indirect - github.com/blevesearch/snowballstem v0.9.0 // indirect - github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect - github.com/blevesearch/vellum v1.0.10 // indirect - github.com/blevesearch/zapx/v11 v11.3.10 // indirect - github.com/blevesearch/zapx/v12 v12.3.10 // indirect - github.com/blevesearch/zapx/v13 v13.3.10 // indirect - github.com/blevesearch/zapx/v14 v14.3.10 // indirect - github.com/blevesearch/zapx/v15 v15.3.13 // indirect - github.com/blevesearch/zapx/v16 v16.0.12 // indirect - github.com/bokwoon95/sq v0.4.5 // indirect - github.com/bokwoon95/sqddl v0.4.11 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect - github.com/golang/protobuf v1.3.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect - github.com/mschoch/smat v0.2.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/schollz/progressbar/v3 v3.14.2 // indirect - github.com/stretchr/testify v1.9.0 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.etcd.io/bbolt v1.3.7 // indirect - golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect - golang.org/x/tools v0.9.1 // indirect -) diff --git a/cli/go.sum b/cli/go.sum deleted file mode 100644 index 45ef79fd..00000000 --- a/cli/go.sum +++ /dev/null @@ -1,127 +0,0 @@ -github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY= -github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= -github.com/TheOpenDictionary/odict/lib/config v0.0.0-20231024210539-d4e83ae7bfdc h1:7o2ZuoSkd46ahLR8kqByb0xI5BfoEDWLSZ72FcbW6QQ= -github.com/TheOpenDictionary/odict/lib/config v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:+aU3saFQkiASuB07qTVt49KAMEJVE5V9U0zV2USCwYo= -github.com/TheOpenDictionary/odict/lib/core v0.0.0-20231024210539-d4e83ae7bfdc h1:bYGYeJvDiIaPtO56Q6MedQo2BkMBHA+Y/LLl83h2JVw= -github.com/TheOpenDictionary/odict/lib/core v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:6r7Uve6zyCBEQ3gF1eM68MMaKE28TahjOEXoXgqtYak= -github.com/TheOpenDictionary/odict/lib/dump v0.0.0-20231024210539-d4e83ae7bfdc h1:a4/xnxa7SBTZjxLBkmFC/vyBjiiRDtmwH+ERKs+Rju4= -github.com/TheOpenDictionary/odict/lib/dump v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:n9iQP2j9K2UWqnr48FuF48n7y7WKJHidb9PH4MWVyTA= -github.com/TheOpenDictionary/odict/lib/search v0.0.0-20231024210539-d4e83ae7bfdc h1:pzEZaJvBl3T+DQ8x7RhmjqzQ4mOcu1azUzzV54Dmuls= -github.com/TheOpenDictionary/odict/lib/search v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:QQP23s5hPNJMgBhiD1SpHD1ZkuTJCxXOR7kNeR+QrT8= -github.com/TheOpenDictionary/odict/lib/server v0.0.0-20231024210539-d4e83ae7bfdc h1:UevlCBjF6SCc7T5C8GrsRzhnNHGiauC8C44LjA1keq0= -github.com/TheOpenDictionary/odict/lib/server v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:fnMKQbabDcNwRbn3H+oeRXABHhhVGfaHVgjOoUKw1Po= -github.com/TheOpenDictionary/odict/lib/types v0.0.0-20231024210539-d4e83ae7bfdc h1:8kWzsJD2IvoJM65K8sWxx4ufjCW7pytjUeQ1J+B6tnA= -github.com/TheOpenDictionary/odict/lib/types v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:EyG+XUeVlK9nKtKexShKWlVwN2qd6Z4KoYdENtQlyT4= -github.com/TheOpenDictionary/odict/lib/utils v0.0.0-20231024210539-d4e83ae7bfdc h1:oVwda5G0bJrj/NYI2GbDlOjbU1CqduXFjTSzSwwjNSk= -github.com/TheOpenDictionary/odict/lib/utils v0.0.0-20231024210539-d4e83ae7bfdc/go.mod h1:PtDJV1c5oYM4xo1ZTdgBg2HlFOEKjH5kYOXASKhZAPs= -github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= -github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/blevesearch/bleve/v2 v2.4.0 h1:2xyg+Wv60CFHYccXc+moGxbL+8QKT/dZK09AewHgKsg= -github.com/blevesearch/bleve_index_api v1.1.6 h1:orkqDFCBuNU2oHW9hN2YEJmet+TE9orml3FCGbl1cKk= -github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM= -github.com/blevesearch/go-faiss v1.0.13 h1:zfFs7ZYD0NqXVSY37j0JZjZT1BhE9AE4peJfcx/NB4A= -github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= -github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= -github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= -github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= -github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= -github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= -github.com/blevesearch/scorch_segment_api/v2 v2.2.9 h1:3nBaSBRFokjE4FtPW3eUDgcAu3KphBg1GP07zy/6Uyk= -github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= -github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= -github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= -github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= -github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= -github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= -github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI= -github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k= -github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk= -github.com/blevesearch/zapx/v11 v11.3.10/go.mod h1:0+gW+FaE48fNxoVtMY5ugtNHHof/PxCqh7CnhYdnMzQ= -github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s= -github.com/blevesearch/zapx/v12 v12.3.10/go.mod h1:0yeZg6JhaGxITlsS5co73aqPtM04+ycnI6D1v0mhbCs= -github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIqMGahDE8= -github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk= -github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU= -github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns= -github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ= -github.com/blevesearch/zapx/v15 v15.3.13/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg= -github.com/blevesearch/zapx/v16 v16.0.12 h1:Uccxvjmn+hQ6ywQP+wIiTpdq9LnAviGoryJOmGwAo/I= -github.com/bokwoon95/sq v0.4.5 h1:1uAaYFJs897zrAJWPedJG0FWuJP7KRKOKT1GnU4ne+w= -github.com/bokwoon95/sq v0.4.5/go.mod h1:E3X8ARaXQ77XGMvjS0sQrcA1F5BZvq4Ck/91dPsMKR4= -github.com/bokwoon95/sqddl v0.4.11 h1:GeHL0ykSoigpEUBWY8NKRVqSswD3Qu0dbfy/pS8Vo3k= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= -github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= -github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= -github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 h1:k4Tw0nt6lwro3Uin8eqoET7MDA4JnT8YgbCjc/g5E3k= -github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= -github.com/google/flatbuffers v24.3.7+incompatible h1:BxGUkIQnOciBu33bd5BdvqY8Qvo0O/GR4SPhh7x9Ed0= -github.com/google/flatbuffers v24.3.7+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede h1:YrgBGwxMRK0Vq0WSCWFaZUnTsrA/PZE/xs1QZh+/edg= -github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= -github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= -github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/schollz/progressbar/v3 v3.14.2 h1:EducH6uNLIWsr560zSV1KrTeUb/wZGAHqyMFIEa99ks= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= -github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cli/index.go b/cli/index.go deleted file mode 100644 index 84181af6..00000000 --- a/cli/index.go +++ /dev/null @@ -1,30 +0,0 @@ -package cli - -import ( - "errors" - - "github.com/TheOpenDictionary/odict/lib/core" - ods "github.com/TheOpenDictionary/odict/lib/search" - cli "github.com/urfave/cli/v2" -) - -func index(c *cli.Context) error { - inputFile := c.Args().Get(0) - quiet := c.Bool("quiet") - - if len(inputFile) == 0 { - return errors.New("the path to a compiled ODict file is required") - } - - return t(c, func() error { - dict, err := core.ReadDictionary(inputFile) - - if err != nil { - return err - } - - ods.Index(ods.IndexRequest{Dictionary: dict, Overwrite: true, Quiet: quiet}) - - return nil - }) -} diff --git a/cli/ipc.go b/cli/ipc.go deleted file mode 100644 index 5beb1ad7..00000000 --- a/cli/ipc.go +++ /dev/null @@ -1,261 +0,0 @@ -/* -Adapted from https://raw.githubusercontent.com/Akumzy/ipc/master/ipc.go - -# MIT License - -# Copyright (c) 2019 Akuma Isaac Akuma - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -package cli - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "log" - "os" - "strings" - "sync" - "time" - - "github.com/TheOpenDictionary/odict/lib/utils" - "github.com/google/uuid" -) - -// IPC channel -type IPC struct { - sendChannel chan payload - receiveListerners map[string][]Handler - receiveSendListerners map[string][]HandlerWithReply -} - -var ( - rLock sync.Mutex - rRLock sync.Mutex -) - -type replyChannel struct { - Event string `json:"event"` - ID string `json:"id"` -} - -// Payload this is the payload structure -type payload struct { - ID string `json:"id"` - Event string `json:"event"` - // If the data received from the parent is a literal value `Data` - //type will be equals to the underlining type for example: - // JavaScripts === Go - // `null === nil` - // `undefined === nil` - // `number(int) === int` - // `string === string` - // else if the `Data` is an Object in JavaScript - // data will be a JSON string - Data interface{} `json:"data"` - Error interface{} `json:"error"` - SR bool `json:"SR"` // send and receive - RS bool `json:"RC"` // receive and send -} - -// Handler When the underline type of data is being -// -// access through `type assertion` if the data has a -// literal value the underlining type will be return -// else a `JSON` representative of the data will be return -type Handler func(data interface{}) - -// HandlerWithReply When the underline type of data is being -// -// access through `type assertion` if the data has a literal -// value the underlining type will be return else a `JSON` representative of -// the data will be return. -// `replyChannel` is the event name you'll pass to `ipc.Reply` method to respond -// to the sender -type HandlerWithReply func(channel replyChannel, data interface{}) - -// PayloadReceive this is the payload structure -type payloadReceive struct { - ID string `json:"id"` - Event string `json:"event"` - Data interface{} `json:"data"` - SR bool `json:"SR"` //send and receive -} - -// Send data to parent process -func (ipc IPC) Send(event string, data interface{}, err interface{}) { - ipc.sendChannel <- payload{ID: uuid.NewString(), Event: event, Data: data, Error: err} -} - -// Reply back to sender -func (ipc IPC) Reply(channel replyChannel, data, err interface{}) { - ipc.sendChannel <- payload{ID: channel.ID, Event: channel.Event, Data: data, SR: true, Error: err} -} - -// On listens for events from parent process -func (ipc IPC) On(event string, handler Handler) { - rLock.Lock() - defer rLock.Unlock() - h := ipc.receiveListerners[event] - h = append(h, handler) - ipc.receiveListerners[event] = h -} - -// OnReceiveAndReply listen for an events and as well reply back to -// the same sender with the help of `ipc.Reply` method -func (ipc IPC) OnReceiveAndReply(event string, handler HandlerWithReply) { - rRLock.Lock() - defer rRLock.Unlock() - h := ipc.receiveSendListerners[event] - h = append(h, handler) - ipc.receiveSendListerners[event] = h -} - -// SendAndReceive send and listen for reply event -func (ipc IPC) SendAndReceive(event string, data interface{}, handler Handler) { - id := uuid.NewString() - ipc.sendChannel <- payload{ID: id, Event: event, Data: data, RS: true} - channel := event + ":" + id - ipc.On(channel, handler) -} - -// RemoveListener remove listener -func (ipc IPC) RemoveListener(event string) { - delete(ipc.receiveListerners, event) -} - -// Start `ipc` -// the `ipc.Start` method will blocks executions -// so is either you put in a separate `Go routine` or put you own code in -// a different `Go routine` -func (ipc IPC) Start() { - - go func() { - for { - msg := <-ipc.sendChannel - data, err := Marshal(msg) - if err != nil { - log.Println(err) - } else { - text := data + "\\n" - - if os.Getenv("ODICT_DEBUG_IPC") == "true" { - utils.AppendToFile("ipc.log", "GO SENT: "+text) - } - - fmt.Print(text) - } - } - }() - - reader := bufio.NewReader(os.Stdin) - - for { - text, err := reader.ReadString('\n') - - if err != nil { - log.Println(err) - continue - } - - if text != "" { - var payload payloadReceive - - text = strings.TrimSuffix(text, "\n") - - if os.Getenv("ODICT_DEBUG_IPC") == "true" { - utils.AppendToFile("ipc.log", "GO RECEIVED: "+text) - } - - // check if the text is not empty string - if text != "" { - if err := json.Unmarshal([]byte(text), &payload); err != nil { - log.Println(err) - continue - } - - if payload.Event == "___EXIT___" { - os.Exit(0) - } - - // Run the handlers in a goroutine to prevent - // https://github.com/Akumzy/ipc/issues/1 - go func() { - if payload.SR { - for _, handler := range ipc.receiveSendListerners[payload.Event] { - handler(replyChannel{ID: payload.ID, Event: payload.Event}, payload.Data) - } - } else { - for _, handler := range ipc.receiveListerners[payload.Event+":"+payload.ID] { - handler(payload.Data) - } - - for _, handler := range ipc.receiveListerners[payload.Event] { - handler(payload.Data) - } - } - }() - } - - } - } -} - -// Marshal to json -func Marshal(v interface{}) (string, error) { - buf := new(bytes.Buffer) - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - if err := enc.Encode(&v); err != nil { - return "", err - } - log.Println(buf.String()) - return strings.TrimSpace(buf.String()), nil -} - -// pingPong is used to eliminate zombies -// ping the parent process every 20 seconds -func pingPong(ipc *IPC) { - isActive := true - ipc.On("pong", func(d interface{}) { - isActive = true - }) - for { - time.Sleep(20 * time.Second) - if isActive { - isActive = false - } else { - log.Println("[IPC] Timeout closing process.") - os.Exit(0) - } - ipc.Send("ping", nil, nil) - } -} - -// New return now ipc -func NewIPC() *IPC { - ipc := &IPC{} - ipc.sendChannel = make(chan payload) - ipc.receiveListerners = make(map[string][]Handler) - ipc.receiveSendListerners = make(map[string][]HandlerWithReply) - go pingPong(ipc) - return ipc -} diff --git a/cli/justfile b/cli/justfile deleted file mode 100644 index ae79687d..00000000 --- a/cli/justfile +++ /dev/null @@ -1,2 +0,0 @@ -@schema: - flatc -g --gen-onefile --go-namespace cli -o . ../flatbuffers/service.fbs ../flatbuffers/enums.fbs && $(go env GOPATH)/bin/goimports -w *.go \ No newline at end of file diff --git a/cli/lexicon.go b/cli/lexicon.go deleted file mode 100644 index 6553fc24..00000000 --- a/cli/lexicon.go +++ /dev/null @@ -1,28 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/TheOpenDictionary/odict/lib/core" - cli "github.com/urfave/cli/v2" -) - -func lexicon(c *cli.Context) error { - inputFile := c.Args().Get(0) - - return t(c, func() error { - dict, err := core.ReadDictionary(inputFile) - - if err != nil { - return err - } - - result := core.Lexicon(dict) - - for _, word := range result { - fmt.Println(word) - } - - return nil - }) -} diff --git a/cli/lookup.go b/cli/lookup.go deleted file mode 100644 index c834ec65..00000000 --- a/cli/lookup.go +++ /dev/null @@ -1,42 +0,0 @@ -package cli - -import ( - "errors" - - "github.com/TheOpenDictionary/odict/lib/core" - "github.com/TheOpenDictionary/odict/lib/types" - cli "github.com/urfave/cli/v2" -) - -func lookup(c *cli.Context) error { - inputFile := c.Args().Get(0) - queries := c.Args().Tail() - format := c.String("format") - - if len(inputFile) == 0 || len(queries) == 0 { - return errors.New("usage: odict lookup [dictionary path] [queries]") - } - - return t(c, func() error { - dict, err := core.ReadDictionary(inputFile) - - if err != nil { - return err - } - - request := core.LookupRequest{ - Dictionary: dict, - Queries: queries, - Follow: c.Bool("follow"), - Split: c.Int("split"), - } - - entries := core.Lookup(request) - - representables := types.NestedEntriesToRepresentables(entries) - - PrintEntries(representables, format, true) - - return nil - }) -} diff --git a/cli/merge.go b/cli/merge.go deleted file mode 100644 index 79204a3d..00000000 --- a/cli/merge.go +++ /dev/null @@ -1,42 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/TheOpenDictionary/odict/lib/core" - cli "github.com/urfave/cli/v2" -) - -func merge(c *cli.Context) error { - inputFile1 := c.Args().Get(0) - inputFile2 := c.Args().Get(1) - outputFile := c.Args().Get(2) - - if len(inputFile1) == 0 || len(inputFile2) == 0 || len(outputFile) == 0 { - return fmt.Errorf("usage: odict merge [dictionary1] [dictionary2] [outputFile]") - } - - return t(c, func() error { - dict1, err := core.ReadDictionary(inputFile1) - - if err != nil { - return err - } - - dict2, err := core.ReadDictionary(inputFile2) - - if err != nil { - return err - } - - result, err := core.MergeDictionaries(dict1, dict2) - - if err != nil { - return err - } - - core.WriteDictionaryToDisk(outputFile, result) - - return nil - }) -} diff --git a/cli/print.go b/cli/print.go deleted file mode 100644 index 35966277..00000000 --- a/cli/print.go +++ /dev/null @@ -1,212 +0,0 @@ -//go:build !js && !wasm - -package cli - -import ( - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/TheOpenDictionary/odict/lib/types" - "github.com/TheOpenDictionary/odict/lib/utils" - "github.com/fatih/color" -) - -var fmtFaint = color.New(color.Faint).SprintfFunc() -var fmtEtymology = color.New(color.Underline, color.Bold).SprintfFunc() -var fmtExample = color.New(color.Faint, color.Italic).SprintfFunc() -var fmtExampleTarget = color.New(color.Faint, color.Underline, color.Italic).SprintfFunc() -var fmtParenthetical = color.New(color.Italic).SprintfFunc() -var fmtNoteTitle = color.New(color.Underline, color.Bold).SprintfFunc() -var fmtPartOfSpeech = color.New(color.Italic).SprintfFunc() -var fmtEntry = color.New(color.Bold).SprintfFunc() - -var parentheticalRegex = regexp.MustCompile(`^(\(.*?\)\s*)`) - -type PrintFormat = string - -const ( - jsonFormat PrintFormat = "json" - xmlFormat PrintFormat = "xml" - printFormat PrintFormat = "print" -) - -func printNewLine() { - fmt.Println() -} - -func printExample(example string, targetWord string, indent int) { - start := strings.Index(strings.ToLower(example), strings.ToLower(targetWord)) - caret := fmtExample("▸") - - if start >= 0 { - end := start + len(targetWord) - before := fmtExample(example[0:start]) - after := fmtExample(example[end:]) - target := fmtExampleTarget(example[start:end]) - - fmt.Printf("%*s%s %s%s%s\n", indent, "", caret, before, target, after) - } else { - fmt.Printf("%*s%s %s\n", indent, "", caret, fmtExample(example)) - } - -} - -func printDivider() { - fmt.Println(strings.Repeat("─", 32)) -} - -func printNote(note types.NoteRepresentable, targetWord string, numbering string, indent int) { - fmtNumbering := "%" + fmt.Sprint(indent) + "s." - - fmt.Printf(fmtNumbering+" %s\n", numbering, note.Value) - - for _, example := range note.Examples { - printExample(example, targetWord, indent+2) - } - - fmt.Println() -} - -func printDefinition(definition types.DefinitionRepresentable, numbering string, entry types.EntryRepresentable, indent int) { - value := definition.Value - matches := parentheticalRegex.FindAllStringIndex(string(value), -1) - fmtNumbering := "%" + fmt.Sprint(indent) + "s." - - if len(matches) > 0 { - j := 0 - - fmt.Printf(fmtNumbering+" %s", numbering, value[0:matches[0][0]]) - - for i := 0; i < len(matches); i += 1 { - start := matches[i][0] - end := matches[i][1] - - fmt.Printf("%s%s", value[j:start], fmtParenthetical(string(value[start:end]))) - - j = end - } - - fmt.Printf("%s\n", value[j:]) - } else { - fmt.Printf(fmtNumbering+" %s\n", numbering, value) - } - - for _, example := range definition.Examples { - printExample(example, entry.Term, indent+2) - } - - if len(definition.Notes) > 0 { - fmt.Printf("\n%*s%s\n\n", indent+2, "", fmtNoteTitle("Notes")) - } - - for j, note := range definition.Notes { - printNote(note, entry.Term, string(rune('a'+j)), indent+4) - } -} - -func printGroup(group types.GroupRepresentable, i int, entry types.EntryRepresentable) { - fmt.Printf("%4d. %s\n", i+1, group.Description) - - for j, definition := range group.Definitions { - printDefinition(definition, string(rune('a'+j)), entry, 7) - } -} - -func printSense(sense types.SenseRepresentable, entry types.EntryRepresentable) { - fmt.Printf("\n%s\n\n", fmtPartOfSpeech(sense.POS.Label)) - - var i = 0 - - for i < len(sense.Groups) { - printGroup(sense.Groups[i], i, entry) - i++ - } - - for i < len(sense.Definitions) { - printDefinition(sense.Definitions[i], strconv.Itoa(i+1), entry, 4) - i++ - } -} - -func printEty(ety types.EtymologyRepresentable, i int, showTitle bool, entry types.EntryRepresentable) { - if showTitle { - fmt.Printf("%s\n\n", fmtEtymology("Etymology #%d", i+1)) - } - - if len(ety.Description) > 0 { - fmt.Println(ety.Description) - } - - for _, sense := range ety.Senses { - printSense(sense, entry) - } - - fmt.Println() -} - -func printEntry(entry types.EntryRepresentable) { - printDivider() - - fmt.Println(fmtEntry(entry.Term)) - - printDivider() - - fmt.Println() - - etys := entry.Etymologies - - for i, ety := range etys { - printEty(ety, i, len(etys) > 1, entry) - } - -} - -func prettyPrint(entries [][]types.EntryRepresentable) error { - fmt.Println() - - hasEntries := false - - for _, entry := range entries { - for _, subentry := range entry { - hasEntries = true - printEntry(subentry) - } - } - - if !hasEntries { - return fmt.Errorf("no entries found") - } - - return nil -} - -func PrintEntries(entries [][]types.EntryRepresentable, format PrintFormat, indent bool) error { - switch { - case format == "json": - json, err := utils.SerializeToJSON(entries, indent) - - if err != nil { - return err - } - - fmt.Print(json) - case format == "xml": - xml, err := utils.SerializeToXML(entries, indent) - - if err != nil { - return err - } - - fmt.Print(xml) - case format == "print": - err := prettyPrint(entries) - - if err != nil { - return err - } - } - - return nil -} diff --git a/cli/report.json b/cli/report.json new file mode 100644 index 00000000..a0ea5485 --- /dev/null +++ b/cli/report.json @@ -0,0 +1,5 @@ +{ + "version": 0, + "root_name": "Workspace", + "workspace_crates": {} +} \ No newline at end of file diff --git a/cli/search.go b/cli/search.go deleted file mode 100644 index 29825049..00000000 --- a/cli/search.go +++ /dev/null @@ -1,79 +0,0 @@ -package cli - -import ( - "errors" - "fmt" - - "github.com/TheOpenDictionary/odict/lib/core" - ods "github.com/TheOpenDictionary/odict/lib/search" - "github.com/TheOpenDictionary/odict/lib/types" - "github.com/TheOpenDictionary/odict/lib/utils" - "github.com/samber/lo" - cli "github.com/urfave/cli/v2" -) - -type SearchRequest struct { - Dictionary *types.Dictionary - Force bool - Exact bool - Query string - Quiet bool - PrettyPrint bool -} - -func search(c *cli.Context) error { - inputFile := c.Args().Get(0) - searchTerm := c.Args().Get(1) - force := c.Bool("index") - exact := c.Bool("exact") - quiet := c.Bool("quiet") - - if len(inputFile) == 0 || len(searchTerm) == 0 { - return errors.New("usage: odict search [odict file] [search term]") - } - - return t(c, func() error { - dict, err := core.ReadDictionary(inputFile) - - if err != nil { - return err - } - - request := SearchRequest{ - Dictionary: dict, - Force: force, - Exact: exact, - Query: searchTerm, - Quiet: quiet, - PrettyPrint: true, - } - - ods.Index(ods.IndexRequest{Dictionary: request.Dictionary, Overwrite: request.Force, Quiet: request.Quiet}) - - results, err := ods.SearchDictionary( - ods.SearchDictionaryRequest{ - Dictionary: request.Dictionary, - Query: request.Query, - Exact: request.Exact, - }, - ) - - if err != nil { - return err - } - - representable := lo.Map(results, func(entry types.Entry, _ int) types.EntryRepresentable { - return entry.AsRepresentable() - }) - - json, err := utils.SerializeToJSON(representable, request.PrettyPrint) - - if err != nil { - return err - } - - fmt.Print(json) - - return nil - }) -} diff --git a/cli/server.go b/cli/server.go deleted file mode 100644 index 1160fb91..00000000 --- a/cli/server.go +++ /dev/null @@ -1,10 +0,0 @@ -package cli - -import ( - "github.com/TheOpenDictionary/odict/lib/server" - cli "github.com/urfave/cli/v2" -) - -func serve(c *cli.Context) error { - return server.StartServer(c.Args().First(), c.Int("port")) -} diff --git a/cli/service.go b/cli/service.go deleted file mode 100644 index 241ccee9..00000000 --- a/cli/service.go +++ /dev/null @@ -1,182 +0,0 @@ -package cli - -import ( - "encoding/base64" - "fmt" - - "github.com/TheOpenDictionary/odict/lib/core" - ods "github.com/TheOpenDictionary/odict/lib/search" - "github.com/TheOpenDictionary/odict/lib/types" - "github.com/samber/lo" - cli "github.com/urfave/cli/v2" -) - -type Request struct { - Function string `json:"function"` - Parameters map[string]string `json:"parameters"` -} - -type Payload struct { - Payload []int `json:"payload"` -} - -func decodePayload(payload interface{}) ([]byte, error) { - text := payload.(string) - - if len(text) > 0 { - return base64.StdEncoding.DecodeString(text) - } - - return nil, fmt.Errorf("cannot decode an empty payload") -} - -func service(c *cli.Context) error { - ipc := NewIPC() - dictPath := c.Args().Get(0) - - go func() { - var dict *types.Dictionary - - if len(dictPath) > 0 { - var err error - - dict, err = core.ReadDictionary(dictPath) - - if err != nil { - ipc.Send(EnumNamesODictMethod[ODictMethodReady], nil, fmt.Sprint(err)) - } else { - ipc.Send(EnumNamesODictMethod[ODictMethodReady], true, nil) - } - } else { - ipc.Send(EnumNamesODictMethod[ODictMethodReady], true, nil) - } - - // Write - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodWrite], func(reply replyChannel, payload interface{}) { - if buf, err := decodePayload(payload); err != nil { - ipc.Reply(reply, nil, err) - } else { - payload := GetRootAsWritePayload(buf, 0) - core.WriteDictionaryFromXML(string(payload.Xml()), string(payload.Out())) - ipc.Reply(reply, true, nil) - } - }) - - // Split - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodSplit], func(reply replyChannel, payload interface{}) { - if buf, err := decodePayload(payload); err != nil { - ipc.Reply(reply, nil, err) - } else { - payload := GetRootAsSplitPayload(buf, 0) - - query := string(payload.Query()) - - threshold := int(payload.Threshold()) - - entries := core.Split(core.SplitRequest{ - Dictionary: dict, - Query: query, - Threshold: threshold, - }) - - representable := types.EntriesToRepresentables(entries) - - ipc.Reply(reply, representable, nil) - } - }) - - // Search - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodSearch], func(reply replyChannel, payload interface{}) { - if buf, err := decodePayload(payload); err != nil { - ipc.Reply(reply, nil, err) - } else { - payload := GetRootAsSearchPayload(buf, 0) - force := payload.Force() - exact := payload.Exact() - query := string(payload.Query()) - - ods.Index(ods.IndexRequest{Dictionary: dict, Overwrite: force, Quiet: true}) - - results, err := ods.SearchDictionary(ods.SearchDictionaryRequest{Dictionary: dict, Query: query, Exact: exact}) - - if err != nil { - ipc.Reply(reply, nil, err) - return - } - - representable := lo.Map(results, func(entry types.Entry, _ int) types.EntryRepresentable { - return entry.AsRepresentable() - }) - - ipc.Reply(reply, representable, nil) - } - }) - - // Index - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodIndex], func(reply replyChannel, payload interface{}) { - ods.Index(ods.IndexRequest{Dictionary: dict, Overwrite: true, Quiet: true}) - ipc.Reply(reply, true, nil) - }) - - // Lexicon - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodLexicon], func(reply replyChannel, payload interface{}) { - result := core.Lexicon(dict) - ipc.Reply(reply, result, nil) - }) - - // Lookup - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodLookup], func(reply replyChannel, payload interface{}) { - if buf, err := decodePayload(payload); err == nil && dict != nil { - payload := GetRootAsLookupPayload(buf, 0) - queries := make([]string, payload.QueriesLength()) - follow := payload.Follow() - split := int(payload.Split()) - markdown := payload.Markdown() - - switch markdown { - case MarkdownStrategyHTML: - types.SetMarkdownProcessingStrategy(types.MarkdownStrategyHTML) - case MarkdownStrategyText: - types.SetMarkdownProcessingStrategy(types.MarkdownStrategyText) - case MarkdownStrategyDisable: - types.SetMarkdownProcessingStrategy(types.MarkdownStrategyDisable) - } - - for i := 0; i < payload.QueriesLength(); i++ { - queries[i] = string(payload.Queries(i)) - } - - entries := core.Lookup(core.LookupRequest{ - Dictionary: dict, - Queries: queries, - Follow: follow, - Split: split, - }) - - representable := types.NestedEntriesToRepresentables(entries) - - ipc.Reply(reply, representable, nil) - } else if err != nil { - ipc.Reply(reply, nil, err) - } else { - ipc.Reply(reply, nil, fmt.Errorf("no dictionary loaded")) - } - }) - - // Compile - ipc.OnReceiveAndReply(EnumNamesODictMethod[ODictMethodCompile], func(reply replyChannel, payload interface{}) { - if buf, err := decodePayload(payload); err != nil { - ipc.Reply(reply, nil, err) - } else { - payload := GetRootAsCompilePayload(buf, 0) - core.CompileDictionary(string(payload.Path()), string(payload.Out())) - ipc.Reply(reply, true, nil) - } - }) - - }() - - ipc.Start() - - return nil -} diff --git a/cli/service_generated.go b/cli/service_generated.go deleted file mode 100644 index 0a3a5c77..00000000 --- a/cli/service_generated.go +++ /dev/null @@ -1,427 +0,0 @@ -// Code generated by the FlatBuffers compiler. DO NOT EDIT. - -package cli - -import ( - "strconv" - - flatbuffers "github.com/google/flatbuffers/go" -) - -type ODictMethod int8 - -const ( - ODictMethodLookup ODictMethod = 1 - ODictMethodSplit ODictMethod = 2 - ODictMethodIndex ODictMethod = 3 - ODictMethodSearch ODictMethod = 4 - ODictMethodCompile ODictMethod = 5 - ODictMethodWrite ODictMethod = 6 - ODictMethodLexicon ODictMethod = 7 - ODictMethodReady ODictMethod = 8 -) - -var EnumNamesODictMethod = map[ODictMethod]string{ - ODictMethodLookup: "Lookup", - ODictMethodSplit: "Split", - ODictMethodIndex: "Index", - ODictMethodSearch: "Search", - ODictMethodCompile: "Compile", - ODictMethodWrite: "Write", - ODictMethodLexicon: "Lexicon", - ODictMethodReady: "Ready", -} - -var EnumValuesODictMethod = map[string]ODictMethod{ - "Lookup": ODictMethodLookup, - "Split": ODictMethodSplit, - "Index": ODictMethodIndex, - "Search": ODictMethodSearch, - "Compile": ODictMethodCompile, - "Write": ODictMethodWrite, - "Lexicon": ODictMethodLexicon, - "Ready": ODictMethodReady, -} - -func (v ODictMethod) String() string { - if s, ok := EnumNamesODictMethod[v]; ok { - return s - } - return "ODictMethod(" + strconv.FormatInt(int64(v), 10) + ")" -} - -type MarkdownStrategy int16 - -const ( - MarkdownStrategyDisable MarkdownStrategy = 0 - MarkdownStrategyText MarkdownStrategy = 1 - MarkdownStrategyHTML MarkdownStrategy = 2 -) - -var EnumNamesMarkdownStrategy = map[MarkdownStrategy]string{ - MarkdownStrategyDisable: "Disable", - MarkdownStrategyText: "Text", - MarkdownStrategyHTML: "HTML", -} - -var EnumValuesMarkdownStrategy = map[string]MarkdownStrategy{ - "Disable": MarkdownStrategyDisable, - "Text": MarkdownStrategyText, - "HTML": MarkdownStrategyHTML, -} - -func (v MarkdownStrategy) String() string { - if s, ok := EnumNamesMarkdownStrategy[v]; ok { - return s - } - return "MarkdownStrategy(" + strconv.FormatInt(int64(v), 10) + ")" -} - -type LookupPayload struct { - _tab flatbuffers.Table -} - -func GetRootAsLookupPayload(buf []byte, offset flatbuffers.UOffsetT) *LookupPayload { - n := flatbuffers.GetUOffsetT(buf[offset:]) - x := &LookupPayload{} - x.Init(buf, n+offset) - return x -} - -func GetSizePrefixedRootAsLookupPayload(buf []byte, offset flatbuffers.UOffsetT) *LookupPayload { - n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) - x := &LookupPayload{} - x.Init(buf, n+offset+flatbuffers.SizeUint32) - return x -} - -func (rcv *LookupPayload) Init(buf []byte, i flatbuffers.UOffsetT) { - rcv._tab.Bytes = buf - rcv._tab.Pos = i -} - -func (rcv *LookupPayload) Table() flatbuffers.Table { - return rcv._tab -} - -func (rcv *LookupPayload) Follow() bool { - o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) - if o != 0 { - return rcv._tab.GetBool(o + rcv._tab.Pos) - } - return false -} - -func (rcv *LookupPayload) MutateFollow(n bool) bool { - return rcv._tab.MutateBoolSlot(4, n) -} - -func (rcv *LookupPayload) Split() int32 { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - return rcv._tab.GetInt32(o + rcv._tab.Pos) - } - return 0 -} - -func (rcv *LookupPayload) MutateSplit(n int32) bool { - return rcv._tab.MutateInt32Slot(6, n) -} - -func (rcv *LookupPayload) Markdown() MarkdownStrategy { - o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) - if o != 0 { - return MarkdownStrategy(rcv._tab.GetInt16(o + rcv._tab.Pos)) - } - return 0 -} - -func (rcv *LookupPayload) MutateMarkdown(n MarkdownStrategy) bool { - return rcv._tab.MutateInt16Slot(8, int16(n)) -} - -func (rcv *LookupPayload) Queries(j int) []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) - if o != 0 { - a := rcv._tab.Vector(o) - return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j*4)) - } - return nil -} - -func (rcv *LookupPayload) QueriesLength() int { - o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) - if o != 0 { - return rcv._tab.VectorLen(o) - } - return 0 -} - -func LookupPayloadStart(builder *flatbuffers.Builder) { - builder.StartObject(4) -} -func LookupPayloadAddFollow(builder *flatbuffers.Builder, follow bool) { - builder.PrependBoolSlot(0, follow, false) -} -func LookupPayloadAddSplit(builder *flatbuffers.Builder, split int32) { - builder.PrependInt32Slot(1, split, 0) -} -func LookupPayloadAddMarkdown(builder *flatbuffers.Builder, markdown MarkdownStrategy) { - builder.PrependInt16Slot(2, int16(markdown), 0) -} -func LookupPayloadAddQueries(builder *flatbuffers.Builder, queries flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(queries), 0) -} -func LookupPayloadStartQueriesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { - return builder.StartVector(4, numElems, 4) -} -func LookupPayloadEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { - return builder.EndObject() -} - -type WritePayload struct { - _tab flatbuffers.Table -} - -func GetRootAsWritePayload(buf []byte, offset flatbuffers.UOffsetT) *WritePayload { - n := flatbuffers.GetUOffsetT(buf[offset:]) - x := &WritePayload{} - x.Init(buf, n+offset) - return x -} - -func GetSizePrefixedRootAsWritePayload(buf []byte, offset flatbuffers.UOffsetT) *WritePayload { - n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) - x := &WritePayload{} - x.Init(buf, n+offset+flatbuffers.SizeUint32) - return x -} - -func (rcv *WritePayload) Init(buf []byte, i flatbuffers.UOffsetT) { - rcv._tab.Bytes = buf - rcv._tab.Pos = i -} - -func (rcv *WritePayload) Table() flatbuffers.Table { - return rcv._tab -} - -func (rcv *WritePayload) Xml() []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) - if o != 0 { - return rcv._tab.ByteVector(o + rcv._tab.Pos) - } - return nil -} - -func (rcv *WritePayload) Out() []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - return rcv._tab.ByteVector(o + rcv._tab.Pos) - } - return nil -} - -func WritePayloadStart(builder *flatbuffers.Builder) { - builder.StartObject(2) -} -func WritePayloadAddXml(builder *flatbuffers.Builder, xml flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(xml), 0) -} -func WritePayloadAddOut(builder *flatbuffers.Builder, out flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(out), 0) -} -func WritePayloadEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { - return builder.EndObject() -} - -type SplitPayload struct { - _tab flatbuffers.Table -} - -func GetRootAsSplitPayload(buf []byte, offset flatbuffers.UOffsetT) *SplitPayload { - n := flatbuffers.GetUOffsetT(buf[offset:]) - x := &SplitPayload{} - x.Init(buf, n+offset) - return x -} - -func GetSizePrefixedRootAsSplitPayload(buf []byte, offset flatbuffers.UOffsetT) *SplitPayload { - n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) - x := &SplitPayload{} - x.Init(buf, n+offset+flatbuffers.SizeUint32) - return x -} - -func (rcv *SplitPayload) Init(buf []byte, i flatbuffers.UOffsetT) { - rcv._tab.Bytes = buf - rcv._tab.Pos = i -} - -func (rcv *SplitPayload) Table() flatbuffers.Table { - return rcv._tab -} - -func (rcv *SplitPayload) Threshold() int32 { - o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) - if o != 0 { - return rcv._tab.GetInt32(o + rcv._tab.Pos) - } - return 0 -} - -func (rcv *SplitPayload) MutateThreshold(n int32) bool { - return rcv._tab.MutateInt32Slot(4, n) -} - -func (rcv *SplitPayload) Query() []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - return rcv._tab.ByteVector(o + rcv._tab.Pos) - } - return nil -} - -func SplitPayloadStart(builder *flatbuffers.Builder) { - builder.StartObject(2) -} -func SplitPayloadAddThreshold(builder *flatbuffers.Builder, threshold int32) { - builder.PrependInt32Slot(0, threshold, 0) -} -func SplitPayloadAddQuery(builder *flatbuffers.Builder, query flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(query), 0) -} -func SplitPayloadEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { - return builder.EndObject() -} - -type SearchPayload struct { - _tab flatbuffers.Table -} - -func GetRootAsSearchPayload(buf []byte, offset flatbuffers.UOffsetT) *SearchPayload { - n := flatbuffers.GetUOffsetT(buf[offset:]) - x := &SearchPayload{} - x.Init(buf, n+offset) - return x -} - -func GetSizePrefixedRootAsSearchPayload(buf []byte, offset flatbuffers.UOffsetT) *SearchPayload { - n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) - x := &SearchPayload{} - x.Init(buf, n+offset+flatbuffers.SizeUint32) - return x -} - -func (rcv *SearchPayload) Init(buf []byte, i flatbuffers.UOffsetT) { - rcv._tab.Bytes = buf - rcv._tab.Pos = i -} - -func (rcv *SearchPayload) Table() flatbuffers.Table { - return rcv._tab -} - -func (rcv *SearchPayload) Force() bool { - o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) - if o != 0 { - return rcv._tab.GetBool(o + rcv._tab.Pos) - } - return false -} - -func (rcv *SearchPayload) MutateForce(n bool) bool { - return rcv._tab.MutateBoolSlot(4, n) -} - -func (rcv *SearchPayload) Exact() bool { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - return rcv._tab.GetBool(o + rcv._tab.Pos) - } - return false -} - -func (rcv *SearchPayload) MutateExact(n bool) bool { - return rcv._tab.MutateBoolSlot(6, n) -} - -func (rcv *SearchPayload) Query() []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) - if o != 0 { - return rcv._tab.ByteVector(o + rcv._tab.Pos) - } - return nil -} - -func SearchPayloadStart(builder *flatbuffers.Builder) { - builder.StartObject(3) -} -func SearchPayloadAddForce(builder *flatbuffers.Builder, force bool) { - builder.PrependBoolSlot(0, force, false) -} -func SearchPayloadAddExact(builder *flatbuffers.Builder, exact bool) { - builder.PrependBoolSlot(1, exact, false) -} -func SearchPayloadAddQuery(builder *flatbuffers.Builder, query flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(query), 0) -} -func SearchPayloadEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { - return builder.EndObject() -} - -type CompilePayload struct { - _tab flatbuffers.Table -} - -func GetRootAsCompilePayload(buf []byte, offset flatbuffers.UOffsetT) *CompilePayload { - n := flatbuffers.GetUOffsetT(buf[offset:]) - x := &CompilePayload{} - x.Init(buf, n+offset) - return x -} - -func GetSizePrefixedRootAsCompilePayload(buf []byte, offset flatbuffers.UOffsetT) *CompilePayload { - n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) - x := &CompilePayload{} - x.Init(buf, n+offset+flatbuffers.SizeUint32) - return x -} - -func (rcv *CompilePayload) Init(buf []byte, i flatbuffers.UOffsetT) { - rcv._tab.Bytes = buf - rcv._tab.Pos = i -} - -func (rcv *CompilePayload) Table() flatbuffers.Table { - return rcv._tab -} - -func (rcv *CompilePayload) Path() []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) - if o != 0 { - return rcv._tab.ByteVector(o + rcv._tab.Pos) - } - return nil -} - -func (rcv *CompilePayload) Out() []byte { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - return rcv._tab.ByteVector(o + rcv._tab.Pos) - } - return nil -} - -func CompilePayloadStart(builder *flatbuffers.Builder) { - builder.StartObject(2) -} -func CompilePayloadAddPath(builder *flatbuffers.Builder, path flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(path), 0) -} -func CompilePayloadAddOut(builder *flatbuffers.Builder, out flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(out), 0) -} -func CompilePayloadEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { - return builder.EndObject() -} diff --git a/cli/split.go b/cli/split.go deleted file mode 100644 index 12997238..00000000 --- a/cli/split.go +++ /dev/null @@ -1,43 +0,0 @@ -package cli - -import ( - "errors" - "fmt" - - "github.com/TheOpenDictionary/odict/lib/core" - "github.com/TheOpenDictionary/odict/lib/types" - "github.com/TheOpenDictionary/odict/lib/utils" - cli "github.com/urfave/cli/v2" -) - -func split(c *cli.Context) error { - inputFile := c.Args().Get(0) - searchTerm := c.Args().Get(1) - threshold := c.Int("threshold") - - if len(inputFile) == 0 || len(searchTerm) == 0 { - return errors.New("usage: odict split [-t threshold] [odict file] [search term]") - } - - return t(c, func() error { - dict, err := core.ReadDictionary(inputFile) - - if err != nil { - return err - } - - request := core.SplitRequest{ - Dictionary: dict, - Query: searchTerm, - Threshold: threshold, - } - - entries := core.Split(request) - - representable := types.EntriesToRepresentables(entries) - - fmt.Print(utils.SerializeToJSON(representable, true)) - - return nil - }) -} diff --git a/cli/src/alias/alias.rs b/cli/src/alias/alias.rs new file mode 100644 index 00000000..78f4b1b6 --- /dev/null +++ b/cli/src/alias/alias.rs @@ -0,0 +1,33 @@ +use std::error::Error; + +use crate::CLIContext; + +use super::{ + delete::{delete, DeleteArgs}, + set::{set, SetArgs}, +}; + +use clap::{command, Subcommand}; + +#[derive(Debug, Subcommand)] +pub enum AliasCommands { + /// Attempts to create a new dictionary alias, failing if one already exists with the given name + #[command(arg_required_else_help = true)] + Add(SetArgs), + + /// Creates or updates an existing dictionary alias + #[command(arg_required_else_help = true)] + Set(SetArgs), + + /// Deletes an alias with the given name if it exists + #[command(arg_required_else_help = true)] + Delete(DeleteArgs), +} + +pub fn alias(ctx: &mut CLIContext, command: &AliasCommands) -> Result<(), Box> { + match command { + AliasCommands::Add(ref args) => set(ctx, args, false), + AliasCommands::Set(ref args) => set(ctx, args, true), + AliasCommands::Delete(ref args) => delete(ctx, args), + } +} diff --git a/cli/src/alias/delete.rs b/cli/src/alias/delete.rs new file mode 100644 index 00000000..e415d192 --- /dev/null +++ b/cli/src/alias/delete.rs @@ -0,0 +1,17 @@ +use std::error::Error; + +use clap::{arg, Args}; + +use crate::CLIContext; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct DeleteArgs { + #[arg(required = true, help = "Name of the alias")] + name: String, +} + +pub fn delete(ctx: &mut CLIContext, args: &DeleteArgs) -> Result<(), Box> { + ctx.alias_manager.delete(args.name.as_str()) +} diff --git a/cli/src/alias/mod.rs b/cli/src/alias/mod.rs new file mode 100644 index 00000000..8861efad --- /dev/null +++ b/cli/src/alias/mod.rs @@ -0,0 +1,5 @@ +mod alias; +mod delete; +mod set; + +pub use self::alias::*; diff --git a/cli/src/alias/set.rs b/cli/src/alias/set.rs new file mode 100644 index 00000000..b23f24af --- /dev/null +++ b/cli/src/alias/set.rs @@ -0,0 +1,26 @@ +use std::error::Error; + +use clap::{arg, Args}; + +use crate::CLIContext; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct SetArgs { + #[arg(required = true, help = "Name of the alias")] + name: String, + + #[arg(required = true, help = "Dictionary path")] + path: String, +} + +pub fn set(ctx: &mut CLIContext, args: &SetArgs, overwrite: bool) -> Result<(), Box> { + let dict = ctx.reader.read_from_path(args.path.as_str())?; + + if overwrite { + ctx.alias_manager.set(args.name.as_str(), &dict) + } else { + ctx.alias_manager.add(args.name.as_str(), &dict) + } +} diff --git a/cli/src/cli.rs b/cli/src/cli.rs new file mode 100644 index 00000000..e1db4de2 --- /dev/null +++ b/cli/src/cli.rs @@ -0,0 +1,69 @@ +use clap::{command, crate_version, Parser, Subcommand}; + +use crate::alias::AliasCommands; +use crate::{ + CompileArgs, DumpArgs, IndexArgs, InfoArgs, LexiconArgs, LookupArgs, MergeArgs, NewArgs, + SearchArgs, ServeArgs, +}; + +#[derive(Debug, Parser)] +#[command(name = "odict", about = "the lighting-fast open-source dictionary compiler", version = crate_version!(), long_about = None)] +pub struct CLI { + #[command(subcommand)] + pub command: Commands, + + #[arg( + short, + long, + default_value_t = false, + help = "Silence any non-important output" + )] + pub quiet: bool, +} + +#[derive(Debug, Subcommand)] +pub enum Commands { + /// Manage dictionary aliases + #[command(subcommand, arg_required_else_help = true)] + Alias(AliasCommands), + + /// Compiles a dictionary from ODXML + #[command(arg_required_else_help = true)] + Compile(CompileArgs), + + /// Outputs a dictionary in a human-readable format + #[command(arg_required_else_help = true)] + Dump(DumpArgs), + + /// Creates a full-text index of a compiled dictionary + #[command(arg_required_else_help = true)] + Index(IndexArgs), + + /// Prints the metadata info for a dictionary file + #[command(arg_required_else_help = true)] + Info(InfoArgs), + + /// Lists all words defined in a dictionary + #[command(arg_required_else_help = true)] + Lexicon(LexiconArgs), + + /// Looks up an entry in a compiled dictionary without indexing + #[command(arg_required_else_help = true)] + Lookup(LookupArgs), + + /// Merge entries from multiple dictionaries into a destination dictionary + #[command(arg_required_else_help = true)] + Merge(MergeArgs), + + /// Scaffolds a new ODict XML dictionary + #[command(arg_required_else_help = true)] + New(NewArgs), + + /// Run a full-text query on a compiled dictionary + #[command(arg_required_else_help = true)] + Search(SearchArgs), + + /// Start a local web server to serve one or several dictionaries + #[command(arg_required_else_help = true)] + Serve(ServeArgs), +} diff --git a/cli/src/compile.rs b/cli/src/compile.rs new file mode 100644 index 00000000..6b5fc22c --- /dev/null +++ b/cli/src/compile.rs @@ -0,0 +1,30 @@ +use std::{error::Error, path::PathBuf}; + +use clap::{arg, command, Args}; +use odict::fs::infer_path; + +use crate::CLIContext; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct CompileArgs { + #[arg(required = true, help = "Path to ODXML file")] + input: PathBuf, + + #[arg(short, help = "Output path of compiled dictionary")] + output: Option, +} + +pub fn compile(ctx: &CLIContext, args: &CompileArgs) -> Result<(), Box> { + let CompileArgs { input, output } = args; + let out = output.to_owned().unwrap_or_else(|| infer_path(&input)); + + let _ = ctx + .writer + .compile_xml(&input, &out) + .map(|_| ()) + .map_err(|e| format!("An error occurred compiling your XML: {}", e))?; + + Ok(()) +} diff --git a/cli/src/context.rs b/cli/src/context.rs new file mode 100644 index 00000000..a0cebba0 --- /dev/null +++ b/cli/src/context.rs @@ -0,0 +1,39 @@ +use std::io::Write; + +use console::Term; + +use crate::CLI; +use odict::{config::AliasManager, DictionaryReader, DictionaryWriter}; + +pub struct CLIContext<'a> { + pub cli: &'a CLI, + pub alias_manager: AliasManager, + pub reader: DictionaryReader, + pub writer: DictionaryWriter, + pub stdout: Term, + pub stderr: Term, +} + +impl<'a> CLIContext<'a> { + pub fn default(cli: &'a CLI) -> Self { + Self { + cli, + alias_manager: AliasManager::default(), + reader: DictionaryReader::default(), + writer: DictionaryWriter::default(), + stdout: Term::buffered_stdout(), + stderr: Term::buffered_stdout(), + } + } + + pub fn println(&mut self, msg: S) + where + S: AsRef, + { + self.stdout + .write_all(format!("{}\n", msg.as_ref()).as_bytes()) + .unwrap(); + + self.stdout.flush().unwrap(); + } +} diff --git a/cli/src/dump.rs b/cli/src/dump.rs new file mode 100644 index 00000000..aa0840d3 --- /dev/null +++ b/cli/src/dump.rs @@ -0,0 +1,50 @@ +use std::{error::Error, fs}; + +use clap::{arg, command, Args}; +use odict::{ + sql::{SQLDialect, ToSQL}, + xml::ToXML, +}; + +use crate::{enums::DumpFormat, CLIContext}; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct DumpArgs { + #[arg(required = true, help = "Path to a compile dictionary")] + input: String, + + #[arg(default_value_t = DumpFormat::XML, short, help = "Format in which to dump the dictionary.")] + format: DumpFormat, + + #[arg(short, help = "Output path of the dump. Defaults to stdout.")] + output: Option, +} + +pub fn dump(ctx: &mut CLIContext, args: &DumpArgs) -> Result<(), Box> { + let DumpArgs { + input, + format, + output, + } = args; + + let dict = ctx + .reader + .read_from_path_or_alias_with_manager(input, &ctx.alias_manager)? + .to_dictionary()?; + + let contents = match format { + DumpFormat::XML => dict.to_xml(true)?, + DumpFormat::SQLite => dict.to_sql(SQLDialect::SQLite)?, + DumpFormat::Postgres => dict.to_sql(SQLDialect::Postgres)?, + DumpFormat::MySQL => dict.to_sql(SQLDialect::MySQL)?, + }; + + match output { + Some(out) => fs::write(&out, &contents)?, + None => ctx.println(contents), + }; + + Ok(()) +} diff --git a/cli/src/enums.rs b/cli/src/enums.rs new file mode 100644 index 00000000..bb927988 --- /dev/null +++ b/cli/src/enums.rs @@ -0,0 +1,39 @@ +use std::fmt::Display; + +use clap::ValueEnum; + +#[derive(Debug, Clone, ValueEnum)] +pub enum PrintFormat { + Print, + JSON, + XML, +} + +#[derive(Debug, Clone, ValueEnum)] +pub enum DumpFormat { + XML, + SQLite, + Postgres, + MySQL, +} + +impl Display for PrintFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PrintFormat::Print => write!(f, "print"), + PrintFormat::JSON => write!(f, "json"), + PrintFormat::XML => write!(f, "xml"), + } + } +} + +impl Display for DumpFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DumpFormat::XML => write!(f, "xml"), + DumpFormat::SQLite => write!(f, "sqlite"), + DumpFormat::Postgres => write!(f, "postgres"), + DumpFormat::MySQL => write!(f, "mysql"), + } + } +} diff --git a/cli/src/index.rs b/cli/src/index.rs new file mode 100644 index 00000000..93436e1c --- /dev/null +++ b/cli/src/index.rs @@ -0,0 +1,67 @@ +use std::{error::Error, path::PathBuf}; + +use clap::{arg, command, Args}; +use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; +use odict::search::{get_default_index_dir, IndexOptions}; + +use crate::CLIContext; + +pub(super) static DEFAULT_INDEX_MEMORY: usize = 15000000; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct IndexArgs { + /// Path to a compiled dictionary or an alias + #[arg(required = true)] + pub(super) dictionary: String, + + /// Custom directory to store the index + #[arg(short)] + pub(super) directory: Option, + + /// Whether to overwrite the index if it already exists + #[arg(short = 'f', default_value_t = false)] + pub(super) overwrite: bool, + + /// Memory arena per thread in bytes. Must be above 15MB. + #[arg(short, default_value_t = DEFAULT_INDEX_MEMORY)] + pub(super) memory: usize, +} + +pub fn index(ctx: &mut CLIContext, args: &IndexArgs) -> Result<(), Box> { + let file = ctx + .reader + .read_from_path_or_alias_with_manager(&args.dictionary, &ctx.alias_manager)?; + + ctx.println("".to_string()); + + let dict = file.to_dictionary()?; + + let progress1 = ProgressBar::new(dict.entries.len() as u64).with_style( + ProgressStyle::with_template("[{eta_precise}] {bar} {pos}/{len} entries indexed").unwrap(), + ); + + progress1.set_draw_target(ProgressDrawTarget::term(ctx.stdout.clone(), 20)); + + let progress2 = progress1.clone(); + + let options = IndexOptions::default() + .overwrite(args.overwrite) + .memory(args.memory) + .dir(args.directory.as_ref().unwrap_or(&get_default_index_dir())) + .on_item(move |_, _| { + progress2.inc(1); + }); + + dict.index(&options)?; + + progress1.finish(); + + ctx.println(format!( + "\n\nSuccessfully wrote index to {}", + options.dir.as_path().to_str().unwrap() + )); + + Ok(()) +} diff --git a/cli/src/info.rs b/cli/src/info.rs new file mode 100644 index 00000000..626ca4dc --- /dev/null +++ b/cli/src/info.rs @@ -0,0 +1,59 @@ +use std::error::Error; + +use crate::context::CLIContext; +use clap::{arg, command, Args}; +use console::Style; +use humansize::{format_size, DECIMAL}; +use num_format::{Locale, ToFormattedString}; +use odict::ArchivedOption; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct InfoArgs { + #[arg(required = true, help = "Path to a compiled dictionary")] + dictionary_path: String, +} + +pub fn info(ctx: &mut CLIContext, args: &InfoArgs) -> Result<(), Box> { + let InfoArgs { + dictionary_path: path, + } = args; + + let file = ctx + .reader + .read_from_path_or_alias_with_manager(&path, &ctx.alias_manager)?; + + let bold = Style::new().bold(); + let dict = file.to_archive()?; + + if let ArchivedOption::Some(name) = &dict.name { + ctx.println(format!( + "\n{}\n{}\n", + bold.apply_to(name), + "─".repeat(name.len()) + )); + } + + ctx.println(format!( + "{} {}", + bold.apply_to("File Version:"), + file.version + )); + + ctx.println(format!( + "{} {}", + bold.apply_to("File Size:"), + format_size(file.total_size, DECIMAL) + )); + + ctx.println(format!( + "{} {}", + bold.apply_to("Entries:"), + dict.entries.len().to_formatted_string(&Locale::en) + )); + + ctx.println(""); + + Ok(()) +} diff --git a/cli/src/lexicon.rs b/cli/src/lexicon.rs new file mode 100644 index 00000000..da695e83 --- /dev/null +++ b/cli/src/lexicon.rs @@ -0,0 +1,28 @@ +use std::error::Error; + +use clap::{arg, command, Args}; + +use crate::CLIContext; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct LexiconArgs { + #[arg(required = true, help = "Path to a compiled dictionary")] + dictionary: String, +} + +pub fn lexicon(ctx: &mut CLIContext, args: &LexiconArgs) -> Result<(), Box> { + let dict = ctx + .reader + .read_from_path_or_alias_with_manager(&args.dictionary, &ctx.alias_manager)? + .to_dictionary()?; + + let lexicon = dict.lexicon(); + + for word in lexicon { + ctx.println(word.to_string()); + } + + Ok(()) +} diff --git a/cli/src/lib.rs b/cli/src/lib.rs new file mode 100644 index 00000000..84f62b35 --- /dev/null +++ b/cli/src/lib.rs @@ -0,0 +1,32 @@ +mod alias; +mod cli; +mod compile; +mod context; +mod dump; +mod enums; +mod index; +mod info; +mod lexicon; +mod lookup; +mod merge; +mod new; +mod print; +mod search; +mod serve; +mod utils; + +pub use alias::*; +pub use cli::*; +pub use compile::*; +pub use context::*; +pub use dump::*; +pub use index::*; +pub use info::*; +pub use lexicon::*; +pub use lookup::*; +pub use merge::*; +pub use new::*; +pub use print::*; +pub use search::*; +pub use serve::*; +pub use utils::*; diff --git a/cli/src/lookup.rs b/cli/src/lookup.rs new file mode 100644 index 00000000..6fcab7b9 --- /dev/null +++ b/cli/src/lookup.rs @@ -0,0 +1,72 @@ +use std::error::Error; + +use crate::deserialize_nested_entries; +use crate::enums::PrintFormat; +use crate::{context::CLIContext, print_entries}; +use clap::{arg, command, Args}; +use odict::lookup::LookupOptions; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct LookupArgs { + #[arg(required = true, help = "Path to a compiled dictionary")] + dictionary_path: String, + + #[arg(required = true, help = "Words to look up")] + queries: Vec, + + #[arg( + short, + long, + value_enum, + default_value_t = PrintFormat::Print, + help = "Output format of the entries" + )] + format: PrintFormat, + + #[arg( + short = 'F', + long, + default_value_t = false, + help = "Follows all \"see also\" attributes (\"see\") until it finds a root term." + )] + follow: bool, + + #[arg( + short, + long, + default_value_t = 0, + help = "If a definition cannot be found, attempt to split the query into words of at least length S and look up each word separately. Can be relatively slow." + )] + split: usize, +} + +pub fn lookup(ctx: &mut CLIContext, args: &LookupArgs) -> Result<(), Box> { + let LookupArgs { + dictionary_path: path, + queries, + format, + follow, + split, + } = args; + + let file = ctx + .reader + .read_from_path_or_alias_with_manager(&path, &ctx.alias_manager)?; + + let result = file.to_archive()?.lookup( + queries, + &LookupOptions::default().follow(*follow).split(*split), + ); + + match result { + Ok(entries) => { + print_entries(ctx, deserialize_nested_entries(entries), format)?; + Ok(()) + } + Err(err) => { + return Err(err); + } + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 00000000..7ada4652 --- /dev/null +++ b/cli/src/main.rs @@ -0,0 +1,35 @@ +use std::io::Write; + +use clap::Parser; +use cli::{ + alias, compile, dump, index, info, lexicon, lookup, merge, new, search, serve, t, CLIContext, + Commands, CLI, +}; + +fn main() { + let cli = CLI::parse(); + let mut ctx = CLIContext::default(&cli); + + let result = t( + |c| match cli.command { + Commands::Alias(ref args) => alias(c, args), + Commands::Compile(ref args) => compile(c, args), + Commands::Dump(ref args) => dump(c, args), + Commands::Index(ref args) => index(c, args), + Commands::Lexicon(ref args) => lexicon(c, args), + Commands::Lookup(ref args) => lookup(c, args), + Commands::Merge(ref args) => merge(c, args), + Commands::New(ref args) => new(c, args), + Commands::Search(ref args) => search(c, args), + Commands::Serve(ref args) => serve(c, args), + Commands::Info(ref args) => info(c, args), + }, + &mut ctx, + ); + + if let Err(e) = result { + ctx.stderr + .write_all(format!("Error: {}", e).as_bytes()) + .unwrap(); + } +} diff --git a/cli/src/merge.rs b/cli/src/merge.rs new file mode 100644 index 00000000..ba72ff7e --- /dev/null +++ b/cli/src/merge.rs @@ -0,0 +1,46 @@ +use std::error::Error; + +use clap::{arg, command, Args}; + +use crate::CLIContext; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct MergeArgs { + #[arg( + required = true, + help = "Path of the dictionary to merge into (unless --output is specified)" + )] + destination: String, + + #[arg(required = true, help = "Paths of dictionaries to merge")] + sources: Vec, + + #[arg(short, long, help = "Separate output path for the compiled dictionary")] + output: Option, +} + +pub fn merge(ctx: &CLIContext, args: &MergeArgs) -> Result<(), Box> { + let mut dict = ctx + .reader + .read_from_path(&args.destination)? + .to_dictionary()?; + + for source in &args.sources { + let source_dict = ctx + .reader + .read_from_path_or_alias_with_manager(source, &ctx.alias_manager)? + .to_dictionary()?; + + dict.merge(&source_dict); + } + + if let Some(output) = &args.output { + ctx.writer.write_to_path(&dict, &output)?; + } else { + ctx.writer.write_to_path(&dict, &args.destination)?; + } + + Ok(()) +} diff --git a/cli/src/new.rs b/cli/src/new.rs new file mode 100644 index 00000000..a8dafb26 --- /dev/null +++ b/cli/src/new.rs @@ -0,0 +1,54 @@ +use std::{ + error::Error, + fs::{canonicalize, File}, + io::Write, + path::PathBuf, +}; + +use clap::{arg, command, Args}; + +use crate::CLIContext; + +#[derive(Debug, Args)] +#[command(args_conflicts_with_subcommands = true)] +#[command(flatten_help = true)] +pub struct NewArgs { + #[arg(required = true, help = "Name of your new dictionary file")] + file_name: String, + + #[arg(short, help = "Name attribute of the dictionary element")] + name: Option, +} + +pub fn new(ctx: &mut CLIContext, args: &NewArgs) -> Result<(), Box> { + let mut template = String::from( + " + +", + ); + + let output = PathBuf::from(format!("{}.xml", args.file_name)); + + if output.exists() { + return Err("\n🚫️ A file already exists with this name! Please choose another one.".into()); + } + + let mut file = File::create(&output)?; + + file.write_all(template.as_bytes())?; + + ctx.println(format!( + "\n✨ Created a new dictionary at {}!", + canonicalize(output)?.display() + )); + + Ok(()) +} diff --git a/cli/src/print/md.rs b/cli/src/print/md.rs new file mode 100644 index 00000000..5a779048 --- /dev/null +++ b/cli/src/print/md.rs @@ -0,0 +1,43 @@ +use console::Style; +use odict::{MDString, MarkdownStrategy}; +use pulldown_cmark::{Event, Parser, Tag}; + +pub fn print_md(md_string: &MDString) -> String { + let md = md_string.parse(MarkdownStrategy::Disabled); + let parser = Parser::new(&md); + let mut tags_stack = Vec::new(); + let mut buffer = String::new(); + + for event in parser { + match event { + Event::Start(tag) => { + tags_stack.push(tag); + } + Event::End(_) => { + tags_stack.pop(); + } + Event::Text(content) => { + let mut style = Style::new(); + + if tags_stack.contains(&Tag::Emphasis) { + style = style.italic(); + } + + if tags_stack.contains(&Tag::Strong) { + style = style.bold(); + } + + if tags_stack.contains(&Tag::Strikethrough) { + style = style.strikethrough(); + } + + buffer.push_str(&style.apply_to(&content).to_string()); + } + Event::Code(content) => buffer.push_str(&content), + Event::SoftBreak => buffer.push(' '), + _ => (), + } + } + + buffer.trim().to_string() +} diff --git a/cli/src/print/mod.rs b/cli/src/print/mod.rs new file mode 100644 index 00000000..ea415804 --- /dev/null +++ b/cli/src/print/mod.rs @@ -0,0 +1,5 @@ +mod md; +mod pprint; +mod print; + +pub use print::*; diff --git a/cli/src/print/pprint.rs b/cli/src/print/pprint.rs new file mode 100644 index 00000000..39507d54 --- /dev/null +++ b/cli/src/print/pprint.rs @@ -0,0 +1,236 @@ +use std::{borrow::Cow, error::Error, sync::LazyLock}; + +use console::{style, Style}; +use odict::{ + Definition, DefinitionType, Entry, Etymology, Example, Group, MarkdownStrategy, Note, Sense, +}; + +use crate::CLIContext; + +use super::md::print_md; + +const STYLE_POS: LazyLock