Skip to content
Draft
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
38 changes: 38 additions & 0 deletions .claude/skills/incremental-build/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: incremental-build
description: >
Work on the incremental (delta) build system in @ui5/project: build caching,
resource indexing, hash trees, stage caching, build server, file watching,
task execution caching, and delta builds.
when_to_use: >
TRIGGER when: the user asks about or wants to modify code related to incremental builds,
build caching, resource indexing, hash trees, stage caching, build server, file watching,
task execution caching, delta builds, resource tags in build context, or any component
listed in the Component Map in architecture.md.
DO NOT TRIGGER when: the user is working on unrelated CLI commands, general tooling,
or non-build features.
user-invocable: true
---

# Incremental Build Skill

You are working on the incremental (delta) build system in `@ui5/project`. Read `architecture.md` in this skill directory for the full architecture reference, including the component map, key flows, caching architecture, and data structures. Read `performance-investigation.md` for guidance on profiling builds, reading perf logs, and known performance peculiarities.

## Guidelines for Working on This Code

1. **Always read the source file before modifying it.** The Component Map in `architecture.md` tells you where each piece lives.
2. **Understand the cache flow direction.** Changes propagate: source change -> index update -> signature change -> cache miss -> task re-execution.
3. **Be careful with tag side effects.** `getTags()` is not a pure read -- it triggers lazy tag application. Avoid calling it in unexpected contexts.
4. **Respect abort signals.** Any long-running operation should check `signal?.throwIfAborted()` periodically.
5. **Test with incremental rebuilds.** A single build passing is not enough; the interesting bugs appear on the second and third builds after file changes.
6. **Watch for stale stage readers after abort.** If a build is aborted, stage writers may contain partial results that shadow source files.
7. **Signature stability matters.** Any change to how hashes are computed (e.g., adding new fields to hash input) invalidates all existing caches.
8. **SharedHashTree operations must go through TreeRegistry.** Never mutate a SharedHashTree directly; always schedule via the registry and flush.

## Known Constraints

- `StageCache` (in-memory) has no `clear()` method -- stage entries persist for the lifetime of the `ProjectBuildCache` instance
- `ProjectBuildContext` instances (including their caches) are reused across sequential builds of the same project within a session
- `resource.getTags()` has side effects: it triggers `#applyCachedResourceTags()` and creates `MonitoredResourceTagCollection` instances, which modify tag collection state. This means calling `getTags()` during hash tree operations (e.g., in `TreeRegistry.flush()`) can affect the stage pipeline state.
- `updateProjectIndices` uses `project.getReader()` (stage pipeline reader) to read resources. After an aborted build, stage writers may contain in-memory resources that shadow updated source content, causing stale reads.
- `getSourcePaths()` and `getVirtualPath()` are NOT consistent with `getSourceReader()` for all project types. Module has no `getVirtualPath()` (base class throws). ThemeLibrary's `getSourcePaths()` returns only `[src/]` and `getVirtualPath()` only maps `src/`, but `_getReader()` also includes `test/` when `_testPathExists`. Any optimization that replaces `sourceReader.byGlob()` with direct filesystem enumeration via `getSourcePaths()` + `getVirtualPath()` must handle these mismatches.
374 changes: 374 additions & 0 deletions .claude/skills/incremental-build/architecture.md

Large diffs are not rendered by default.

378 changes: 378 additions & 0 deletions .claude/skills/incremental-build/performance-investigation.md

Large diffs are not rendered by default.

67 changes: 67 additions & 0 deletions .claude/skills/ui5-fs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
name: ui5-fs
description: >
Work on the @ui5/fs package: the virtual file system abstraction layer providing
Resource, Adapters (FileSystem, Memory), Reader Collections (ReaderCollection,
ReaderCollectionPrioritized, DuplexCollection, WriterCollection), specialized readers
(Filter, Link, Proxy), resource tagging, monitoring, and the resourceFactory API.
when_to_use: >
TRIGGER when: the user asks about or wants to modify code related to @ui5/fs,
the virtual file system, resources, adapters, reader collections, writer collections,
DuplexCollection, resourceFactory, ResourceTagCollection, MonitoredReader, fsInterface,
ResourceFacade, or any file within packages/fs/.
DO NOT TRIGGER when: the user is working on builder tasks/processors, CLI commands,
server middleware, or project graph resolution that does not touch the FS layer.
user-invocable: true
---

