Skip to content

chore: migrate from cli-style to the shared style configs - #1765

Merged
kabaros merged 8 commits into
masterfrom
chore/migrate-to-style-configs
Sep 15, 2026
Merged

kabaros merged 8 commits into
masterfrom
chore/migrate-to-style-configs

Conversation

@HendrikThePendric

@HendrikThePendric HendrikThePendric commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Implements: N/A — follow-up to the style-configs rollout (LIBS-614)

Description

Replaces @dhis2/cli-style with @dhis2/config-eslint/react and @dhis2/config-prettier from
dhis2/style-configs. That carries eslint 7 → 9 and flat
config
and prettier 2 → 3, and takes eslint 7, husky 7, commitlint 12 and ls-lint out of the
dependency tree.

cli-style is being phased out by the extensibility team. Its commitlint, ls-lint and stylelint
configs are still in progress upstream, so commitlint is inlined locally here — as in
event-visualizer-app#336.

Two commits are formatting only and can be skipped: style: reflow markdown list markers
(45 files) and style: reformat code (18 files). The other six touch 26 files.


Implementation choices

Four rules the shared config leaves off are enabled here, keeping what cli-style did:

  • import/extensions — the JS packages publish ESM, where Node does no extension guessing, so
    relative imports need .js. TS sources are the inverse (never), since TypeScript resolves
    extensionless.
  • import/no-unresolved — off upstream over a resolver issue this repo does not hit.
  • react/react-in-jsx-scope + react/jsx-uses-react — off upstream via jsx-runtime.
    @dhis2/cli-app-scripts runs @babel/preset-react in classic mode, so JSX compiles to
    React.createElement and a missing import fails at runtime rather than at build time. The second
    rule stops no-unused-vars flagging the import the first one requires.

