Liking cljdoc? Tell your friends :D

wagoe.ai.core.parsing

Pure response-parsing functions for AI outputs.

FC/IS rule: no I/O here — receives raw AI response strings, returns parsed data or error maps.

Pure response-parsing functions for AI outputs.

FC/IS rule: no I/O here — receives raw AI response strings,
returns parsed data or error maps.
raw docstring

delimiter-balanceclj

(delimiter-balance source)

Count of still-open delimiters in source, or nil if they do not nest.

A generated namespace that hits the model's output limit is cut off mid-form — measured, one stopped at result (s — and writing that file produces EOF while reading rather than anything the caller can use. Counting open delimiters is the cheap, provider-free way to see it: a complete file ends at 0.

A count alone is not enough. (is (= 1 1]) nets to zero and is not readable, so the kind of each opener is tracked and a closer that does not match the innermost one is rejected. Depth-only, all three of (is (= 1 1]), ([)] and (deftest a (is [1 2)]) were reported complete.

Args: source - Clojure source string

Returns: Number of unclosed delimiters (0 means balanced), or nil when a closer appears with nothing open or with the wrong opener — which is damage rather than truncation, and equally unreadable.

Count of still-open delimiters in `source`, or nil if they do not nest.

A generated namespace that hits the model's output limit is cut off
mid-form — measured, one stopped at `result (s` — and writing that file
produces `EOF while reading` rather than anything the caller can use.
Counting open delimiters is the cheap, provider-free way to see it: a
complete file ends at 0.

A count alone is not enough. `(is (= 1 1])` nets to zero and is not
readable, so the kind of each opener is tracked and a closer that does not
match the innermost one is rejected. Depth-only, all three of `(is (= 1 1])`,
`([)]` and `(deftest a (is [1 2)])` were reported complete.

Args:
  source - Clojure source string

Returns:
  Number of unclosed delimiters (0 means balanced), or nil when a closer
  appears with nothing open or with the wrong opener — which is damage
  rather than truncation, and equally unreadable.
sourceraw docstring

ensure-standard-requiresclj

(ensure-standard-requires test-source)

Add :require entries for standard namespaces test-source uses but omits.

Only touches a namespace form that already has a :require clause; a generated test namespace always does, and synthesising one would mean guessing where it belongs.

Args: test-source - generated Clojure source string

Returns: The source with the missing requires added, or nil for nil input.

Add `:require` entries for standard namespaces `test-source` uses but omits.

Only touches a namespace form that already has a `:require` clause; a
generated test namespace always does, and synthesising one would mean
guessing where it belongs.

Args:
  test-source - generated Clojure source string

Returns:
  The source with the missing requires added, or nil for nil input.
sourceraw docstring

ensure-test-metadataclj

(ensure-test-metadata test-source test-type)

Tag every unmetadata'd deftest in test-source with ^:<test-type>.

Kaocha selects suites on this metadata, so a test namespace without it runs in no suite — present in the file, absent from every run. The system prompt asks the model for it; measured against two of the framework's own core namespaces, it produced 15 deftests and tagged none of them. The test type is already derived in Clojure by context/determine-test-type, so this is a fact the code knows and does not need to ask for.

A deftest that already carries metadata is left alone — the model may have tagged it more precisely than the path-based default, and a second tag would be noise at best.

Args: test-source - generated Clojure source string test-type - :unit, :integration or :contract

Returns: The source with metadata applied, or nil for nil input.

Tag every unmetadata'd `deftest` in `test-source` with `^:<test-type>`.

Kaocha selects suites on this metadata, so a test namespace without it runs
in no suite — present in the file, absent from every run. The system prompt
asks the model for it; measured against two of the framework's own core
namespaces, it produced 15 deftests and tagged none of them. The test type
is already derived in Clojure by `context/determine-test-type`, so this is a
fact the code knows and does not need to ask for.

A deftest that already carries metadata is left alone — the model may have
tagged it more precisely than the path-based default, and a second tag would
be noise at best.

Args:
  test-source - generated Clojure source string
  test-type   - :unit, :integration or :contract

Returns:
  The source with metadata applied, or nil for nil input.
sourceraw docstring

missing-standard-requiresclj

(missing-standard-requires test-source)

Standard namespaces test-source uses without requiring.

Two shapes, both measured against the framework's own namespaces: an alias use (str/join with no alias bound to str, which fails with No such namespace: str) and a fully qualified use (clojure.set/subset? with no require, which fails with ClassNotFoundException: clojure.set). They are checked separately because satisfying one does not satisfy the other — a namespace can be required under a different alias, and an alias can be bound to a different namespace.

Args: test-source - generated Clojure source string

Returns: Sorted seq of {:alias str :namespace str :aliased? bool}, empty when nothing is missing. :aliased? distinguishes the two shapes so the repair can add [ns :as alias] only where an alias is actually needed.

Standard namespaces `test-source` uses without requiring.

Two shapes, both measured against the framework's own namespaces: an alias
use (`str/join` with no alias bound to `str`, which fails with
`No such namespace: str`) and a fully qualified use
(`clojure.set/subset?` with no require, which fails with
`ClassNotFoundException: clojure.set`). They are checked separately because
satisfying one does not satisfy the other — a namespace can be required
under a different alias, and an alias can be bound to a different namespace.

Args:
  test-source - generated Clojure source string

Returns:
  Sorted seq of {:alias str :namespace str :aliased? bool}, empty when
  nothing is missing. `:aliased?` distinguishes the two shapes so the repair
  can add `[ns :as alias]` only where an alias is actually needed.
sourceraw docstring

module-spec->cli-argsclj

(module-spec->cli-args {:keys [module-name entity fields http web]})

Convert a parsed module spec map into CLI args for the scaffolder.

Args: spec - normalised module spec map from parse-module-spec

Returns: Vector of string args for wagoe.scaffolder.shell.cli-entry.

Convert a parsed module spec map into CLI args for the scaffolder.

Args:
  spec - normalised module spec map from parse-module-spec

Returns:
  Vector of string args for wagoe.scaffolder.shell.cli-entry.
sourceraw docstring

normalise-module-specclj

(normalise-module-spec module-spec)

Normalise a provider-parsed module spec map into canonical scaffolder shape.

Args: module-spec - map parsed from provider JSON mode

Returns: Normalised map with keyword keys and validated field specs, or {:error str} on failure.

Normalise a provider-parsed module spec map into canonical scaffolder shape.

Args:
  module-spec - map parsed from provider JSON mode

Returns:
  Normalised map with keyword keys and validated field specs,
  or {:error str} on failure.
sourceraw docstring

parse-generated-testsclj

(parse-generated-tests response-text)

Extract Clojure test code from an AI response.

The AI should return raw Clojure, but may wrap in code fences.

Args: response-text - raw AI response string

Returns: Clean Clojure source string.

Extract Clojure test code from an AI response.

The AI should return raw Clojure, but may wrap in code fences.

Args:
  response-text - raw AI response string

Returns:
  Clean Clojure source string.
sourceraw docstring

parse-json-responseclj

(parse-json-response text)

Parse a JSON string from an AI response.

Handles responses that may include markdown code fences or leading text.

Args: text - raw AI response string

Returns: Parsed map on success, {:error str :raw text} on failure.

Parse a JSON string from an AI response.

Handles responses that may include markdown code fences or leading text.

Args:
  text - raw AI response string

Returns:
  Parsed map on success, {:error str :raw text} on failure.
sourceraw docstring

parse-module-specclj

(parse-module-spec response-text)

Parse an AI-generated module specification JSON into a normalised map.

Expected AI output shape: {"module-name": "product", "entity": "Product", "fields": [{"name": "price", "type": "decimal", "required": true}], "http": true, "web": true}

Returns: Normalised map with keyword keys and validated field specs, or {:error str} on failure.

Parse an AI-generated module specification JSON into a normalised map.

Expected AI output shape:
{"module-name": "product", "entity": "Product",
 "fields": [{"name": "price", "type": "decimal", "required": true}],
 "http": true, "web": true}

Returns:
  Normalised map with keyword keys and validated field specs,
  or {:error str} on failure.
sourceraw docstring

parse-sql-responseclj

(parse-sql-response response-text)

Parse an AI-generated SQL copilot response.

Expected AI output: {"honeysql": "...", "explanation": "...", "raw-sql": "..."}

