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

code-blocksclj

(code-blocks text)

The fenced blocks in text, in order, as {:info str :body str}.

Fences start a line, as in Markdown. A closer is a bare ``` outside a string literal, so a fence quoted inside a generated test does not end the block. A block the output limit cut off runs to the end of the text.

The fenced blocks in `text`, in order, as {:info str :body str}.

Fences start a line, as in Markdown. A closer is a bare ``` outside a string
literal, so a fence quoted inside a generated test does not end the block.
A block the output limit cut off runs to the end of the text.
sourceraw 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

io-namespacesclj

Namespace prefixes whose calls reach a database, a file, a process or the network. A test calling one does real I/O.

Namespace prefixes whose calls reach a database, a file, a process or the
network. A test calling one does real I/O.
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 public-api]})

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

normalise-setup-specclj

(normalise-setup-spec data)

The seven setup choices, with a default for every one the provider omitted.

Keys are read in both forms. parse-json-response keywordizes, and the caller read string keys, so every answer fell through to its default — the description reached the provider, came back parsed, and was then thrown away (BOU-401). Returns string keys: this is written straight out as JSON.

The database default is sqlite, not postgresql: an absent choice must still yield a project that boots without a database server (BOU-228).

The seven setup choices, with a default for every one the provider omitted.

Keys are read in both forms. `parse-json-response` keywordizes, and the
caller read string keys, so every answer fell through to its default — the
description reached the provider, came back parsed, and was then thrown away
(BOU-401). Returns string keys: this is written straight out as JSON.

The database default is sqlite, not postgresql: an absent choice must still
yield a project that boots without a database server (BOU-228).
sourceraw docstring

parse-admin-entityclj

(parse-admin-entity response-text)

Parse an admin entity EDN answer.

Returns: {:text edn-string :entity-name str :value map}, where :text is the EDN without fence or prose, or {:error str :raw-text str} naming what was actually wrong.

Parse an admin entity EDN answer.

Returns:
  {:text edn-string :entity-name str :value map}, where :text is the EDN
  without fence or prose, or {:error str :raw-text str} naming what was
  actually wrong.
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, one entity or several (BOU-497): {"module-name": "billing", "entities": [{"name": "Invoice", "fields": [...]}, {"name": "InvoiceLineItem", "belongs-to": "Invoice", "fields": [...]}], "http": true, "web": true, "public-api": false}

The older singular shape — entity plus fields — is still read.

Returns: {:module-name :entities [{:name :fields :belongs-to? :min? :workflow?}] :http :web :public-api}, plus :entity and :fields for the first entity, or {:error str} on failure.

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

Expected AI output shape, one entity or several (BOU-497):
{"module-name": "billing",
 "entities": [{"name": "Invoice", "fields": [...]},
               {"name": "InvoiceLineItem", "belongs-to": "Invoice",
                "fields": [...]}],
 "http": true, "web": true, "public-api": false}

The older singular shape — `entity` plus `fields` — is still read.

Returns:
  {:module-name :entities [{:name :fields :belongs-to? :min? :workflow?}] :http :web :public-api}, plus
  :entity and :fields for the first entity, 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-code-fenceclj

(strip-code-fence text)
(strip-code-fence text langs)

The code in text without fences or the prose around them. Text with no fence is returned trimmed.

With langs, the blocks tagged with one of them are joined, so an answer split over two clojure blocks stays whole and abash example ahead of the ```json one is skipped. Failing that, untagged blocks, then the first.

Every parser here reads through this. Each used to strip its own fence — json in one,clojure in another — and an ```edn answer from the admin-entity generator matched neither (BOU-493).

The code in `text` without fences or the prose around them. Text with no
fence is returned trimmed.

With `langs`, the blocks tagged with one of them are joined, so an answer
split over two ```clojure blocks stays whole and a ```bash example ahead of
the ```json one is skipped. Failing that, untagged blocks, then the first.

Every parser here reads through this. Each used to strip its own fence —
```json in one, ```clojure in another — and an ```edn answer from the
admin-entity generator matched neither (BOU-493).
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

tag-testsclj

(tag-tests test-source test-type)

Give every deftest in test-source exactly one pyramid tag, from what it touches: ^:integration (^:contract for an adapter's test-type) when it does real I/O, directly or through a helper or fixture in the file, and ^:unit otherwise. Kaocha selects suites on the tag. The model's own tag is replaced: rc-4 tagged reify-only tests ^:integration because the source sat under shell/ (BOU-572). Other metadata is kept.

Returns the source, or nil for nil input.

Give every deftest in `test-source` exactly one pyramid tag, from what it
touches: ^:integration (^:contract for an adapter's `test-type`) when it
does real I/O, directly or through a helper or fixture in the file, and
^:unit otherwise. Kaocha selects suites on the tag. The model's own tag is
replaced: rc-4 tagged reify-only tests ^:integration because the source sat
under shell/ (BOU-572). Other metadata is kept.

Returns the source, 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