/**
* `queryHref(base, { … })` → `bf.query(...)` lowering for the Jinja adapter
* (#2042). Ported from
* `packages/adapter-xslate/src/__tests__/query-href.test.ts`. Parity with
* the go-template / Xslate lowering: the call + object literal are
* structured IR, so it lowers directly. The shared `query` runtime helper
* (`barefootjs.runtime`) includes a pair iff its guard is truthy AND its
* value is a non-empty string, so a plain `key: v` passes guard `true` and a
* conditional `key: cond ? v : undefined` passes the lowered condition.
*/
import { describe, test, expect } from 'bun:test'
import { compileJSX, type ComponentIR } from '@barefootjs/jsx'
import { JinjaAdapter } from '../adapter/jinja-adapter'
function template(src: string): string {
const a = new JinjaAdapter()
const r = compileJSX(src.trimStart(), 'T.tsx', { adapter: a, outputIR: true })
const ir = JSON.parse(r.files.find(f => f.type === 'ir')!.content) as ComponentIR
return a.generate(ir).template
}
describe('queryHref → bf.query (Jinja, #2042)', () => {
test('a plain value passes guard true', () => {
const t = template(`
'use client'
import { queryHref } from '@barefootjs/client'
export function P(props: { base: string; tag: string }) {
return x
}
`)
expect(t).toContain("bf.query(base, 1, 'tag', tag)")
})
test('a conditional include passes the lowered condition as the guard', () => {
const t = template(`
'use client'
import { queryHref } from '@barefootjs/client'
export function P(props: { base: string; sort: string; tag: string }) {
return x
}
`)
// Jinja's `!=` handles string inequality directly (like Kolon's `!=`;
// unlike Perl's `ne`).
expect(t).toContain("bf.query(base, (sort != 'date'), 'sort', sort, 1, 'tag', tag)")
})
// A bare-value guard (`flag ? v : undefined`) is JS *string* truthiness —
// `'0'` is a truthy string in JS. The lowering must normalise it to a
// non-empty-string test so SSR matches the client / go (where
// `lowerUrlGuard` emits `ne ""`). Jinja renders the `!== ''` test
// as `!= ''` (its string inequality), matching the comparison guard above.
test('a bare-value guard is normalised to a non-empty-string test', () => {
const t = template(`
'use client'
import { queryHref } from '@barefootjs/client'
export function P(props: { base: string; flag: string; val: string }) {
return x
}
`)
expect(t).toContain("bf.query(base, (flag != ''), 'q', val)")
})
// An array value (`{ tag: props.tags }`) lowers to the bare receiver
// expression; the shared `query` runtime helper detects the list at
// runtime and appends one pair per non-empty member (#2048). No
// adapter-side change beyond passing the value through.
test('an array value passes the receiver expression for the helper to append', () => {
const t = template(`
'use client'
import { queryHref } from '@barefootjs/client'
export function P(props: { base: string; tags: string[] }) {
return x
}
`)
expect(t).toContain("bf.query(base, 1, 'tag', tags)")
})
test('an aliased import is recognised', () => {
const t = template(`
'use client'
import { queryHref as qh } from '@barefootjs/client'
export function P(props: { base: string; tag: string }) {
return x
}
`)
expect(t).toContain("bf.query(base, 1, 'tag', tag)")
})
test('a dynamic (non-literal) params object falls back (no bf.query)', () => {
const t = template(`
'use client'
import { queryHref } from '@barefootjs/client'
export function P(props: { base: string; q: Record }) {
return x
}
`)
expect(t).not.toContain('.query')
})
})