Skip to content

docs: position combine for streamed parsing #97

docs: position combine for streamed parsing

docs: position combine for streamed parsing #97

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request: {}
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
quality:
runs-on: ubuntu-latest
outputs:
formatting: ${{ steps.formatting.outcome }}
lint: ${{ steps.lint.outcome }}
types: ${{ steps.types.outcome }}
tests: ${{ steps.tests.outcome }}
benchmark_verification: ${{ steps.benchmark_verification.outcome }}
package: ${{ steps.package.outcome }}
runtime: ${{ steps.runtime.outcome }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.0
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Check formatting
id: formatting
continue-on-error: true
run: bun run format:check
- name: Lint
id: lint
continue-on-error: true
run: bun run lint
- name: Type-check
id: types
continue-on-error: true
run: bun run typecheck
- name: Run tests
id: tests
continue-on-error: true
run: bun run test
- name: Verify benchmark correctness
id: benchmark_verification
continue-on-error: true
run: bun run bench:verify
- name: Verify npm package
id: package
continue-on-error: true
run: bun run package:check
- name: Verify Bun package runtime
id: runtime
continue-on-error: true
run: |
bun --eval '
import { parseAll, str } from "@claudiu-ceia/combine";
import { recognizeAt } from "@claudiu-ceia/combine/nondeterministic";
import { createTracer } from "@claudiu-ceia/combine/perf";
import { createStreamingParser } from "@claudiu-ceia/combine/streaming";
const result = parseAll(str("value"), "value");
if (!result.success || result.value !== "value") process.exit(1);
recognizeAt(str("value"));
createTracer();
createStreamingParser(str("value"));
'
- name: Enforce quality checks
if: always()
env:
FORMATTING: ${{ steps.formatting.outcome }}
LINT: ${{ steps.lint.outcome }}
TYPES: ${{ steps.types.outcome }}
TESTS: ${{ steps.tests.outcome }}
BENCHMARK_VERIFICATION: ${{ steps.benchmark_verification.outcome }}
PACKAGE: ${{ steps.package.outcome }}
RUNTIME: ${{ steps.runtime.outcome }}
run: |
for result in "$FORMATTING" "$LINT" "$TYPES" "$TESTS" "$BENCHMARK_VERIFICATION" "$PACKAGE" "$RUNTIME"; do
if [[ "$result" != "success" ]]; then
exit 1
fi
done
npm-compat:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 26]
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.0
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Build npm package
run: bun run build
- name: Verify Node package runtime
run: |
node --input-type=module <<'JS'
import { parseAll, str } from "@claudiu-ceia/combine";
import { recognizeAt } from "@claudiu-ceia/combine/nondeterministic";
import { createTracer } from "@claudiu-ceia/combine/perf";
import { createStreamingParser } from "@claudiu-ceia/combine/streaming";
const result = parseAll(str("value"), "value");
if (!result.success || result.value !== "value") process.exit(1);
recognizeAt(str("value"));
createTracer();
createStreamingParser(str("value"));
JS
jsr:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Deno
uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2
with:
deno-version: v2.x
- name: Verify package versions
run: |
deno eval --allow-read '
const packageVersion = JSON.parse(await Deno.readTextFile("package.json")).version;
const denoVersion = JSON.parse(await Deno.readTextFile("deno.json")).version;
if (packageVersion !== denoVersion) {
throw new Error("package.json version " + packageVersion + " does not match deno.json version " + denoVersion);
}
'
- name: Check and test with Deno
run: deno task check
- name: Verify Deno package runtime
run: |
deno eval '
import { parseAll, str } from "@claudiu-ceia/combine";
import { recognizeAt } from "@claudiu-ceia/combine/nondeterministic";
import { createTracer } from "@claudiu-ceia/combine/perf";
import { createStreamingParser } from "@claudiu-ceia/combine/streaming";
const result = parseAll(str("value"), "value");
if (!result.success || result.value !== "value") {
throw new Error("Deno package runtime check failed");
}
recognizeAt(str("value"));
createTracer();
createStreamingParser(str("value"));
'
- name: Verify JSR package
run: deno publish --dry-run
benchmark:
runs-on: ubuntu-latest
outputs:
performance: ${{ steps.performance.outcome }}
env:
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
steps:
- name: Checkout head revision
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
path: current
- name: Checkout base revision
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ env.BASE_SHA }}
path: baseline
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.0
- name: Install head dependencies
working-directory: current
run: bun install --frozen-lockfile
- name: Install base dependencies
working-directory: baseline
run: bun install --frozen-lockfile
- name: Compare benchmark performance
id: performance
continue-on-error: true
run: |
mkdir -p benchmark-results/base benchmark-results/head
trap 'test -f benchmark-results/report.md || printf "## Performance\n\nBenchmark execution failed. See the workflow logs.\n" > benchmark-results/report.md' ERR
for run in 1 2 3; do
(cd baseline && bun run bench:comparison:json) > "benchmark-results/base/${run}.json"
(cd current && bun run bench:comparison:json) > "benchmark-results/head/${run}.json"
done
bun run current/scripts/benchmark-report.ts \
--baseline benchmark-results/base \
--current benchmark-results/head \
--output benchmark-results/report.md \
--threshold 15
- name: Add benchmark job summary
if: always()
run: cat benchmark-results/report.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload benchmark report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: benchmark-report
path: benchmark-results/report.md
- name: Enforce benchmark result
if: always() && steps.performance.outcome != 'success'
run: exit 1
report:
if: always() && github.event_name == 'pull_request'
needs: [quality, npm-compat, jsr, benchmark]
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Download benchmark report
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: benchmark-report
path: benchmark-report
- name: Build CI summary
env:
FORMATTING: ${{ needs.quality.outputs.formatting }}
LINT: ${{ needs.quality.outputs.lint }}
TYPES: ${{ needs.quality.outputs.types }}
TESTS: ${{ needs.quality.outputs.tests }}
BENCHMARK_VERIFICATION: ${{ needs.quality.outputs.benchmark_verification }}
PACKAGE: ${{ needs.quality.outputs.package }}
RUNTIME: ${{ needs.quality.outputs.runtime }}
NPM_COMPAT: ${{ needs.npm-compat.result }}
JSR: ${{ needs.jsr.result }}
PERFORMANCE: ${{ needs.benchmark.outputs.performance }}
run: |
status() {
if [[ "$1" == "success" ]]; then
printf "Passed"
else
printf "Failed"
fi
}
{
printf "## CI results\n\n"
printf "| Check | Result |\n"
printf "| --- | :---: |\n"
printf "| Formatting | %s |\n" "$(status "$FORMATTING")"
printf "| Lint | %s |\n" "$(status "$LINT")"
printf "| Types | %s |\n" "$(status "$TYPES")"
printf "| Tests | %s |\n" "$(status "$TESTS")"
printf "| Benchmark correctness | %s |\n" "$(status "$BENCHMARK_VERIFICATION")"
printf "| Package | %s |\n" "$(status "$PACKAGE")"
printf "| Bun runtime | %s |\n" "$(status "$RUNTIME")"
printf "| Node 20/26 | %s |\n" "$(status "$NPM_COMPAT")"
printf "| Deno / JSR | %s |\n" "$(status "$JSR")"
printf "| Performance | %s |\n\n" "$(status "$PERFORMANCE")"
} > ci-report.md
if [[ -f benchmark-report/report.md ]]; then
cat benchmark-report/report.md >> ci-report.md
else
printf "## Performance\n\nNo benchmark report was produced.\n" >> ci-report.md
fi
cat ci-report.md >> "$GITHUB_STEP_SUMMARY"
- name: Post PR summary
if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]'
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
with:
header: ci-results
path: ci-report.md
skip_unchanged: true