Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"name": "docusaurus-plugin-gitlab",

// Image ships with nvm preinstalled (default Node 20). We additionally install
// the other CI matrix versions so you can switch instantly, e.g. `nvm use 18`.
"image": "mcr.microsoft.com/devcontainers/javascript-node:20-bookworm",
// Image ships with nvm preinstalled (default Node 22). We additionally install
// the other CI matrix version so you can switch instantly, e.g. `nvm use 24`.
"image": "mcr.microsoft.com/devcontainers/javascript-node:22-bookworm",

// Install the full CI matrix (20 / 22 / 24) and keep 20 (the minimum) as default.
"onCreateCommand": "bash -c 'export NVM_DIR=/usr/local/share/nvm && . \"$NVM_DIR/nvm.sh\" && nvm install 20 && nvm install 22 && nvm install 24 && nvm alias default 20'",
// Install the full CI matrix (22 / 24) and keep 22 (the minimum) as default.
"onCreateCommand": "bash -c 'export NVM_DIR=/usr/local/share/nvm && . \"$NVM_DIR/nvm.sh\" && nvm install 22 && nvm install 24 && nvm alias default 22'",

// Install dependencies once the container is up.
"postCreateCommand": "npm ci",
// Activate the pinned pnpm (via corepack) and install the workspace.
"postCreateCommand": "corepack enable && pnpm install --frozen-lockfile",

// Docusaurus dev server (used by the example sites) listens here.
"forwardPorts": [3000],
Expand Down
31 changes: 14 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ jobs:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run typecheck
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run lint
- run: pnpm run typecheck

test:
runs-on: ubuntu-latest
Expand All @@ -33,24 +34,20 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [20, 22, 24]
node: [22, 24]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ matrix.node }}
cache: npm
cache-dependency-path: |
package-lock.json
examples/site/package-lock.json
- run: npm ci
- name: "Build package (needed by the example site file: link)"
run: npm run build
- name: Install example site deps
working-directory: examples/site
run: npm ci
cache: pnpm
- name: Install workspace deps (package + example sites)
run: pnpm install --frozen-lockfile
- name: Build package (needed by the example site workspace link)
run: pnpm run build
- name: Run tests (unit + e2e docusaurus build)
run: npm test
run: pnpm test

dependency-review:
if: github.event_name == 'pull_request'
Expand Down
11 changes: 7 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 20
node-version: 22
registry-url: https://registry.npmjs.org
cache: npm
cache: pnpm
- name: Use OIDC-capable npm
run: npm install -g npm@latest
- run: npm ci
- run: npm run build
- run: pnpm install --frozen-lockfile
- run: pnpm run build
# npm (not pnpm) publishes: OIDC trusted publishing is proven with the npm
# CLI, and publishing only needs the built dist/ — no pnpm layout involved.
- run: npm publish --provenance --access public
11 changes: 10 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,13 @@ if [ "$(git config --get commit.gpgsign)" != "true" ] || [ -z "$(git config --ge
exit 1
fi

npx lint-staged
# pnpm isn't always on the hook's PATH (GUI git clients, shells without mise
# activated) — prefer the mise toolchain (mise.toml pins node + pnpm), then a
# PATH pnpm, then npx (ships with node; runs the locally installed lint-staged).
if command -v mise >/dev/null 2>&1; then
mise exec -- pnpm exec lint-staged
elif command -v pnpm >/dev/null 2>&1; then
pnpm exec lint-staged
else
npx lint-staged
fi
15 changes: 8 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ static HTML. The browser never holds a token or calls the GitLab API.
`commit.gpgsign=true`, so this happens automatically; if signing is ever
stripped, pass `git commit -S` and verify with `git log --format="%G?"`
(expect `G`).
- **Docusaurus 3 only** (MDX v3, unified ESM, native `fetch`). **Node 20, 22, 24**
(Docusaurus 3 requires Node 20+; the e2e build will not run on Node 18).
- **Docusaurus 3 only** (MDX v3, unified ESM, native `fetch`). **Node 22 or 24**
(engines: `^22.13.0 || >=24.0.0` — pnpm 11 requires ≥22.13; Node 20 is no
longer supported).
- Prefer the latest versions of libraries.
- ESM-first. Intra-package imports use explicit `.js` extensions
(e.g. `import { Fallback } from "./Fallback.js"`) — required by the
Expand All @@ -34,19 +35,19 @@ static HTML. The browser never holds a token or calls the GitLab API.

## Commands

- `npm run build` — compile with `tsc -p tsconfig.build.json` (ESM `.js` + `.d.ts`)
- `pnpm run build` — compile with `tsc -p tsconfig.build.json` (ESM `.js` + `.d.ts`)
into `dist/`. The base `tsconfig.json` sets `noEmit: true` so a stray `tsc` can't
pollute `src/`; the build config flips `noEmit` off with `outDir: ./dist`.
The package is **ESM-only** (`module: ESNext`): every remark/rehype/unified
dependency is pure ESM, so a CJS build would `require()` them — which breaks
under Node's `require(ESM)` interop (`unified().use()` receives `{ default: fn }`
→ "empty preset", failing the Docusaurus build). Do not add a CJS build or a
`require` export condition; `test/packaging.test.ts` guards this.
- `npm run test` — run all tests (Vitest). Use `npx vitest run <file>` for one file.
- `npm run typecheck` — `tsc --noEmit`.
- `pnpm test` — run all tests (Vitest). Use `pnpm exec vitest run <file>` for one file.
- `pnpm run typecheck` — `tsc --noEmit`.

There is no lint step and no dev server. After code edits, run
`npx vitest run` and `npm run typecheck`. The e2e test
There is no dev server. After code edits, run
`pnpm exec vitest run` and `pnpm run typecheck`. The e2e test
(`test/e2e/build.test.ts`) builds a real Docusaurus site and is slow (~1 min);
run it explicitly when touching the pipeline.

Expand Down
35 changes: 19 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,34 @@ you from clone to a green build.

## Prerequisites

- **Node 20, 22, or 24** and **npm** (Docusaurus 3 requires Node 20+)
- **Node 22 or 24** (≥22.13 — required by pnpm 11) and **pnpm 11**.
With [mise](https://mise.jdx.dev), `mise install` sets up both (from
`mise.toml`); otherwise `corepack enable` activates the pnpm version pinned
in `package.json`'s `packageManager`, or `npm install -g pnpm@11`.
- A GitLab token is **not** required for development (the tests mock the API).
- Optionally, a **Dev Container** (`.devcontainer/`) — open the repo in a container
with nvm preloaded with Node 20/22/24; switch with `nvm use 22`.
with nvm preloaded with Node 22/24; switch with `nvm use 24`.

## Setup

```bash
git clone <repo-url>
cd mdx-gitlab-set
npm install # also installs the git pre-commit hook (via husky)
npm run build # bundle the package into dist/
pnpm install # installs the workspace (package + example sites) and the git pre-commit hook (via husky)
pnpm run build # bundle the package into dist/
```

## Everyday commands

| Command | What it does |
|---|---|
| `npm test` | Run all tests (unit + e2e) with Vitest |
| `npx vitest run --exclude '**/test/e2e/**'` | Unit tests only (fast) |
| `npx vitest run test/e2e/build.test.ts` | End-to-end only (builds a real Docusaurus site; ~1 min) |
| `npm run typecheck` | `tsc --noEmit` |
| `npm run lint` | ESLint + markdownlint |
| `npm run lint:fix` | Auto-fix lint issues |
| `npm run build` | Compile with tsc (ESM-only + types) |
| `pnpm test` | Run all tests (unit + e2e) with Vitest |
| `pnpm exec vitest run --exclude '**/test/e2e/**'` | Unit tests only (fast) |
| `pnpm exec vitest run test/e2e/build.test.ts` | End-to-end only (builds a real Docusaurus site; ~1 min) |
| `pnpm run typecheck` | `tsc --noEmit` |
| `pnpm run lint` | ESLint + markdownlint |
| `pnpm run lint:fix` | Auto-fix lint issues |
| `pnpm run build` | Compile with tsc (ESM-only + types) |

The example sites have their own READMEs:
[`examples/site`](./examples/site/README.md) (mocked, drives the e2e) and
Expand All @@ -49,16 +52,16 @@ The example sites have their own READMEs:

## Pre-commit hook

`npm install` sets up a husky pre-commit hook that runs **lint-staged**:
`pnpm install` sets up a husky pre-commit hook that runs **lint-staged**:
ESLint `--fix` on staged TS/JS and markdownlint on the root docs. If the hook
blocks your commit, run `npm run lint:fix` and re-stage.
blocks your commit, run `pnpm run lint:fix` and re-stage.

## Pull requests

Before opening a PR, make sure these pass:

```bash
npm run lint && npm run typecheck && npm test
pnpm run lint && pnpm run typecheck && pnpm test
```

Keep changes focused, and add/adjust tests for any behavior you change.
Expand All @@ -84,8 +87,8 @@ and published to npm with provenance via OIDC trusted publishing.
`@ebuildy/docusaurus-plugin-gitlab`.
- **First publish only:** because the package name does not yet exist on npm, the
very first publish may need to be bootstrapped manually from a clean checkout:
`npm ci && npm run build && npm publish --access public` (without
`--provenance`, which requires CI/OIDC). Subsequent releases publish
`pnpm install --frozen-lockfile && pnpm run build && npm publish --access public`
(without `--provenance`, which requires CI/OIDC). Subsequent releases publish
automatically.

## Working with AI (Claude Code)
Expand Down
33 changes: 15 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ tokens or network calls ever reach the browser, and pages stay fast.
- ✅ README images **and badges are downloaded and localized** (offline-safe, frozen at build time)
- ✅ On-disk caching, theme-aware (Infima) styling, graceful error fallbacks

> Requires Docusaurus **3.x** and Node **20, 22, or 24** (Docusaurus 3 itself
> needs Node 20+).
> Requires Docusaurus **3.x** and Node **22.13+ or 24**.

## Installation