Returns: Map with :honeysql :explanation :raw-sql, or {:error str} on failure.

Parse an AI-generated SQL copilot response.

Expected AI output:
{"honeysql": "...", "explanation": "...", "raw-sql": "..."}

Returns:
  Map with :honeysql :explanation :raw-sql,
  or {:error str} on failure.
sourceraw docstring

require-clauseclj

(require-clause source)

The text of the namespace form's :require clause, or nil.

Whether a namespace is required cannot be answered by searching the whole file: clojure.set/subset? in a test body contains the text clojure.set, so a whole-file search calls it required and the file then dies at load with ClassNotFoundException: clojure.set. Measured — that is exactly how a generated namespace failed.

Args: source - Clojure source string

Returns: Substring covering (:require ...) inclusive, or nil when there is none.

The text of the namespace form's `:require` clause, or nil.

Whether a namespace is required cannot be answered by searching the whole
file: `clojure.set/subset?` in a test body contains the text `clojure.set`,
so a whole-file search calls it required and the file then dies at load with
`ClassNotFoundException: clojure.set`. Measured — that is exactly how a
generated namespace failed.

Args:
  source - Clojure source string

Returns:
  Substring covering `(:require ...)` inclusive, or nil when there is none.
sourceraw docstring

standard-aliasesclj

Aliases the generator uses in test bodies but routinely forgets to require.

Restricted to clojure.* namespaces with one conventional alias each, because the repair below infers the namespace from the alias — which is only sound where the mapping is unambiguous. An alias outside this map is left to fail at compile time rather than guessed at.

Aliases the generator uses in test bodies but routinely forgets to require.

Restricted to clojure.* namespaces with one conventional alias each, because
the repair below infers the namespace from the alias — which is only sound
where the mapping is unambiguous. An alias outside this map is left to fail
at compile time rather than guessed at.
sourceraw docstring

strip-noncodeclj

(strip-noncode source)

source with string, regex, character-literal and comment content blanked.

Both checks below need to reason about structure, and both were wrong without this: a ( inside a docstring is not an open paren, and an edn/read inside a test's string literal is not a use of the edn alias. The second was measured — a generated namespace that merely quoted (edn/read d) in a test string had [clojure.edn :as edn] added to its requires, which clj-kondo then flags as unused.

Blanked, not removed: offsets and line structure are preserved, so a caller can still relate a position back to the original.

wagoe.tools.parsing/strip-comments-and-strings does the same job for the quality gates. It is not shared: libs/tools is Babashka-only and declares no Wagoe dependency, libs/ai declares none either, and a common home would mean one of them taking on the other's dependency tree. Two small copies beat that, but they are copies — a fix here is worth checking against there.

Args: source - Clojure source string

Returns: Source of the same length with non-code characters replaced by spaces (newlines kept), or nil for nil input.

`source` with string, regex, character-literal and comment content blanked.

Both checks below need to reason about structure, and both were wrong
without this: a `(` inside a docstring is not an open paren, and an
`edn/read` inside a test's string literal is not a use of the `edn` alias.
The second was measured — a generated namespace that merely *quoted*
`(edn/read d)` in a test string had `[clojure.edn :as edn]` added to its
requires, which clj-kondo then flags as unused.

Blanked, not removed: offsets and line structure are preserved, so a caller
can still relate a position back to the original.

`wagoe.tools.parsing/strip-comments-and-strings` does the same job for the
quality gates. It is not shared: libs/tools is Babashka-only and declares no
Wagoe dependency, libs/ai declares none either, and a common home would mean
one of them taking on the other's dependency tree. Two small copies beat
that, but they are copies — a fix here is worth checking against there.

Args:
  source - Clojure source string

Returns:
  Source of the same length with non-code characters replaced by spaces
  (newlines kept), or nil for nil input.
sourceraw docstring

truncated?clj

(truncated? source)

Whether source looks cut off mid-form rather than complete.

Args: source - Clojure source string

Returns: true when delimiters are left open (or a stray closer appears).

Whether `source` looks cut off mid-form rather than complete.

Args:
  source - Clojure source string

Returns:
  true when delimiters are left open (or a stray closer appears).
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close