Skip to content

Latest commit

 

History

History
181 lines (136 loc) · 13 KB

AGENTS.md

File metadata and controls

181 lines (136 loc) · 13 KB

ng-select — instructions for AI coding assistants

This file is the single canonical repository context for every coding agent (Claude Code, Cursor, Codex, JetBrains AI Assistant, Copilot, …). Tool-specific files, if any, should only point here. Shared agent skills live in .agents/skills/. If instructions conflict, prefer this file and the actual codebase.


Prime Directive

ng-select is a widely consumed Angular 22 component library (select, multiselect, autocomplete) published to npm. Preserve public API compatibility, accessibility, keyboard navigation, forms integration, and OnPush-friendly data flow. Breaking changes require deliberate versioning and release notes. Inspect nearby code first and prefer established local patterns over new abstractions.


Project Summary

Package Path Purpose
@ng-select/ng-select src/ng-select/ Main select/multiselect/autocomplete component
@ng-select/ng-option-highlight src/ng-option-highlight/ NgOptionHighlightDirective ([ngOptionHighlight]): highlights the search term in option labels
docs site website/ Astro + Starlight; demos in src/demo/app/examples/ render as Angular islands via @analogjs/astro-angular
  • Stack: Angular 22, TypeScript 6, @angular/cdk (dropdown overlay), ng-packagr (@angular/build:ng-packagr), Vitest browser mode, ESLint 10 + angular-eslint, Prettier, pnpm.
  • Public API: src/ng-select/public-api.ts, src/ng-option-highlight/public-api.ts. User docs: README.md and website/src/content/docs/reference/api.mdx.
  • Versions: semantic-release versions from git tags. v24.x (CDK Overlay) and v23.x (no Overlay from 23.11.0; 23.7.0–23.10.0 shipped it by mistake) both target Angular ^22.0.0. The version in src/*/package.json is not bumped in-repo; run pnpm view @ng-select/ng-select version for the latest release. Compatibility matrix: website/src/content/docs/reference/versions.mdx and README.
  • Peers: @angular/{cdk,common,core,forms} ^22.0.0 (ng-option-highlight: common, core).
  • Links: docs · repository

Rules

  • pnpm only. Never npm or yarn.
  • Public API: check public-api.ts, README, and reference/api.mdx before adding, renaming, or removing public members, and document new user-facing inputs/outputs there. Keep inputs, outputs, CSS class names, and DOM structure backward compatible.
  • OnPush: consumers must replace items/model arrays rather than mutate them; library code uses immutable updates too.
  • Standalone: all components and directives are standalone. Keep NgSelectModule for backward compatibility; never add new NgModules.
  • Reuse existing helpers (utils/value-utils.ts, utils/search-helper.ts, items-list.ts, selection-model.ts); search for similar code before adding helpers.
  • Dependencies: no new runtime dependencies in published packages without strong justification.
  • Generated files: never hand-edit dist/, coverage output, or llms.txt/llms-full.txt (regenerated by pnpm build:llms from the MDX docs and examples).
  • User-visible behavior: add or update a demo example.
  • Commits: Conventional Commits; semantic-release derives versions from them.
  • Attribution: DO NOT list yourself, your model name, or any AI/LLM as author, co-author, contributor, or credit anywhere: files, changelogs, comments, docs, commit messages (including Co-authored-by trailers), PR titles or bodies.

Agent Workflow

  • Execute implementation with Opus (medium effort) or Sonnet agents, parallelizing independent work aggressively for speed. Use up to 100 agents for max speed.
  • Use as many parallel agents as useful without duplicating work or making conflicting edits: give each a non-overlapping file scope and a complete brief (files, constraints from this file, done criteria).

Commands

pnpm install
pnpm start                                  # docs site at http://localhost:4300/ng-select/
pnpm build                                  # both libraries + compiled themes + SCSS copies → dist/
pnpm build:docs                             # llms.txt + Astro build → dist/docs
pnpm docs:preview                           # serve the built docs site
pnpm test                                   # both libraries, zoneless, with coverage
pnpm test:watch                             # ng-select only, watch mode
pnpm test:zone                              # both libraries on the zone.js lane
pnpm test:ci                                # what CI runs: zoneless + coverage, then zone.js lane
pnpm exec ng test ng-select --watch=false   # fast single-library run
pnpm lint                                   # ESLint, both libraries
pnpm format                                 # Prettier write (format:check to verify)

Layout

src/ng-select/
├── lib/
│   ├── ng-select/                 # NgSelectComponent (.ts/.html/.scss) + focused specs
│   ├── dropdown-panel/            # NgDropdownPanelComponent/Service (virtual-scroll range), CDK overlay manager + container, positioning
│   ├── directives/                # ng-templates.directive.ts: ng-*-tmp template directives, ngItemLabel
│   ├── services/                  # NgSelectConfig (global defaults), ConsoleService
│   ├── types/                     # ng-select.types.ts, id.ts
│   ├── utils/                     # search-helper.ts, value-utils.ts
│   ├── ng-option.component.ts
│   ├── items-list.ts              # filtering, grouping, marking, selected options
│   ├── selection-model.ts         # SelectionModel, DefaultSelectionModel(Factory)
│   └── ng-select.module.ts        # legacy NgSelectModule
├── themes/                        # default, material, ant.design (+ _mixins.scss)
├── testing/                       # helpers, mocks, fixtures, timer helpers
└── public-api.ts
src/ng-option-highlight/lib/       # ng-option-highlight.directive.ts
src/demo/app/examples/             # one folder per demo (no app shell)
website/
├── astro.config.mjs               # base /ng-select, outDir ../dist/docs
└── src/
    ├── content/docs/{getting-started,reference,examples}/*.mdx
    ├── components/                # Demo.astro, ThemeSelect.astro (theme switcher)
    ├── angular/                   # demo-host.component.ts, examples.registry.ts, hero-select.component.ts
    └── stackblitz/                # StackBlitz starter files
scripts/generate-llms.mjs
.github/workflows/                 # ci, release, codeql, stale, deprecate, dependabot

Docs and examples

  • Embed a demo in MDX: import Demo from '@components/Demo.astro'; then <Demo example="<folder>" />.
  • New example: src/demo/app/examples/<name>-example/<name>-example.component.{ts,html,scss}, class <PascalCase(name)>ExampleComponent, selector ng-<name>-example, then add a line to the manual registry website/src/angular/examples.registry.ts.
  • Each demo is its own Angular app. Demo NgSelectConfig defaults come from DEMO_PROVIDERS in demo-host.component.ts, not a shared root injector.

Angular Conventions

  • Target Angular 22 / TypeScript 6 APIs; no deprecated APIs.

  • New code: input(), output(), model(), signal(), computed(), effect(), linkedSignal(), inject(), and control flow (@if, @for, @switch). No new @Input/@Output; don't rewrite unrelated legacy code.

  • NgSelectComponent inputs use a backward-compatible pattern. Follow it when adding inputs:

    readonly _placeholder = input<string>(this.config.placeholder, { alias: 'placeholder' });
    readonly placeholder = linkedSignal(() => this._placeholder());

    bindLabel, bindValue, appearance, isOpen, and items are model()s; outputs use output({ alias }). Give inputs an explicit type and, for booleans, transform: booleanAttribute.

  • DI: providedIn: 'root' unless scoped (NgDropdownPanelService is provided per NgSelectComponent). Global defaults via NgSelectConfig; selection override via the SELECTION_MODEL_FACTORY token (defined in ng-select.component.ts).

  • Selectors (ESLint-enforced): elements ng-* kebab-case, attribute directives ng* camelCase.

  • Templates: preserve content projection and the template directives (ng-option-tmp, ng-label-tmp, …).

  • Types: explicit types in new code; avoid any (ESLint allows it). tsconfig.json is strict: false, so match the surrounding file.

  • Libraries never do HTTP or hold app state; keep data loading (HttpClient, RxJS) in demo examples.

  • JSDoc public inputs, outputs, and methods.

Sensitive behavior

  • Forms: one NG_VALUE_ACCESSOR serves ngModel, reactive forms, and signal forms ([formField] via CVA interop). All three must keep working in single and multiple mode, including disabled/readonly and validation classes (ng-invalid, ng-touched).
  • Selection: default logic in selection-model.ts, overridable via SELECTION_MODEL_FACTORY. Don't change default semantics without single + multiple tests.
  • Dropdown: the panel renders in a CDK Overlay anchored to the select. appendTo controls DOM containment only (positioning stays viewport-based); popover is a deprecated no-op. NgDropdownPanelService does virtual-scroll measurement.
  • Accessibility: keyboard navigation (arrows, Enter, Escape, Tab, Backspace), focus management, and ARIA (ariaLabel, ariaLabelDropdown, labelForId, aria-live status) are core; regressions are high severity. ESLint enables templateAccessibility.
  • Virtual/infinite scroll interacts with ItemsList and scroll events; test with large datasets.
  • Typeahead: typeahead is a consumer-owned Subject<string>; the library emits terms once minTermLength is met and never debounces.

Themes

  • src/ng-select/themes/*.theme.scss → dist/ng-select/themes/*.theme.css (build:themes); SCSS copied to dist/ng-select/scss/ (copy-sass).
  • ViewEncapsulation.None: styles are global and theme class names are part of the public styling contract.
  • When changing styles, verify all three themes (docs site theme switcher) and validation-state styling.

Testing

  • Vitest browser mode: headless Chromium via @vitest/browser-playwright, wired through @angular/build:unit-test + vitest.config.ts. Real layout, not jsdom. No e2e suite.
  • Zoneless by default; the test-zone target (pnpm test:zone, part of test:ci) reruns specs with zone.js.
  • Timers: vi.useFakeTimers via testing/timer-helpers.ts (enableDebounceFakeTimers, advanceDebounce, openSelect), not fakeAsync/tick. Other helpers: testing/helpers.ts (tickAndDetectChanges, selectOption, triggerKeyDownEvent, …), testing/mocks.ts.
  • Specs sit next to code. NgSelectComponent behavior specs are split by area in lib/ng-select/ (ng-select.<area>.spec.ts: forms, signal-forms, selection, keyboard, overlay, events, templates, accessibility); extend the matching one.
  • Failed specs save screenshots to a __screenshots__/ folder next to the spec.
  • Don't add tests unless requested or needed to cover changed behavior; update existing specs when behavior changes.

Definition of Done

  • Trivial/medium changes: pnpm lint + pnpm build.
  • Library behavior: also pnpm exec ng test ng-select --watch=false (or pnpm test:ci).
  • Docs/examples: pnpm build:docs.
  • Formatting: pnpm exec prettier --check <changed files>.
  • Report skipped or failed checks; call out public API, accessibility, theming, and coverage impacts; update README/docs/examples when user-facing behavior or API changed.
  • Runtime verification recipe: .agents/skills/verify.

CI and Release

  • ci.yml (every PR; pushes touching ts, html, scss, mdx, mjs, astro, website/**): install → Playwright Chromium → lint → test:ci → build:docs → Coveralls.
  • release.yml (push to master): pnpm build → semantic-release publishes @ng-select/ng-select from dist/ng-select → version-synced @ng-select/ng-option-highlight → build:docs → deploy dist/docs to gh-pages.

Tooling Notes

  • pnpm-workspace.yaml patchedDependencies patches @analogjs/astro-angular (patches/); re-check the patch when upgrading it.
  • tsconfig.json path aliases map @ng-select/ng-select, @ng-select/ng-option-highlight, and @examples/* to source.
  • IDEs: use pnpm, the workspace eslint.config.js, and Prettier (.prettierrc.json).