Skip to content

feat: injectable StringFormatter + Slugify (app-admin & api-core) + api-core DateFormatter - #5549

Open
adrians5j wants to merge 7 commits into
nextfrom
claude/formatters-next
Open

feat: injectable StringFormatter + Slugify (app-admin & api-core) + api-core DateFormatter#5549
adrians5j wants to merge 7 commits into
nextfrom
claude/formatters-next

Conversation

@adrians5j

@adrians5j adrians5j commented Aug 4, 2026

Copy link
Copy Markdown
Member

Injectable, decoratable formatting features on both admin and backend. Combines #5517 (admin) and #5526 (api-core), rebased from release/6.5.0 onto next.

Features

@webiny/app-admin

  • StringFormatter — consumer-facing string-transform API (parallel to the existing DateFormatter). Exposes slugify() today; methods grow over time.
  • Slugify — single-method (execute()) feature holding Webiny's canonical slug options; the fine-grained decorate seam behind StringFormatter.slugify().

@webiny/api-core

  • StringFormatter / Slugify — backend counterparts using api-core's @webiny/feature/api DI. No hooks (no React).
  • DateFormatter — deterministic absolute date/time formatting (UTC, YYYY-MM-DD HH:mm), decoratable. No viewer-locale dependence, unlike the admin side.

Consumers use StringFormatter; to change slug logic a project decorates Slugify alone — a smaller surface than decorating the whole formatter. The canonical slug options are a private detail of the default impl, so the contract stays independent of any specific slug library.

Override (per project) — decorate the fine-grained seam

const MySlugify = Slugify.createDecorator(() => {
    return {
        execute: value => {
            return value.trim().toLowerCase().replace(/\s+/g, "_");
        }
    };
});

container.registerDecorator(MySlugify);

Migrated

  • app-admin: RolesPresenter, ApiKeysPresenter, TeamsPresenter
  • app-aco: FolderTreePresenter, folder create dialog (useCreateDialog)
  • app-headless-cms: ModelGroupPresenter
  • api-headless-cms: CreateGroupRepository now injects StringFormatter instead of importing the toSlug util.
  • Dropped the now-unused slugify dependency from app-aco and app-headless-cms.

Left as-is on purpose

  • app-website-builder experiment toKey — strict machine-key transform ({ lower: true, strict: true }), not a display slug; kept as direct slugify for now (follow-up).
  • PagePath / pagePathFromTitle — pure value objects / exported utils with no DI seam.
  • @webiny/form useGenerateSlug — base-layer package that cannot depend on @webiny/app-admin.
  • contentModelGroup zod validation schema — pure schema factory with no DI seam; keeps using the toSlug util directly.

Docs

  • ai-context/core-features-reference.md — added StringFormatter / Slugify / DateFormatter.

TODO / follow-ups

  • Bring the app-website-builder experiment toKey into the feature system as its own StringFormatter method backed by its own fine-grained feature.

Notes

🤖 Generated with Claude Code

adrians5j and others added 3 commits August 4, 2026 16:04
…ings

The `slugify` npm package was imported directly across many admin presenters,
each repeating the same options object, so slug generation could drift and
projects had no supported way to override it.

Introduce two injectable, decoratable features in @webiny/app-admin:

- StringFormatter — the consumer-facing string-transform API (parallel to
  DateFormatter). Its methods will grow over time; for now it exposes slugify().
- Slugify — a small, single-method feature (execute()) holding Webiny's canonical
  slug options. StringFormatter.slugify() delegates to Slugify.execute().

Consumers use StringFormatter. To change slug logic, a project decorates Slugify
alone — a smaller surface than decorating the whole formatter. Both are
registered with the core admin features (always available); StringFormatter's
feature registers Slugify as its internal dependency.

- @webiny/app-admin: new features/stringFormatter + features/slugify, registered
  in Admin core and exported from the package root.
- Migrated the DI-connected, user-facing form-slug generators to StringFormatter:
  Roles/ApiKeys/Teams presenters (app-admin), FolderTreePresenter + folder create
  dialog (app-aco), ModelGroupPresenter (app-headless-cms). Dropped the now-unused
  slugify dependency from app-aco and app-headless-cms.
- Documented the injectable-formatter convention in AGENTS.md.

Left as-is on purpose: app-website-builder experiment `toKey` (internal keys must
stay stable regardless of project overrides), the pure PagePath /
pagePathFromTitle value utils (no DI seam, publicly exported), and
@webiny/form's useGenerateSlug (base layer, cannot depend on app-admin).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brings the same formatting utilities added on the admin side to the backend, so
server code gets the same injectable, decoratable formatting via api-core's DI.

- StringFormatter — consumer-facing string-transform API; exposes slugify()
  today, more methods later. Delegates to the fine-grained Slugify feature.
- Slugify — single-method feature (execute()) holding Webiny's canonical slug
  options; the decorate seam behind StringFormatter.slugify().
- DateFormatter — deterministic absolute date/time formatting (UTC), decoratable.
- All three register with ApiCoreFeature (always available) and are consumed by
  injecting the abstraction via a feature's `dependencies`.
- Migrated the DI-connected backend slug caller: CreateGroupRepository now injects
  StringFormatter instead of importing the toSlug util.
- Documented the new features in ai-context/core-features-reference.md.

Left as-is on purpose: the contentModelGroup zod validation schema keeps using
the toSlug util directly — it is a pure schema factory with no DI seam (mirrors
the admin-side pure-util exceptions).

Follows the admin-side PRs (#5512 DateFormatter, #5517 StringFormatter/Slugify).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adrians5j

Copy link
Copy Markdown
Member Author

/vitest

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Vitest tests have been initiated (for more information, click here). ✨

Group Status
No storage ❌ 0/57 passed
DDB ❌ 0/3 passed
DDB+OS ❌ 0/19 passed
SQL ❌ 0/10 passed
PGlite ❌ 0/10 passed
❌ Failed packages

DDB

  • api-aco
  • api-websockets
  • api-headless-cms (5/6)
  • api-headless-cms-aco

@adrians5j

Copy link
Copy Markdown
Member Author

/e2e

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Cypress E2E tests have been initiated (for more information, click here). ✨

Database Status Admin URL
DDB 🔄 Deploying... -
DDB+OS 🔄 Deploying... -

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant