Pure functions for generating file content from templates.
Each generator function takes a template context and returns file content as a string. All functions are pure and deterministic.
Pure functions for generating file content from templates. Each generator function takes a template context and returns file content as a string. All functions are pure and deterministic.
(add-admin-entity source plural)config.edn source with the entity plural in the admin's :allowlist and
its file in :entities.
{:status :updated :content s}, :present, :no-admin, or
{:status :unrecognised :reason s} for an :entities that is not a #merge.
Pure: true
config.edn `source` with the entity `plural` in the admin's :allowlist and
its file in :entities.
{:status :updated :content s}, :present, :no-admin, or
{:status :unrecognised :reason s} for an :entities that is not a `#merge`.
Pure: true(add-admin-has-many source parent-plural child)The admin entity file source of parent-plural with an editable
:has-many for child. {:status :updated :content s}, :present, or
{:status :unrecognised :reason s}.
Pure: true
The admin entity file `source` of `parent-plural` with an editable
`:has-many` for `child`. {:status :updated :content s}, :present, or
{:status :unrecognised :reason s}.
Pure: true(add-admin-has-many-field source parent-plural child-plural field)The admin entity file source of parent-plural with field in the
:fields of its :has-many for child-plural: when it lists fewer than
the four the scaffolder writes, or the field is required, since the admin
creates the children from these (BOU-578). {:status :updated :content s},
:unchanged, or {:status :unrecognised :reason s}.
Pure: true
The admin entity file `source` of `parent-plural` with `field` in the
`:fields` of its `:has-many` for `child-plural`: when it lists fewer than
the four the scaffolder writes, or the field is required, since the admin
creates the children from these (BOU-578). {:status :updated :content s},
:unchanged, or {:status :unrecognised :reason s}.
Pure: true(add-children-to-schema source parent child)source — a schema.clj — with child's entry in parent's Create
request, and in parent itself when that is the [:map ...] generate wrote.
{:content s} or {:error reason}.
Pure: true
`source` — a schema.clj — with `child`'s entry in `parent`'s Create
request, and in `parent` itself when that is the [:map ...] generate wrote.
{:content s} or {:error reason}.
Pure: true(add-entity-to-wiring source ctx entity)source — a module_wiring.clj — with entity wired in.
Returns {:content s} or {:error reason}. The first further entity also
installs the seam described above, and refuses when the routes init-key is
not the one generate wrote: replacing it would drop the edit.
Pure: true
`source` — a module_wiring.clj — with `entity` wired in.
Returns {:content s} or {:error reason}. The first further entity also
installs the seam described above, and refuses when the routes init-key is
not the one `generate` wrote: replacing it would drop the edit.
Pure: true(add-field-to-children-entry source plural field)source — a schema.clj — with field in the create entry the parent's
request has for the child plural, so a child created with its parent
takes it too (BOU-578), and in the rows the parent's GET shows (BOU-581).
{:status :inserted :content s :parent "Invoice"}, {:status :present}, or {:status :none} when no parent's create takes the child.
Pure: true
`source` — a schema.clj — with `field` in the create entry the parent's
request has for the child `plural`, so a child created with its parent
takes it too (BOU-578), and in the rows the parent's GET shows (BOU-581).
{:status :inserted :content s :parent "Invoice"}, {:status :present}, or
{:status :none} when no parent's create takes the child.
Pure: true(add-field-to-generated-test source field)source, a repository or workflow test generate wrote, with a value for
the required field in the row it creates. The NOT NULL column field --required adds otherwise fails the test on its first run (BOU-581).
{:content s}, or nil when the field needs nothing there or the test is not the shape generate wrote.
Pure: true
`source`, a repository or workflow test `generate` wrote, with a value for
the required `field` in the row it creates. The NOT NULL column `field
--required` adds otherwise fails the test on its first run (BOU-581).
{:content s}, or nil when the field needs nothing there or the test is not
the shape generate wrote.
Pure: true(add-field-to-schema source entity field)Add field to the entity and request schemas in source.
Returns {:status :updated :content <new source> :schemas [changed] :unreachable [names]} when at least one schema changed, or {:status :skipped :reason :already-present|:unrecognised-shape :unreachable [names]} when none did.
:unreachable names the target schemas the field could not be placed in. It
is what tells the caller that manual work remains, and it is reported on a
successful edit too — two of three schemas updated is still a schema set that
does not agree with itself.
All three targets are edited because that is what the tool has always told users to do: the instruction comment it used to print said to add the field to the entity schema and then to the Create and Update request schemas as well.
Each target is tracked separately. Deciding :already-present by searching
the whole file let one schema answer for the others — with the field in the
entity schema and a hand-restructured CreateXRequest, this reported that
nothing remained to be done while both request schemas still lacked it. That
is the unsynchronised Malli set of AGENTS.md pitfall 6, reported as success.
Add `field` to the entity and request schemas in `source`.
Returns {:status :updated :content <new source> :schemas [changed]
:unreachable [names]} when at least one schema changed, or
{:status :skipped :reason :already-present|:unrecognised-shape
:unreachable [names]} when none did.
`:unreachable` names the target schemas the field could not be placed in. It
is what tells the caller that manual work remains, and it is reported on a
successful edit too — two of three schemas updated is still a schema set that
does not agree with itself.
All three targets are edited because that is what the tool has always told
users to do: the instruction comment it used to print said to add the field
to the entity schema and then to the Create and Update request schemas as
well.
Each target is tracked separately. Deciding `:already-present` by searching
the whole file let one schema answer for the others — with the field in the
entity schema and a hand-restructured `CreateXRequest`, this reported that
nothing remained to be done while both request schemas still lacked it. That
is the unsynchronised Malli set of AGENTS.md pitfall 6, reported as success.(add-seed-examples source entities)resources/seeds/dev.edn with a commented example for each of entities
it does not mention yet, as {:content s :added [plural]}, or nil when there
is nothing to add. source is the file, or nil for a new one. What is in
the file stays as it is: the examples go inside its top-level vector or
map, or after it when its end cannot be found.
Pure: true
resources/seeds/dev.edn with a commented example for each of `entities`
it does not mention yet, as {:content s :added [plural]}, or nil when there
is nothing to add. `source` is the file, or nil for a new one. What is in
the file stays as it is: the examples go inside its top-level vector or
map, or after it when its end cannot be found.
Pure: true(add-subscriber-to-wiring source ctx sub)source — a module_wiring.clj — requiring the subscriber sub, so its
component is defined, with the seam that starts it installed first when
the module has none. {:content s} or {:error reason}.
Pure: true
`source` — a module_wiring.clj — requiring the subscriber `sub`, so its
component is defined, with the seam that starts it installed first when
the module has none. {:content s} or {:error reason}.
Pure: true(admin-active? source)Whether the config.edn source switches the admin UI on. A :wagoe/admin
that is not a literal map counts: it cannot be read without Aero.
Pure: true
Whether the config.edn `source` switches the admin UI on. A :wagoe/admin that is not a literal map counts: it cannot be read without Aero. Pure: true
(admin-display-fields field-names)The fields that stand for an entity on another's page: its first two own fields, not its keys or secrets.
Pure: true
The fields that stand for an entity on another's page: its first two own fields, not its keys or secrets. Pure: true
(admin-entity-file entity {:keys [children parent]})resources/conf/<profile>/admin/<plural>.edn for entity.
children are the entities that belong to it, each getting an editable
:has-many; parent is {:name "Invoice" :fields [...]} when it belongs
to one, for the banner on its pages. Deletes are hard, as the generated
API's are, so a child's ON DELETE CASCADE runs.
Pure: true
resources/conf/<profile>/admin/<plural>.edn for `entity`.
`children` are the entities that belong to it, each getting an editable
`:has-many`; `parent` is {:name "Invoice" :fields [...]} when it belongs
to one, for the banner on its pages. Deletes are hard, as the generated
API's are, so a child's ON DELETE CASCADE runs.
Pure: true(admin-has-many child)The editable :has-many entry a parent's admin config gets for child.
Pure: true
The editable `:has-many` entry a parent's admin config gets for `child`. Pure: true
(append-section source section)source with section after it, one blank line between.
Pure: true
`source` with `section` after it, one blank line between. Pure: true
(children-entry child)The entry the first entity's Create request gets for child, an entity
that belongs to it: its children, each with the child's create fields but
the parent's id, which the create fills in. Required, with at least :min of
them, when the child has a minimum (BOU-578).
Pure: true
The entry the first entity's Create request gets for `child`, an entity that belongs to it: its children, each with the child's create fields but the parent's id, which the create fills in. Required, with at least :min of them, when the child has a minimum (BOU-578). Pure: true
(children-response-entry child)The entry the first entity's own schema gets for child: the rows its GET
shows, under the key its create takes them (BOU-581). Optional: a list has
them only when asked.
Pure: true
The entry the first entity's own schema gets for `child`: the rows its GET shows, under the key its create takes them (BOU-581). Optional: a list has them only when asked. Pure: true
(defined-symbols source)Every top-level name source defines, protocol methods included, or nil
when it does not parse.
Pure: true
Every top-level name `source` defines, protocol methods included, or nil when it does not parse. Pure: true
(entity-files ctx entity migration-number)The files a further entity adds, as [{:path :content}]: core, service, persistence and http namespaces of its own, its migration pair and its tests. No http namespace when the module has no HTTP interface.
Pure: true
The files a further entity adds, as [{:path :content}]: core, service,
persistence and http namespaces of its own, its migration pair and its tests.
No http namespace when the module has no HTTP interface.
Pure: true(entity-ports-section entity)The ports.clj text a further entity appends: its repository and service protocols under one banner.
Pure: true
The ports.clj text a further entity appends: its repository and service protocols under one banner. Pure: true
(entity-schema-section entity-ctx)The schema.clj text a further entity appends: its entity, request and validation defs under one banner. Every name in it carries the entity's name, so it cannot collide with the defs already in the file.
Pure: true
The schema.clj text a further entity appends: its entity, request and validation defs under one banner. Every name in it carries the entity's name, so it cannot collide with the defs already in the file. Pure: true
(generate-adapter-file module-name port-name adapter-name methods & [base-ns])Generate a complete adapter implementation file.
Args: module-name - Module name (e.g., "cache") port-name - Port protocol name (e.g., "ICache") adapter-name - Adapter name (e.g., "redis") methods - Vector of method specs [{:name "get-value" :args ["key"]}] base-ns - Optional base namespace (default "wagoe")
Returns: String content for adapter.clj file
Pure: true
Generate a complete adapter implementation file.
Args:
module-name - Module name (e.g., "cache")
port-name - Port protocol name (e.g., "ICache")
adapter-name - Adapter name (e.g., "redis")
methods - Vector of method specs [{:name "get-value" :args ["key"]}]
base-ns - Optional base namespace (default "wagoe")
Returns:
String content for adapter.clj file
Pure: true(generate-add-field-migration _module-name entity-name field migration-number)Generate ALTER TABLE migration for adding a field.
Args: module-name - Module name entity-name - Entity name (PascalCase) field - Field definition map {:name :type :required :unique} migration-number - Migration sequence number (e.g., "006")
Returns: String content for migration SQL
Pure: true
Generate ALTER TABLE migration for adding a field.
Args:
module-name - Module name
entity-name - Entity name (PascalCase)
field - Field definition map {:name :type :required :unique}
migration-number - Migration sequence number (e.g., "006")
Returns:
String content for migration SQL
Pure: true(generate-add-field-schema-comment module-name entity-name field)Generate schema addition comment/instructions for adding a field.
Args: module-name - Module name entity-name - Entity name field - Field definition map
Returns: String with instructions for manual schema update
Pure: true
Generate schema addition comment/instructions for adding a field. Args: module-name - Module name entity-name - Entity name field - Field definition map Returns: String with instructions for manual schema update Pure: true
(generate-core-file ctx)(generate-core-file ctx entity)Generate core/{entity}.clj file content.
Args: ctx - Template context map
Returns: String content for core/{entity}.clj
Pure: true
Generate core/{entity}.clj file content.
Args:
ctx - Template context map
Returns:
String content for core/{entity}.clj
Pure: true(generate-core-test-file ctx)(generate-core-test-file ctx entity)Generate test core file content.
Args: ctx - Template context map
Returns: String content for core test file
Pure: true
Generate test core file content. Args: ctx - Template context map Returns: String content for core test file Pure: true
(generate-endpoint-definition module-name path method handler-name)Generate a single endpoint definition for adding to http.clj.
Args: module-name - Module name path - Route path (e.g., "/invoices/:id/send") method - HTTP method keyword (e.g., :post) handler-name - Handler function name (e.g., "send-invoice")
Returns: String content for endpoint definition (Reitit route data)
Pure: true
Generate a single endpoint definition for adding to http.clj. Args: module-name - Module name path - Route path (e.g., "/invoices/:id/send") method - HTTP method keyword (e.g., :post) handler-name - Handler function name (e.g., "send-invoice") Returns: String content for endpoint definition (Reitit route data) Pure: true
(generate-entity-http-file ctx entity)shell/<entity>_http.clj for a further entity: its CRUD API routes.
Pure: true
shell/<entity>_http.clj for a further entity: its CRUD API routes. Pure: true
(generate-field-schema field-ctx)(generate-field-schema field-ctx force-optional?)Generate Malli schema for a single field.
Args: field-ctx - Field context map
Returns: String representation of Malli schema
Pure: true
Generate Malli schema for a single field. Args: field-ctx - Field context map Returns: String representation of Malli schema Pure: true
(generate-http-file ctx)Generate shell/http.clj: the first entity's API and web routes, and the module's route contribution.
Pure: true
Generate shell/http.clj: the first entity's API and web routes, and the module's route contribution. Pure: true
(generate-migration-down-file ctx)(generate-migration-down-file _ctx entity)Generate the rollback SQL matching generate-migration-file.
migratus pairs <id>-<name>.up.sql with <id>-<name>.down.sql; without the
down file a migration cannot be rolled back. Dropping the table also removes
its index, so the index needs no separate statement.
Pure: true
Generate the rollback SQL matching `generate-migration-file`. migratus pairs `<id>-<name>.up.sql` with `<id>-<name>.down.sql`; without the down file a migration cannot be rolled back. Dropping the table also removes its index, so the index needs no separate statement. Pure: true
(generate-migration-field field-ctx)Generate SQL for a single field.
Args: field-ctx - Field context map
Returns: SQL field definition string
Pure: true
Generate SQL for a single field. Args: field-ctx - Field context map Returns: SQL field definition string Pure: true
(generate-migration-file ctx migration-number)(generate-migration-file _ctx entity migration-number)Generate migration SQL file content.
Args: ctx - Template context map migration-number - Migration sequence number (e.g., "005")
Returns: String content for migration SQL
Pure: true
Generate migration SQL file content. Args: ctx - Template context map migration-number - Migration sequence number (e.g., "005") Returns: String content for migration SQL Pure: true
(generate-module-wiring-file ctx)Generate shell/module_wiring.clj file content.
The scaffolder emitted every other file a module needs and not this one, so
bb scaffold integrate always reported that the module had no wiring yet and
the user hand-wrote the Integrant keys the framework says never to hand-write
(BOU-309). A first entity with a workflow gets the seam's ig-config at
once: it is what hands the service the workflow module.
Pure: true
Generate shell/module_wiring.clj file content. The scaffolder emitted every other file a module needs and not this one, so `bb scaffold integrate` always reported that the module had no wiring yet and the user hand-wrote the Integrant keys the framework says never to hand-write (BOU-309). A first entity with a workflow gets the seam's `ig-config` at once: it is what hands the service the workflow module. Pure: true
(generate-persistence-file ctx)(generate-persistence-file ctx entity)Generate shell/persistence.clj file content.
Args: ctx - Template context map
Returns: String content for persistence.clj file
Pure: true
Generate shell/persistence.clj file content. Args: ctx - Template context map Returns: String content for persistence.clj file Pure: true
(generate-persistence-test-file ctx)(generate-persistence-test-file ctx entity)Generate test persistence file content.
Args: ctx - Template context map
Returns: String content for persistence test file
Pure: true
Generate test persistence file content. Args: ctx - Template context map Returns: String content for persistence test file Pure: true
(generate-ports-file ctx)Generate ports.clj file content for the module's first entity.
Pure: true
Generate ports.clj file content for the module's first entity. Pure: true
(generate-schema-file ctx)Generate schema.clj file content for the module's first entity.
Pure: true
Generate schema.clj file content for the module's first entity. Pure: true
(generate-service-file ctx)(generate-service-file ctx entity)Generate shell/service.clj file content.
The first entity's service creates the entities that belong to it with it,
in one transaction: children, which the module wiring hands it, says
which (BOU-578).
Args: ctx - Template context map
Returns: String content for service.clj file
Pure: true
Generate shell/service.clj file content. The first entity's service creates the entities that belong to it with it, in one transaction: `children`, which the module wiring hands it, says which (BOU-578). Args: ctx - Template context map Returns: String content for service.clj file Pure: true
(generate-service-test-file ctx)(generate-service-test-file ctx entity)Generate test service file content.
Args: ctx - Template context map
Returns: String content for service test file
Pure: true
Generate test service file content. Args: ctx - Template context map Returns: String content for service test file Pure: true
(generate-subscriber-file {:keys [event topic entity key parent] :as sub})shell/<name>_subscriber.clj.
Pure: true
shell/<name>_subscriber.clj. Pure: true
(generate-subscriber-test-file {:keys [event topic entity key] :as sub})test/.../shell/<name>_subscriber_test.clj: the events it takes, and one
reaching handle through an in-memory bus.
Pure: true
test/.../shell/<name>_subscriber_test.clj: the events it takes, and one reaching `handle` through an in-memory bus. Pure: true
(generate-ui-file ctx)Generate core/ui.clj file content.
Args: ctx - Template context map
Returns: String content for ui.clj file
Pure: true
Generate core/ui.clj file content. Args: ctx - Template context map Returns: String content for ui.clj file Pure: true
(generate-web-handlers-file ctx)Generate shell/web_handlers.clj file content.
Args: ctx - Template context map
Returns: String content for web_handlers.clj file
Pure: true
Generate shell/web_handlers.clj file content. Args: ctx - Template context map Returns: String content for web_handlers.clj file Pure: true
(generate-workflow-file ctx entity)shell/<entity>_workflow.clj: the definition, its registration and the adapter the service drives it through.
Pure: true
shell/<entity>_workflow.clj: the definition, its registration and the adapter the service drives it through. Pure: true
(generate-workflow-test-file ctx entity)test/.../shell/<entity>_workflow_test.clj: the transitions, and the status following them through the service on H2.
Pure: true
test/.../shell/<entity>_workflow_test.clj: the transitions, and the status following them through the service on H2. Pure: true
(insert-schema-entry source schema-name entry)Add entry to the Malli map in (def schema-name …) within source.
Returns one of:
{:status :inserted :content <new source>} {:status :present :entry <the entry already there>} {:status :unrecognised} a shape this cannot place the field in safely
The last two are kept apart rather than collapsed into one falsey value: the caller has to distinguish nothing-to-do from could-not-do-it. Reporting the second as the first is how the request schemas ended up without the field while the output said the work was finished.
:present carries the entry that is already there, because its shape
matters — a required entry in an update request is not nothing-to-do.
:unrecognised covers a hand-edited file, a renamed schema, or a def whose
value is not a literal [:map …]. Refusing rather than guessing is
deliberate: a skip the user can see beats a mangled schema file they discover
later.
Everything outside the inserted entry round-trips byte for byte, including the trailing newline — rewrite-clj preserves whitespace and comments, so the diff is the one line added.
Add `entry` to the Malli map in `(def schema-name …)` within `source`.
Returns one of:
{:status :inserted :content <new source>}
{:status :present :entry <the entry already there>}
{:status :unrecognised} a shape this cannot place the field in safely
The last two are kept apart rather than collapsed into one falsey value: the
caller has to distinguish nothing-to-do from could-not-do-it. Reporting the
second as the first is how the request schemas ended up without the field
while the output said the work was finished.
`:present` carries the entry that is already there, because its shape
matters — a required entry in an update request is not nothing-to-do.
:unrecognised covers a hand-edited file, a renamed schema, or a `def` whose
value is not a literal `[:map …]`. Refusing rather than guessing is
deliberate: a skip the user can see beats a mangled schema file they discover
later.
Everything outside the inserted entry round-trips byte for byte, including
the trailing newline — rewrite-clj preserves whitespace and comments, so the
diff is the one line added.The most children one create takes. The admin's max-child-rows, which a
test holds this to: the scaffolder does not depend on the admin.
The most children one create takes. The admin's `max-child-rows`, which a test holds this to: the scaffolder does not depend on the admin.
(module-active? source k)Whether the config.edn source names module k under :active.
Pure: true
Whether the config.edn `source` names module `k` under :active. Pure: true
(schema-field-entry field)(schema-field-entry field force-optional?)The Malli entry line for field, without indentation.
Required fields are plain; optional ones carry {:optional true}, matching
what module generation emits for the same field definition.
force-optional? produces the optional form regardless. Update request
schemas take that one: an update is a partial, so a required entry there
means every existing caller doing a partial update has to start sending the
new field or fail validation. See libs/scaffolder/AGENTS.md, and
generate-field-schema, which applies the same rule at module generation.
The Malli entry line for `field`, without indentation.
Required fields are plain; optional ones carry `{:optional true}`, matching
what module generation emits for the same field definition.
`force-optional?` produces the optional form regardless. Update request
schemas take that one: an update is a partial, so a required entry there
means every existing caller doing a partial update has to start sending the
new field or fail validation. See `libs/scaffolder/AGENTS.md`, and
`generate-field-schema`, which applies the same rule at module generation.(schema-field-names source schema-name)The keys of the Malli map in (def schema-name …) within source, or nil.
Pure: true
The keys of the Malli map in `(def schema-name …)` within `source`, or nil. Pure: true
(sensitive-field? k)Whether a column holds a secret the admin must not show: the admin's own
hidden names (common-hidden-fields in wagoe.admin.core.schema-introspection)
and any name with a word that says so.
Pure: true
Whether a column holds a secret the admin must not show: the admin's own hidden names (`common-hidden-fields` in wagoe.admin.core.schema-introspection) and any name with a word that says so. Pure: true
(service-takes-children? source)Whether the service.clj source creates its entity with the entities that
belong to it (BOU-578). One generated before takes the repository alone.
Pure: true
Whether the service.clj `source` creates its entity with the entities that belong to it (BOU-578). One generated before takes the repository alone. Pure: true
What migratus splits a migration on. Without it the file is one statement: SQLite runs the first and drops the rest, and PostgreSQL's driver refuses it (BOU-569).
What migratus splits a migration on. Without it the file is one statement: SQLite runs the first and drops the rest, and PostgreSQL's driver refuses it (BOU-569).
(subscriber-context ctx event entity sub-name)What a subscriber is generated from: event a qualified keyword, entity
the payload's :entity it takes (nil for every one), and sub-name its name
(derived from the two when nil).
Pure: true
What a subscriber is generated from: `event` a qualified keyword, `entity` the payload's :entity it takes (nil for every one), and `sub-name` its name (derived from the two when nil). Pure: true
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |