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
12 changes: 6 additions & 6 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Content files are YAML (preferred) or JSON under `content/{category}/{slug}.yaml
| `related` | Exactly **3** entries as `category/slug` paths (cross-category OK) |
| `tags` | Non-empty list of slugs registered in `html-generators/tags.properties` |
| `docs` | At least **1** entry with `title` and `href` |
| `prev` / `next` | `category/slug` path or `null` for first/last in the global chain |
| `navigationOrder` | Non-negative integer; global order is `(navigationOrder, category/slug)` |
| `jdkVersion` | The JDK version where the feature became **final** (not preview) |
| `difficulty` | One of: `beginner`, `intermediate`, `advanced` |
| `support.state` | One of: `available`, `preview`, `experimental` |
Expand All @@ -60,24 +60,24 @@ Content files are YAML (preferred) or JSON under `content/{category}/{slug}.yaml

1. Create `content/{category}/new-slug.yaml` with all required fields (use `content/template.json` as reference) and generate its `id` with `uuidgen`.
2. Add a non-empty `tags` list. Every tag slug must already exist in `html-generators/tags.properties`; add new `slug=Display Name` entries there in the same change.
3. Update `prev`/`next` in the adjacent patterns to maintain the navigation chain.
3. Set `navigationOrder` to place the pattern in the global sequence. Values are spaced by 1000; duplicate values are allowed and tie-break by pattern key.
4. Create `proof/{category}/{PascalCaseSlug}.java` — JBang script wrapping the modern code.
5. Create a partial translation at `translations/content/{locale}/{category}/{slug}.yaml` for every non-English locale registered in `html-generators/locales.properties`.
6. Run `jbang html-generators/generate.java` and verify all localized output builds. Generated site files are ignored and must not be committed. The generator rejects missing, malformed, or duplicate UUIDs as well as missing, empty, malformed, and unregistered tags.
7. Run `jbang html-generators/generatesocialqueue.java` without `--reshuffle`. Commit the appended `social/queue.txt` entry and `social/tweets.yaml` draft; do not change `social/state.yaml`.
8. Run `jbang html-generators/validatepatternchanges.java --file content/{category}/{slug}.yaml` and the new proof. The validator enforces translations, proof, navigation, related targets, and social artifacts.
7. Run `jbang html-generators/generatesocialqueue.java --file content/{category}/{slug}.yaml`. Commit the generated `social/tweets/{category}/{slug}.yaml`; do not change `social/queue.txt` or `social/state.yaml`.
8. Run `jbang html-generators/validatepatternchanges.java --file content/{category}/{slug}.yaml` and the new proof. The validator enforces translations, proof, navigation order, related targets, and the tweet draft.

### Removing or reordering a pattern

Update `prev`/`next` in adjacent patterns. Search for the slug in other patterns' `related` arrays and replace with an appropriate alternative.
Update `navigationOrder` when reordering. Search for a removed slug in other patterns' `related` arrays and replace it with an appropriate alternative.

## Internationalization

Full spec: `specs/i18n/i18n-spec.md`. Key rules:

- All locales (including English) go through the same build pipeline.
- UI strings: `translations/strings/{locale}.yaml`. Missing keys fall back to English with a build-time warning.
- Content translations contain **only** translatable fields: `title`, `summary`, `explanation`, `oldApproach`, `modernApproach`, `whyModernWins`, `support.description`. Code, slugs, navigation, and docs are never translated.
- Content translations contain **only** translatable fields: `title`, `summary`, `explanation`, `oldApproach`, `modernApproach`, `whyModernWins`, `support.description`. Code, slugs, navigation order, and docs are never translated.
- `oldCode`/`modernCode` in translation files are **always overwritten** with English values at build time to prevent hallucinated code.
- Locale registry: `html-generators/locales.properties` (format: `locale=Display Name`).
- When adding a new UI string key, add it to `en.yaml` first, then to all other locale files. The generator warns on missing keys but doesn't fail.
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/content-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ on:
- '.github/workflows/content-validation.yml'
- 'content/**'
- 'proof/**'
- 'social/queue.txt'
- 'social/tweets.yaml'
- 'social/tweets/**'
- 'translations/**'
- 'templates/**'
- 'html-generators/generate.java'
- 'html-generators/generatesocialqueue.java'
- 'html-generators/socialpost.java'
- 'html-generators/validatepatternchanges.java'
- 'html-generators/tags.properties'
- 'html-generators/categories.properties'
Expand Down Expand Up @@ -42,5 +43,10 @@ jobs:
--base "${{ github.event.pull_request.base.sha }}"
--head "${{ github.event.pull_request.head.sha }}"