Expand All @@ -29,12 +28,10 @@ npm install @ebuildy/docusaurus-plugin-gitlab
```

> **ESM-only.** This package ships as ES modules (all of its remark/rehype
> dependencies are ESM). Load it from an ESM config — `docusaurus.config.ts` or
> `docusaurus.config.mjs` (the examples below use `import`). If your site still
> uses a CommonJS `docusaurus.config.js` on **Node < 20.19**, either switch the
> config to ESM or load the plugin with `await import(...)`. On **Node 20.19+**
> (and 22+) CommonJS configs work too, since Node can `require()` ES modules
> natively.
> dependencies are ESM). Load it from an ESM config — `docusaurus.config.ts` or
> `docusaurus.config.mjs` (the examples below use `import`). CommonJS configs
> work too on the supported Node versions (22.13+), since Node can `require()`
> ES modules natively.

## Setup

Expand Down Expand Up @@ -278,15 +275,15 @@ Renders a timeline of GitLab **epics** (Premium/Ultimate, group-level) or
| Prop | Values | Default | Notes |
|---|---|---|---|
| `source` | `epics` \| `milestones` | `epics` | Fetch path |
| `group` | group path/id | — | Required for epics; one of group/project for milestones |
| `project` | project path/id | — | Milestones only |
| `group` | group path/id | | Required for epics; one of group/project for milestones |
| `project` | project path/id | | Milestones only |
| `layout` | `gantt` \| `timeline` | `gantt` | Horizontal bars vs. vertical spine |
| `layoutFit` | `page` \| `content` | `page` | Gantt only: `page` pins to the page width (ticks reduced to quarters/years by span, year rules bolded); `content` expands with a horizontal scrollbar |
| `scale` | `quarters` \| `months` \| `weeks` | auto | Auto from span; prop overrides |
| `state` | `opened` \| `closed` \| `all` | `opened` | |
| `labels` | comma-separated | — | Label filter |
| `labels` | comma-separated | | Label filter |
| `from` / `to` | `YYYY-MM-DD` | derived | Explicit window |
| `limit` | number | `50` | Max items (≤ 500) |
| `limit` | number | `50` | Max items ( 500) |
| `order` | `start` \| `due` \| `title` | `start` | Sort key |
| `groupBy` | `none` \| `label` \| `parent` | `none` | Section headings. In the **timeline** layout, `none` groups by **year → quarter** |
| `colorBy` | `source` \| `label` \| `state` | `source` | Bar/card tint |
Expand Down Expand Up @@ -427,8 +424,8 @@ markdown files) is rendered at build time by a `unified` plugin chain. By defaul
it is:

```text
remarkParse → remarkGemoji → remarkGfm → remarkRehype({ allowDangerousHtml })
→ rehypeRaw → rehypeSanitize
remarkParse → remarkEmoji → remarkGfm remarkRehype({ allowDangerousHtml })
rehypeRaw rehypeSanitize
```

Override or extend it with the `markdownRenderChain` option. Spread the exported
Expand Down Expand Up @@ -518,10 +515,10 @@ into your `src/css/custom.css` and edit freely. The class names you can target:
## Development

```bash
npm install
npm run build # compile with tsc (ESM-only + types)
npm run test # unit tests (Vitest)
npm run typecheck # tsc --noEmit
pnpm install # whole workspace (package + example sites)
pnpm run build # compile with tsc (ESM-only + types)
pnpm test # unit tests (Vitest)
pnpm run typecheck # tsc --noEmit
```

The `examples/site/` directory contains a minimal Docusaurus 3 site used by the
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default tseslint.config(
"dist/**",
"node_modules/**",
"examples/**",
"external/**",
"coverage/**",
".agents/**",
".claude/**",
Expand Down
15 changes: 8 additions & 7 deletions examples/gitlab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,19 @@ examples/gitlab/
## Running

```bash
# from the repo root: build the plugin the site consumes via file:../..
npm run build
# from the repo root: install the workspace and build the plugin the site
# consumes via its workspace link
pnpm install # first time only
pnpm run build

# from examples/gitlab
npm install # first time only
npm run build # production build → ./build (hits gitlab.com)
npm run serve # preview the production build
pnpm run build # production build → ./build (hits gitlab.com)
pnpm run serve # preview the production build
# or
npm start # dev server with hot reload (http://localhost:3000)
pnpm start # dev server with hot reload (http://localhost:3000)

# optional: authenticate to raise the rate limit
GITLAB_TOKEN=glpat-xxxxxxxx npm run build
GITLAB_TOKEN=glpat-xxxxxxxx pnpm run build
```

Because this build performs live network requests, it is slower than the mocked
Expand Down
3 changes: 1 addition & 2 deletions examples/gitlab/docusaurus.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createRequire } from "node:module";
import type { Config } from "@docusaurus/types";
import gitlabPlugin, { remarkGitlab } from "@ebuildy/docusaurus-plugin-gitlab";
import remarkGemoji from "remark-gemoji";
import remarkGfm from "remark-gfm";

const require = createRequire(import.meta.url);
Expand Down Expand Up @@ -37,7 +36,7 @@ const config: Config = {
docs: {
routeBasePath: "/",
sidebarPath: "./sidebars.ts",
remarkPlugins: [remarkGfm, remarkGemoji, [remarkGitlab, gitlabOptions]],
remarkPlugins: [remarkGfm, [remarkGitlab, gitlabOptions]],
},
blog: false,
theme: {
Expand Down
Loading
Loading