# @ui5/fs Skill

You are working on the `@ui5/fs` package — the virtual file system abstraction layer for UI5 CLI. Read `architecture.md` in this skill directory for the full architecture reference, including the class hierarchy, API surface, adapter internals, and collection patterns.

## Package Location

Source: `packages/fs/lib/`
Tests: `packages/fs/test/lib/`
Fixtures: `packages/fs/test/fixtures/`

## Guidelines for Working on This Code

1. **Always read the source file before modifying it.** The Component Map in `architecture.md` tells you where each piece lives.
2. **Understand the content type state machine.** Resources have internal content types (BUFFER, STREAM, FACTORY, DRAINED_STREAM, IN_TRANSFORMATION) with strict transitions. Never bypass `modifyStream()` for content transformations — it handles mutex locking and state management.
3. **Respect the mutex.** Resource content access is protected by `async-mutex`. Concurrent `getBuffer()` / `getString()` calls are safe, but `modifyStream()` acquires an exclusive lock. Never hold a reference to content across an `await` that could trigger a transformation.
4. **Virtual paths are POSIX-absolute.** All virtual paths must be absolute POSIX paths (start with `/`). Base paths must end with `/`. Adapters normalize patterns relative to their `virBasePath`.
5. **Content parameters are mutually exclusive.** When creating a Resource, only one of `buffer`, `string`, `stream`, `createStream`, or `createBuffer` can be provided. The `createBuffer`/`createStream` factories enable lazy loading.
6. **byGlob randomizes result order.** `AbstractReader.byGlob()` intentionally shuffles results to prevent consumers from relying on ordering. Do not assume or depend on glob result order.
7. **Clone semantics matter.** Resources are cloned on retrieval from adapters. `resource.clone()` creates an independent copy including content. When modifying resources from collections, understand whether you're working on the original or a clone.
8. **ResourceFacade is immutable.** `ResourceFacade.setPath()` throws. The facade wraps a resource with a different virtual path (used by Link reader). Use `getOriginalPath()` to get the underlying path.
9. **Tag format is strict.** Tags follow the pattern `"namespace:Name"` — namespace is lowercase alphanumeric, name is PascalCase. Tags are validated on set. Use `ResourceTagCollection` or `MonitoredResourceTagCollection` for tag operations.
10. **Test with both FileSystem and Memory adapters.** Behavior can differ between adapters (e.g., FileSystem uses `globby` while Memory uses `micromatch`; FileSystem has lazy content loading via factories, Memory clones on read).

## Known Constraints

- `Resource.getStream()` is deprecated — use `getStreamAsync()` or `getBuffer()` / `getString()` instead. The deprecation warning is only logged once per process.
- `Resource.getStatInfo()` is deprecated — use `getLastModified()`, `getSize()`, `getInode()` instead.
- FileSystem adapter's `write()` uses `fs.copyFile` for unmodified resources (optimization). It also detects same-source-same-target writes and skips them, but switches to buffer-based writes if the content was modified (to avoid stream read-during-write conflicts).
- Memory adapter auto-creates virtual directory entries in its hierarchy on `write()`.
- `WriterCollection` matches the **longest prefix** (greedy match) when routing writes to writers.
- `DuplexCollection` uses an internal `ReaderCollectionPrioritized` with the writer first, so written resources shadow the reader's resources.
- `fsInterface` provides a Node.js `fs`-compatible wrapper but only implements `readFile`, `stat`, and `readdir`. `mkdir` is a no-op.
- `Resource.getIntegrity()` computes SHA-256 via `ssri` — this triggers full content loading if not already loaded.
- Monitored readers/writers (`MonitoredReader`, `MonitoredReaderWriter`) prevent reads/writes after being sealed. They track all access patterns for build caching analysis.

## Running Tests

```bash
# All tests
npm run unit --workspace=@ui5/fs

# Single file
cd packages/fs && npx ava test/lib/Resource.js

# Verbose with logging
npm run unit-verbose --workspace=@ui5/fs

# Coverage
npm run coverage --workspace=@ui5/fs
```
Loading
Loading