- name: Validate social posting flow
run: |
jbang html-generators/generatesocialqueue.java
jbang html-generators/socialpost.java --dry-run

- name: Validate content and generate site
run: jbang html-generators/generate.java
5 changes: 4 additions & 1 deletion .github/workflows/social-post.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:

- uses: jbangdev/setup-jbang@main

- name: Reconcile pending queue
run: jbang html-generators/generatesocialqueue.java

- name: Post to Twitter
env:
TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_APP_CONSUMER_KEY }}
Expand All @@ -37,7 +40,7 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add social/state.yaml social/queue.txt social/tweets.yaml
git add social/state.yaml social/queue.txt
git diff --cached --quiet && exit 0
git commit -m "chore: update social post state [skip ci]"
git pull --rebase
Expand Down
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ Contributions are welcome! Content is managed as YAML files — never edit gener
1. Fork the repo
2. Create a new YAML file in the appropriate `content/<category>/` folder (e.g. `content/language/my-feature.yaml`)
3. Copy [`content/template.json`](content/template.json) as a starting point for all required fields (see the [snippet schema](.github/copilot-instructions.md) for details)
4. Update the `prev`/`next` fields in adjacent pattern files to maintain navigation
5. Run `jbang html-generators/generate.java` to verify your changes build correctly
6. Open a pull request
4. Set `navigationOrder` to place the pattern in the global sequence. Values are spaced by 1000; duplicate values are allowed and are ordered by pattern key.
5. Generate its tweet draft with `jbang html-generators/generatesocialqueue.java --file content/<category>/<slug>.yaml`
6. Run `jbang html-generators/generate.java` to verify your changes build correctly
7. Open a pull request

Please ensure JDK version labels only reference the version where a feature became **final** (non-preview).

Expand Down Expand Up @@ -51,6 +52,6 @@ support:
description: "Ampliamente disponible desde JDK 10 (marzo 2018)"
```

Do **not** include `id`, `slug`, `category`, `difficulty`, `jdkVersion`, `oldCode`, `modernCode`, `prev`, `next`, `related`, or `docs` — these are always taken from the English source.
Do **not** include `id`, `slug`, `category`, `navigationOrder`, `difficulty`, `jdkVersion`, `oldCode`, `modernCode`, `related`, or `docs` — these are always taken from the English source.

**Important:** If your text contains colons (`:`), ensure the value is properly quoted in YAML to avoid parse errors. Always validate with `jbang html-generators/generate.java` before submitting.
3 changes: 1 addition & 2 deletions content/collections/collection-bulk-operations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 6a0d1711-a495-490e-a830-95087e092b69
slug: "collection-bulk-operations"
title: "Collection bulk operations instead of mutation loops"
category: "collections"
navigationOrder: 39000
difficulty: "beginner"
jdkVersion: "8"
oldLabel: "Iterator mutation loop"
Expand Down Expand Up @@ -32,8 +33,6 @@ whyModernWins:
support:
state: "available"
description: "Available since JDK 8 (March 2014)"
prev: "collections/stack-to-deque"
next: "collections/comparator-factories"
related:
- "collections/reverse-list-iteration"
- "collections/copying-collections-immutably"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/collectors-teeing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: a04b95a4-d198-4e96-ac9b-870ec57fdeb9
slug: "collectors-teeing"
title: "Collectors.teeing()"
category: "collections"
navigationOrder: 32000
difficulty: "intermediate"
jdkVersion: "12"
oldLabel: "Java 8"
Expand Down Expand Up @@ -40,8 +41,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 12 (March 2019)"
prev: "collections/sequenced-collections"
next: "collections/stream-toarray-typed"
related:
- "collections/copying-collections-immutably"
- "collections/unmodifiable-collectors"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/comparator-factories.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: a1ac8e52-14cf-49be-a22a-be72de7caa4e
slug: "comparator-factories"
title: "Comparator factories and fluent ordering"
category: "collections"
navigationOrder: 40000
difficulty: "beginner"
jdkVersion: "8"
oldLabel: "Anonymous comparator"
Expand Down Expand Up @@ -35,8 +36,6 @@ whyModernWins:
support:
state: "available"
description: "Available since JDK 8 (March 2014)"
prev: "collections/collection-bulk-operations"
next: null
related:
- "collections/collection-bulk-operations"
- "collections/reverse-list-iteration"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/copying-collections-immutably.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 34332f56-c837-4ddb-b00f-aca32bb68bef
slug: "copying-collections-immutably"
title: "Copying collections immutably"
category: "collections"
navigationOrder: 29000
difficulty: "beginner"
jdkVersion: "10"
oldLabel: "Java 8"
Expand Down Expand Up @@ -34,8 +35,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 10 (March 2018)"
prev: "collections/immutable-set-creation"
next: "collections/map-entry-factory"
related:
- "collections/immutable-set-creation"
- "collections/map-entry-factory"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/immutable-list-creation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 1fa578db-e750-4adb-a88e-bdd2bbda14c4
slug: "immutable-list-creation"
title: "Immutable list creation"
category: "collections"
navigationOrder: 26000
difficulty: "beginner"
jdkVersion: "9"
oldLabel: "Java 8"
Expand Down Expand Up @@ -36,8 +37,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 9 (Sept 2017)"
prev: "language/exhaustive-switch"
next: "collections/immutable-map-creation"
related:
- "collections/immutable-map-creation"
- "collections/immutable-set-creation"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/immutable-map-creation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: d118236d-2cfb-4c8a-81b6-f870fc10c25d
slug: "immutable-map-creation"
title: "Immutable map creation"
category: "collections"
navigationOrder: 27000
difficulty: "beginner"
jdkVersion: "9"
oldLabel: "Java 8"
Expand Down Expand Up @@ -34,8 +35,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 9 (Sept 2017)"
prev: "collections/immutable-list-creation"
next: "collections/immutable-set-creation"
related:
- "collections/copying-collections-immutably"
- "collections/sequenced-collections"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/immutable-set-creation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 26dee8f0-333e-44ae-9467-4c99bae5516a
slug: "immutable-set-creation"
title: "Immutable set creation"
category: "collections"
navigationOrder: 28000
difficulty: "beginner"
jdkVersion: "9"
oldLabel: "Java 8"
Expand Down Expand Up @@ -35,8 +36,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 9 (Sept 2017)"
prev: "collections/immutable-map-creation"
next: "collections/copying-collections-immutably"
related:
- "collections/copying-collections-immutably"
- "collections/collectors-teeing"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/legacy-synchronized-collections.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: d54a4e9f-74b9-4579-84a3-2541fe7b4272
slug: "legacy-synchronized-collections"
title: "Legacy synchronized collections to modern alternatives"
category: "collections"
navigationOrder: 36000
difficulty: "intermediate"
jdkVersion: "5"
oldLabel: "Legacy synchronized collection"
Expand Down Expand Up @@ -32,8 +33,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 5 (September 2004)"
prev: "collections/unmodifiable-collectors"
next: "collections/map-compute-and-merge"
related:
- "collections/immutable-map-creation"
- "collections/copying-collections-immutably"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/map-compute-and-merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: fe4cbd51-2be6-4d7b-86c5-0ce82ce9bf10
slug: "map-compute-and-merge"
title: "Atomic map updates with compute and merge"
category: "collections"
navigationOrder: 37000
difficulty: "intermediate"
jdkVersion: "8"
oldLabel: "Manual lookup and update"
Expand Down Expand Up @@ -38,8 +39,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 8 (March 2014)"
prev: "collections/legacy-synchronized-collections"
next: "strings/string-isblank"
related:
- "collections/legacy-synchronized-collections"
- "collections/immutable-map-creation"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/map-entry-factory.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 672534a8-9e26-4d9d-b448-a48ca562519f
slug: "map-entry-factory"
title: "Map.entry() factory"
category: "collections"
navigationOrder: 30000
difficulty: "beginner"
jdkVersion: "9"
oldLabel: "Java 8"
Expand Down Expand Up @@ -32,8 +33,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 9 (Sept 2017)"
prev: "collections/copying-collections-immutably"
next: "collections/sequenced-collections"
related:
- "collections/sequenced-collections"
- "collections/immutable-map-creation"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/reverse-list-iteration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: ed019aff-c1e9-462a-9750-79d27891cee4
slug: "reverse-list-iteration"
title: "Reverse list iteration"
category: "collections"
navigationOrder: 34000
difficulty: "beginner"
jdkVersion: "21"
oldLabel: "Java 8"
Expand Down Expand Up @@ -37,8 +38,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 21 LTS (Sept 2023)"
prev: "collections/stream-toarray-typed"
next: "collections/unmodifiable-collectors"
related:
- "collections/sequenced-collections"
- "collections/immutable-list-creation"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/sequenced-collections.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 8d95ed1f-c10f-49c9-8427-916904b5ce92
slug: "sequenced-collections"
title: "Sequenced collections"
category: "collections"
navigationOrder: 31000
difficulty: "beginner"
jdkVersion: "21"
oldLabel: "Java 8"
Expand Down Expand Up @@ -36,8 +37,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 21 LTS (Sept 2023)"
prev: "collections/map-entry-factory"
next: "collections/collectors-teeing"
related:
- "collections/collectors-teeing"
- "collections/immutable-set-creation"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/stack-to-deque.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 5ec6dc04-e96e-4d30-a11c-ea48c9d28fbf
slug: "stack-to-deque"
title: "Stack to Deque and ArrayDeque"
category: "collections"
navigationOrder: 38000
difficulty: "beginner"
jdkVersion: "6"
oldLabel: "Legacy Stack"
Expand Down Expand Up @@ -32,8 +33,6 @@ whyModernWins:
support:
state: "available"
description: "Available since JDK 6 (December 2006)"
prev: "enterprise/spring-boot-mvc-config"
next: "collections/collection-bulk-operations"
related:
- "collections/sequenced-collections"
- "collections/reverse-list-iteration"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/stream-toarray-typed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 5af66a72-0bcb-4c3a-9237-678c149ccef3
slug: "stream-toarray-typed"
title: "Typed stream toArray"
category: "collections"
navigationOrder: 33000
difficulty: "beginner"
jdkVersion: "8"
oldLabel: "Pre-Streams"
Expand Down Expand Up @@ -40,8 +41,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 8 (March 2014)"
prev: "collections/collectors-teeing"
next: "collections/reverse-list-iteration"
related:
- "collections/collectors-teeing"
- "collections/map-entry-factory"
Expand Down
3 changes: 1 addition & 2 deletions content/collections/unmodifiable-collectors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 4ed99b6a-ef57-4769-a640-46521d03b190
slug: "unmodifiable-collectors"
title: "Unmodifiable collectors"
category: "collections"
navigationOrder: 35000
difficulty: "intermediate"
jdkVersion: "16"
oldLabel: "Java 8"
Expand Down Expand Up @@ -35,8 +36,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 16 (March 2021)"
prev: "collections/reverse-list-iteration"
next: "collections/legacy-synchronized-collections"
related:
- "collections/immutable-map-creation"
- "collections/immutable-set-creation"
Expand Down
3 changes: 1 addition & 2 deletions content/concurrency/completablefuture-chaining.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 1abbda8c-c7e3-42d1-874e-978403c51325
slug: "completablefuture-chaining"
title: "CompletableFuture chaining"
category: "concurrency"
navigationOrder: 63000
difficulty: "intermediate"
jdkVersion: "8"
oldLabel: "Pre-Java 8"
Expand Down Expand Up @@ -37,8 +38,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 8 (March 2014)"
prev: "concurrency/stable-values"
next: "concurrency/executor-try-with-resources"
related:
- "concurrency/stable-values"
- "concurrency/scoped-values"
Expand Down
3 changes: 1 addition & 2 deletions content/concurrency/concurrent-http-virtual.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: 70ce47ef-a05c-4e30-8801-376665667e93
slug: "concurrent-http-virtual"
title: "Concurrent HTTP with virtual threads"
category: "concurrency"
navigationOrder: 67000
difficulty: "intermediate"
jdkVersion: "21"
oldLabel: "Java 8"
Expand Down Expand Up @@ -45,8 +46,6 @@ whyModernWins:
support:
state: "available"
description: "Widely available since JDK 21 LTS (Sept 2023)"
prev: "concurrency/process-api"
next: "concurrency/lock-free-lazy-init"
related:
- "concurrency/structured-concurrency"
- "concurrency/stable-values"
Expand Down
Loading