Skip to content

Make lib folder dependencies point in a single direction - #67

Merged
adelrodriguez merged 7 commits into
mainfrom
t3code/c7ad03ab
Oct 1, 2026
Merged

adelrodriguez merged 7 commits into
mainfrom
t3code/c7ad03ab

Conversation

@adelrodriguez

@adelrodriguez adelrodriguez commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

The folders in src/lib imported each other in both directions. store and workspace depended on each other, and core/errors and core/packages formed a cycle. This made it hard to see which module owns what, and any new code could add more cycles without notice.

Now each folder imports only lower layers:

  1. core, shared
  2. layout (new: on-disk paths and the Packref home)
  3. registries, manifests, store, workspace
  4. sources
  5. references

To break the cycles, the path helpers and PackrefHome moved from workspace to layout. core/packages.ts is split into identity.ts, repository.ts (repository hosts), and spec parsing. This also removes duplicate provider checks in sources, store, and references.

oxlint import/no-cycle now also reports cycles through type-only imports (ignoreTypes: false). On main it reports the old core/errors ↔ core/packages cycle. Per-folder no-restricted-imports overrides in oxlint.config.ts enforce the layers, and import/no-relative-parent-imports stops relative imports from bypassing them. docs/architecture.md documents the layers. Behavior does not change, so there is no changeset.


Changes made by Claude Opus 5.5 (1M context) in Claude Code.

🤖 Generated with Claude Code

Move on-disk paths and the Packref home into a new layout folder so store and
workspace no longer import each other. Split core/packages into identity,
repository host, and spec modules to break the errors/packages cycle. Add a
layer test that enforces the folder order and rejects import cycles.

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

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues. There are two gaps in the new layer test and one doc nit. See the inline comments.

Reviewed changes

I reviewed the full diff of the single commit. I ran tsc --noEmit, pnpm run check, pnpm run analyze, and pnpm run test (296 passed, 2 skipped). All of them pass. I also ran mutation probes against layers.test.ts.

  • Split of core/packages.ts — Identity types and orders move to core/identity.ts, and repository hosts move to core/repository.ts. This removes the core/errors.ts ↔ core/packages.ts file cycle.
  • New layout folder — PackrefHome and the project and user-level path helpers move from workspace to layout, and getStorePackagePath becomes getPackageIdentityPath. This removes the store ↔ workspace folder cycle.
  • Shared provider check — checkIsRepositoryProvider replaces three inline provider checks in references/install.ts, store/index.ts, and sources/repository/normalize.ts. Behavior does not change.
  • Reference path lookups — references/remove.ts and references/sync.ts now call getProjectReferencePath. It gives the same path as the old getDirectoryPath + getStorePackagePath composition.
  • Layer guard test — src/lib/__tests__/layers.test.ts enforces a folder allow-list and rejects file-level import cycles. The probes show that it catches an upward #lib import and a file cycle in core.
  • Architecture docs — docs/architecture.md adds the layout row and a ### Layers section.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread src/lib/__tests__/layers.test.ts Outdated
Comment thread src/lib/__tests__/layers.test.ts Outdated
Comment thread docs/architecture.md Outdated
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found. The new commit fixes all three points from the last review.

Reviewed changes

I reviewed commit 0db6084, which changes layers.test.ts and one row in docs/architecture.md. pnpm run check passes, and all 5 tests in layers.test.ts pass. I ran mutation probes against the new tests.

  • Shared cycle search — Moved the DFS into findCycles(graph). The file-cycle test and a new folder-cycle test over ALLOWED_DEPENDENCIES both use it. When I add "sources" to the store allow-list, the folder test fails with sources -> store -> sources.
  • Relative import guard — Added a test that rejects from "./..." and from "../..." specifiers in non-test src/lib files. Both of my probes fail this test: a ../layout/home.ts import and a same-folder import type from ./identity.ts.
  • Narrower layout doc row — Changed the docs/architecture.md row so that it lists only project paths, user-level paths, and the Packref home. The global store paths stay in store/paths.ts.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

adelrodriguez and others added 2 commits October 1, 2026 14:29
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found. The new commit removes only a test and one doc sentence. The source code does not change.

Reviewed changes

I reviewed commit 3194e72. The range diff against 0db6084 shows changes in only these two files. I also did a lint probe to find which layer rules a check still enforces.

  • Removed the layer guard test — Deleted src/lib/__tests__/layers.test.ts, which contained the ALLOWED_DEPENDENCIES allow-list, the folder-cycle and file-cycle checks, and the relative-import check.
  • Removed the doc pointer — Deleted the sentence in docs/architecture.md that told contributors to update ALLOWED_DEPENDENCIES. The ### Layers list stays.

ℹ️ Only file cycles are still enforced — the folder layers are now documentation only

Lint still catches file-level cycles. Adamantite's core preset sets import/no-cycle to error, and oxlint resolves #lib/... specifiers. In my probe, two files in src/lib/core that import each other through #lib caused an import(no-cycle) error on both files. But no check now catches an upward folder import, or a folder cycle that has no file cycle. Before this PR, store ↔ workspace was that type of cycle. This is acceptable if you want the ### Layers list to be a convention only.

Technical details
# Folder layering is no longer enforced after `3194e72`

## Affected sites
- docs/architecture.md:32-41 — the `### Layers` section states the rule, but no test or lint rule enforces it.
- node_modules/adamantite/dist/presets/lint/core.js — `"import/no-cycle": "error"` (still active, and it catches file cycles over `#lib` specifiers); `"import/no-relative-parent-imports": "off"`.

## Probe results at `3194e72`
- `src/lib/core/a.ts` <-> `src/lib/core/b.ts` through `#lib/core/...` → `import(no-cycle)` error on both. Caught.
- `src/lib/core/c.ts` imports `#lib/layout/home.ts` (upward import, no file cycle) → no layer error. Not caught.

## Required outcome
- None, if the layers are a convention only. If you want enforcement, then an upward `#lib` import or a folder cycle must fail `pnpm run check` or `pnpm run test`.

## Suggested approach (optional)
- Use `no-restricted-imports` `patterns` overrides for each folder in `oxlint.config.ts` (for example, files in `src/lib/core/**` cannot import `#lib/layout/**` or a higher layer). This keeps enforcement in the lint step and does not need a test file.

## Open questions for the human (optional)
- Is it your intention that the `### Layers` list is a convention only?

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

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

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found. The new commits add lint enforcement for the src/lib layers. This closes the enforcement gap from the last review.

Reviewed changes

I reviewed commits a6b7cca and 38f8f46. They change only oxlint.config.ts and docs/architecture.md. pnpm run check and tsc --noEmit pass. I ran lint probes with scratch files in src/lib, and then deleted the files.

  • Type-only cycles — Set import/no-cycle to ignoreTypes: false, so lint also reports cycles through import type. No cycles of this type are in the current code.
  • LIB_LAYERS overrides — Added one no-restricted-imports override for each src/lib folder. Each override rejects #lib folders that are not in the allow-list, and all ./ and ../ specifiers. The probes caught these imports: an upward import, a type-only import, export * from, dynamic import(), a side-effect import, a same-layer import (store → workspace), a deep-folder import (sources/repository → references), and relative ./ and ../ imports. Allowed imports and same-folder #lib imports do not cause errors. The custom messages show as help: lines.
  • Test exemption — Turned off no-restricted-imports for src/lib/**/__tests__/**. The probe shows that this also applies to nested folders such as sources/repository/__tests__. No Adamantite preset sets this rule, so the overrides do not replace other settings.
  • Architecture docs — Added a sentence that names LIB_LAYERS and import/no-cycle as the enforcement. The allow-list agrees with the ### Layers list and has no cycles.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

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

pullfrog Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Run failed. View the logs →

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using claude-opus-5-5 | 𝕏

1 similar comment
@pullfrog

pullfrog Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Run failed. View the logs →

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using claude-opus-5-5 | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues. The layer rules have not changed, and there is one wording nit inline.

Reviewed changes

I reviewed commit 1010499. It changes only oxlint.config.ts and one paragraph in docs/architecture.md. pnpm run check (0 warnings, 0 errors) and tsc --noEmit pass. I ran lint probes with scratch files in src/lib, and then deleted the files.

  • Explicit layer overrides — Replaced the LIB_LAYERS generator with one hand-written no-restricted-imports override for each folder except references. Each group list is the same as the complement of the old allow-list, so the layers do not change. The probes still catch an upward import (core → #lib/layout) and a deep-folder import (sources/repository → #lib/workspace).
  • Relative imports — Replaced the ./** and ../** pattern group with import/no-relative-parent-imports on src/lib/**/*.ts. The probes caught these ../ imports: value imports, import type, export * from, dynamic import(), side-effect imports, and ./../. Same-folder ./ imports are now allowed. They cannot get to a different folder.
  • Test exemption — Turned off import/no-relative-parent-imports with no-restricted-imports in src/lib/**/__tests__/**. A nested test file with ../../../ and upward #lib imports causes no errors.
  • Architecture docs — Changed the enforcement paragraph to name the overrides and import/no-relative-parent-imports.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread oxlint.config.ts Outdated
Comment thread oxlint.config.ts Outdated
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@adelrodriguez
adelrodriguez merged commit 045ccaf into main Oct 1, 2026
8 checks passed
@adelrodriguez
adelrodriguez deleted the t3code/c7ad03ab branch October 1, 2026 21:22
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