The shared config's ignores are app-shaped as well (./*.js, and src/-scoped globs that never
match components/*/src), so this repo's list replaces them and re-includes the root config files.

Other points to take note of:

  • The 62 hand-written .d.ts files stay unlinted, as before this PR. Linting them costs ~350
    errors, 277 of them react/no-unused-prop-types reading type declarations as components.
  • react/no-object-type-as-default-prop and react-hooks/static-components are off for stories
    only — both concern re-render churn in shipped components.
  • eslint stays on 9: eslint-plugin-import and eslint-plugin-react do not support 10 yet
    (#3230,
    #3979).
  • @commitlint/cli is on v20 rather than v21, which needs node ≥ 22.12.
  • Node is pinned to 24.x rather than lts/*, so node 26 becoming LTS on 2026-10-28 does not move
    CI on its own.
  • Prettier 3 sets markdown list-marker spacing at one space and exposes no option for it, hence the
    45-file commit.

New mechanisms

  • commitlint.config.mjs at the root. Both commit jobs used to require @dhis2/cli-style at
    runtime to locate their config. .mjs is the filename both actions look for by default, so that
    lookup step is gone rather than moved. lint-pr-title also replaces
    pull-request-name-linter-action, pinned to the removed node12 runtime, with commitlint reading
    the title from env: — it is untrusted input.
  • Plain git hooks. They sourced a husky shim that never existed here: nothing installs it and
    core.hooksPath is unset, so neither has run on a fresh clone. They are dependency-free now.
  • yarn lint is eslint . && prettier --check ., and format the equivalent, replacing the
    four d2-style scripts. build-world.sh formats build output directly.

Behaviour changes

  • Prettier now also covers .css/.scss, which d2-style's *.{md,json,yml,html} pattern did
    not. One file was reformatted.
  • eslint.config.mjs is linted; the shared config ignores eslint.config* by default.
  • Node 20 reached end of life on 2026-04-30, so node-version: 20.x pinned every job to an
    unsupported runtime. Moving also satisfies @eslint/core and eslint-visitor-keys, which want
    ^20.19.0 || ^22.13.0 || >=24.
  • The @typescript-eslint/parser pin and the typescript ~5.5.4 ceiling added in feat: support writing components in TypeScript, with a placeholder OuTree #1764 are gone.
    typescript-eslint v8 supersedes both, and disables no-undef, no-redeclare and
    no-dupe-class-members for .ts/.tsx — the set that was being worked around there.

Known issues

None.


Checklist

  • API docs are generated — unchanged; build:api runs clean
  • Tests were added — none needed; the existing 976 pass
  • Storybook demos were added — n/a

Verification

All green: yarn lint (0 errors; the 10 remaining warnings are pre-existing
react-hooks/exhaustive-deps), CI=true yarn lint, which adds import/no-cycle and
import/no-self-import, yarn typecheck on TypeScript 5.9.3, yarn test (126 suites, 976
passed), and build:lib + build:api + the storybook build. CI passes too, including all seven
e2e shards.

Commitlint was checked differentially: across 150 commits of master, v20 and the v12 cli-style
bundles accept and reject the same set.

🤖 Generated with Claude Code

@dhis2-bot

Copy link
Copy Markdown
Contributor

🚀 Deployed on https://pr-1765--dhis2-ui.netlify.app

@dhis2-bot
dhis2-bot temporarily deployed to netlify September 14, 2026 15:29 Inactive
@HendrikThePendric
HendrikThePendric force-pushed the chore/migrate-to-style-configs branch from 8ff8680 to 91437da Compare September 15, 2026 09:34
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 15, 2026 09:37 Inactive
Base automatically changed from chore/add-claude-and-ts-support to master September 15, 2026 09:47
@HendrikThePendric
HendrikThePendric force-pushed the chore/migrate-to-style-configs branch from 91437da to b0743c5 Compare September 15, 2026 09:56
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 15, 2026 09:59 Inactive
@HendrikThePendric
HendrikThePendric force-pushed the chore/migrate-to-style-configs branch from b0743c5 to a4355be Compare September 15, 2026 10:02
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 15, 2026 10:04 Inactive
@HendrikThePendric
HendrikThePendric force-pushed the chore/migrate-to-style-configs branch from a4355be to 1a10641 Compare September 15, 2026 10:32
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 15, 2026 10:35 Inactive
@HendrikThePendric
HendrikThePendric force-pushed the chore/migrate-to-style-configs branch from 1a10641 to 42d2fb6 Compare September 15, 2026 11:27
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 15, 2026 11:30 Inactive
HendrikThePendric and others added 8 commits September 15, 2026 13:35
Replaces the `@dhis2/cli-style` eslint and prettier configs with
`@dhis2/config-eslint/react` and `@dhis2/config-prettier`, which means
eslint 7 -> 9 and flat config, and prettier 2 -> 3.

The shared eslint config is written for single-package apps, so this
repo re-opens the paths it ignores (`./*.js`, and `src/`-scoped globs
that never match `components/*/src`) and re-enables four rules it drops:
`import/extensions`, `import/no-unresolved`, and the two React-in-scope
rules, which matter here because cli-app-scripts still builds JSX with
babel's classic runtime.

The ignore lists grow because `d2-style` applied a hardcoded blacklist
on top of them: build output, CHANGELOG.md and the generated icon
sources were never passed to either tool, and now have to be named.

`yarn lint` is red after this commit: prettier 3 reformats 66 files and
the new eslint rules report 21 errors. The next two commits clear them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Prettier 2 padded a list marker out to the tab width (`-   item`);
prettier 3 always uses a single space (`- item`). There is no option
for it: `tabWidth` still controls the indentation of nested items, but
the space after the marker is fixed.

Nothing but whitespace changes here, in its own commit so it can be
skipped rather than read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Template literals holding css break differently, `es5` trailing commas
now reach typescript type parameter lists, and call arguments hug
differently when a single argument is itself a call.

No content changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Most of the 21 errors come from three rules the old config did not
have. Two of them are about re-render churn, so they are switched off
for stories, which are fixtures rather than shipped components.

The rest are fixed where they are:

- hoist the object, array and function defaults in SimpleSingleSelect
  and MultiSelectFieldFF, so they keep one identity across renders
- build the debounced refetch in SharingAutocomplete with `useMemo`
  instead of wrapping an already-built one in `useCallback`, which
  created and discarded a debounce on every render
- drop the unused catch bindings in the api doc generator, leaving the
  three that actually log the error alone
- render `null` as the empty child of a Node story, rather than an
  expression that is constant
- delete an `eslint-enable` with no matching `eslint-disable`

One is suppressed with a reason: a named export that static analysis
cannot see behind a CommonJS shim.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`@typescript-eslint/parser` was pinned to 7.18 because it was the last
release supporting eslint 8, and `typescript` was pinned below 5.6 to
stay inside that parser's supported range. `@dhis2/config-eslint`
brings its own parser on the v8 line, so neither pin has anything left
to hold: the direct dependency goes, and typescript moves to 5.9.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both commit-linting jobs resolved their config by requiring
`@dhis2/cli-style` at runtime, which is the last thing in CI that
depends on the package. A root `commitlint.config.mjs` replaces it, and
because it is the filename both actions already look for, the lookup
step goes away rather than moving.

The pull request title job drops `pull-request-name-linter-action`,
which is pinned to the long-removed node12 runtime, in favour of
piping the title into commitlint directly. The title is untrusted, so
it goes through the environment instead of being interpolated into the
shell.

Verified against 150 commits of master: commitlint 20 and the 12 that
cli-style bundles accept and reject exactly the same set.

The hooks lose the husky shim they sourced, which never existed here --
nothing installs it, `core.hooksPath` is unset, and so neither hook has
ever run on a fresh clone. They are left working for anyone who points
git at them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing resolves through it any more. Its remaining pieces were either
already standalone or dead: `.editorconfig` and the github templates
are plain files it copied in once and never read again, and the ls-lint
check it ran on every invocation was a no-op without a `.ls-lint.yml`.

Removing it also takes eslint 7, husky 7, commitlint 12 and ls-lint out
of the dependency tree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Node 20 reached end of life on 2026-04-30, so `20.x` pinned every job
to an unsupported runtime. Node 24 is the active lts until 2026-10-20
and in maintenance until 2028-04-30.

This also settles an engine mismatch the eslint 9 upgrade introduced:
`@eslint/core` and `eslint-visitor-keys` declare
`^20.19.0 || ^22.13.0 || >=24`, which the last node 20 releases satisfy
but earlier ones do not.

Pinned to `24.x` rather than `lts/*` deliberately: node 26 becomes lts
on 2026-10-28, and a runtime should move because someone decided it
should, not because a date passed.

Verified on node 24: lint, typecheck, the full test suite, build:lib,
build:api, the storybook build and `yarn setup`. No package in the
installed tree declares an engine range that excludes node 24.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@HendrikThePendric
HendrikThePendric force-pushed the chore/migrate-to-style-configs branch from 42d2fb6 to ecd4df6 Compare September 15, 2026 11:36
@sonarqubecloud

Copy link
Copy Markdown

@dhis2-bot
dhis2-bot temporarily deployed to netlify September 15, 2026 11:39 Inactive
@HendrikThePendric
HendrikThePendric marked this pull request as ready for review September 15, 2026 12:02
@HendrikThePendric
HendrikThePendric requested a review from a team as a code owner September 15, 2026 12:02
@HendrikThePendric HendrikThePendric self-assigned this Sep 15, 2026
Comment thread .hooks/pre-commit
set -e

yarn d2-style check --staged
staged_files_without_deletions() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I normally use lint-staged here .. maybe we could discuss what approach to take in general and standardise, but happy with this if it works

@kabaros
kabaros merged commit 20f16e7 into master Sep 15, 2026
27 checks passed
@kabaros
kabaros deleted the chore/migrate-to-style-configs branch September 15, 2026 13:47
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.

3 participants