Skip to content

Latest commit

 

History

History
120 lines (94 loc) · 14.6 KB

AGENTS.md

File metadata and controls

120 lines (94 loc) · 14.6 KB

AGENTS.md

Setup commands

  • Install deps: yarn install
  • Check types: yarn build
  • Check website build cd website; yarn; yarn build

Before committing

  • Run Node tests: yarn test-node
  • Run headless browser tests: yarn test-headless
  • Format code: yarn lint fix
  • Always run yarn lint fix after making changes to ensure that Biome formatting is maintained.
  • Use the exact script names from package.json; do not substitute spaced forms such as yarn test node or yarn test headless.

Test philosophy

  • Chromium is the canonical runtime for browser-capable behavior. Plain *.spec.ts files run in Chromium; use *.browser.spec.ts when the test specifically requires browser APIs, *.cross.spec.ts only for the small compatibility set that also runs in Node, and *.node.spec.ts only for genuine Node-only APIs or behavior.
  • Keep required pull-request tests fast and hermetic. Put expensive exhaustive matrices, large-fixture parses, and long fuzz corpora in *.slow.spec.ts (or *.node.slow.spec.ts), and put live-service checks in *.external.spec.ts. Fast and slow-hermetic projects must not access the public network.
  • Prefer high-signal behavior and boundary coverage over test count. Test an implementation exhaustively in its owning module, then keep only focused public-entrypoint or integration conformance in wrapper modules; do not duplicate the same fixture, call, and assertions across packages.
  • Build remote loaders.gl fixture URLs from @loaders.gl/core/constants. Its LOADERS_GL_FIXTURE_BRANCH names the branch the tests live on (master, or e.g. 4.4-release on a release branch); change it when cutting a release branch. yarn test-audit fails when a test hard-codes another branch, or when CI targets a branch other than LOADERS_GL_FIXTURE_BRANCH.
  • Use the smallest deterministic fixture that exercises the behavior. Fixtures over 1 MiB require an audited exception in the fast suite. Keep one representative large end-to-end parse in the slow lane when scale itself is meaningful.
  • Parse immutable fixture data once with beforeAll when multiple assertions inspect the same result. Tests that mutate a result must clone it or parse independently so state cannot leak between cases.
  • Write every new test case, and every substantially revised test, with native Vitest syntax (test, describe, test.each, lifecycle hooks, mocks, and expect). Do not use Tape or its retired compatibility shim; the test audit rejects these imports.
  • Coverage is enforced per non-private published modules/* package across statements, lines, functions, and branches. Never lower a committed threshold or add an exclusion merely to make coverage pass; generated, vendored, declaration, or unreachable platform-specific exclusions require an adjacent reason.
  • Run yarn test-audit after changing test structure or fixtures. Use yarn test-profile <mode> when adding costly coverage, and move any fast test file that remains above the documented performance budget into smaller fast cases plus an explicit slow case.

Test-performance pitfalls

  • More workers are not automatically faster. Four Chromium workers made this suite slower than one because parsing-heavy files contended for CPU and memory. Benchmark a worker-count change with at least three equivalent runs before changing the default.
  • Do not put every package import into one sequential compatibility test. A single all-package import smoke became a 75-second bottleneck and also tried to import browser-only @loaders.gl/video in Node. Keep Node compatibility checks lightweight and let Chromium exercise real browser package behavior.
  • Vitest setup files run once per isolated test file. A broad setup import is multiplied across the suite, so keep project setup minimal and import specialized polyfills or helpers only in the projects or tests that need them.
  • When consolidating case modules behind one aggregator, exclude the original *.spec.* files from direct discovery; otherwise every case runs twice. The aggregator must preserve named registrations so failures still identify the original case.
  • Moving or deleting a spec can leave a stale side-effect import in a legacy test/index.ts. Check package test entrypoints as well as Vitest discovery; a missing import may appear only when another package imports that test subpath.
  • yarn build cleans package dist directories, including previously built worker bundles. Run yarn build-workers after the final build and before browser tests; otherwise worker URLs return Vite's HTML fallback and fail with Unexpected token '<'.
  • A remote URL may be stored in a constant and evade a simple static fetch('https://…') scan. Keep the runtime outbound-network blocker enabled for hermetic projects in addition to the source audit.
  • Splitting tests into shards does not reduce critical-path time if shards run sequentially in one CI job. Put shards in separate matrix jobs, give blob artifacts unique names, and merge all reports before evaluating test counts or coverage.
  • Coverage from a browser shard, the reduced Node suite, or a moved slow case is incomplete on its own. Enforce thresholds only after merging all browser shards, Node coverage, and coverage from the hermetic slow tests selected for the change. Keep a browser-only ratchet so Node or slow coverage cannot hide a browser regression.
  • Vitest 4 removed coverage.all; explicit coverage.include is what keeps unexecuted production files in the denominator. Do not reintroduce obsolete settings when tuning coverage.
  • File size is only a proxy for cost. For example, a moderately sized LAZ fixture can expand to hundreds of thousands of points and dominate runtime. Use profile results and decoded record counts in addition to bytes when deciding whether a case belongs in the slow lane.
  • Runtime if (isBrowser) returns still pay file discovery, setup, and import costs. Prefer project/file naming (.node, .cross, .slow, .external) so the wrong runtime never collects the file.

GitHub

  • If gh authentication fails, check whether the authenticated GitHub plugin is available before treating GitHub access as blocked.
  • When opening a pull request, verify that its description renders as properly formatted Markdown with real newlines, headings, and lists; do not submit a description with escaped or flattened newlines.

Babysitting pull requests

  • After opening a PR, or when asked to address reviews or babysit it, own the work until the latest revision is ready for merge. Continue after pushing fixes; local success alone does not finish the task.
  • Wait 15 minutes after opening a PR for review comments, as in luma.gl. Use that time to inspect CI and coverage, and address comments as they arrive.
  • Close the loop on every actionable review thread: implement the fix, add focused regression coverage when appropriate, run the required build/tests/formatting after the final changes, reply with what changed and how it was verified, then resolve the thread. Recheck for newly posted comments after each push.
  • Keep the branch current with master, resolve merge conflicts promptly, and recheck mergeability after every push.
  • Inspect all required CI checks and coverage on the latest head commit. Investigate failures; rerun transient jobs when the evidence supports it. Never lower coverage thresholds or add exclusions merely to make the PR pass.
  • Treat CI as the final gate after review changes. Older successful runs and focused local checks do not replace green required checks on the current revision. Do not declare readiness while checks are failing or pending.
  • Before finishing, recheck review threads, current master, mergeability, and the latest checks. A ready PR has no outstanding actionable review threads, passes every required check and coverage gate, and has an accurate Markdown description.
  • Report the PR link, review fixes, verification, and any remaining blockers. Do not merge unless the user asks to merge.

Ready for merge

  • Add or update TSDoc for every new class, function, method, and field.
  • Update docs when behavior, public API, examples, or migration guidance changed.
  • Make sure yarn.lock is up to date by running yarn in the repo root.
  • Run build: yarn build
  • Run Node tests: yarn test-node
  • Run headless browser tests: yarn test-headless
  • Format code: yarn lint fix
  • Provide a copyable markdown PR description, compared to master, that starts with goals of the PR and then lists actual changes.

Code style

  • TypeScript strict mode
  • Single quotes, no semicolons
  • Never abbreviate variables, always type out the full name in camelCase (variables, functions, fields), PascalCase (types), CAPITAL_CASE (constant)
  • Add TSDoc to all new classes, functions, methods, fields.
  • Prefer verbNoun structure for function and method names.
  • Prefer readonly fields over getters for fixed or constructor-derived values.
  • We end JavaScript statements with semicolons. Do not remove semicolons.

Notes

  • Keep NPM_TAG in modules/core/src/constants/index.ts set to beta on master and latest on release branches. Update LOADERS_GL_FIXTURE_BRANCH when cutting a release branch.

  • Keep @loaders.gl/core/polyfills independent: its implementation must not import the core root, other core subpath entry points, or other @loaders.gl/* modules. Put the small Node-specific helpers it needs inside the polyfills subpath instead of creating package or entry-point cycles.

  • Published loaders.gl modules may import independent @loaders.gl/core/* subpaths when they need those APIs. Declare @loaders.gl/core as a peer dependency, not an exact runtime dependency, and never list a subpath as a package dependency. Keep the core root entry point independent of optional subpath dependencies.

  • Avoid importing node specific files unless in specific functions that are intentionally designed to handle both cases. For instance, fetchFile handles both browser and Node.js, so importing fs is almost never required.

  • In package.json browser fields, use relative replacements that match actual emitted files in the current layout: pair ./src/...*.ts entries with the corresponding ./dist/...*.js entries, and map each one either to a real browser shim file or to false. Do not leave stale paths such as old dist/esm targets or entries for files that do not exist in that module.

  • Keep the upgrade guide focused on deleted or deprecated functionality. New feature documentation belongs in the module docs and release notes instead.

  • Running module- or file-scoped commands such as tsc tends to generate .js and .d.ts files in this repo. After such commands, check for generated files and remove them before finishing.

  • Running tests that use workers requires yarn build first so the worker bundles exist before the tests run.

  • Loader-required geometry construction belongs in focused @loaders.gl/core/arrow-geometry entry points, with metadata types/helpers in @loaders.gl/core/schema. The GIS compatibility package has been removed; do not restore imports or implementations under that package.

  • @loaders.gl/core/geoarrow is an opt-in utility subpath providing the richer converter and processing APIs for geospatial tables, especially GeoArrow-formatted Arrow tables.

  • Loaders should not import the larger @loaders.gl/core/geoarrow module; applications can install and use it when they need more extensive geospatial processing.

Loader module structure

  • Use modules/tables/src/csv as the reference shape for loader modules that want a lightweight root import and an implementation subpath.
  • The package root src/index.ts should export metadata-only loaders, deprecated *WorkerLoader aliases if needed for compatibility, writers, and shared public types/options. It should not export *WithParser loaders.
  • Each public metadata loader should live in its own *-loader-types.ts file. That file should contain the loader metadata, options, default values, and an optional preload() function, but no parse, parseSync, parseText, or parseInBatches methods.
  • preload() should use a static package-subpath import such as await import('@loaders.gl/tables/csv-loader'), and return the parser-bearing loader export. Prefer static package imports over relative paths or computed import specifiers.
  • Each parser-bearing loader should live in its own *-loader.ts file and export only the *WithParser loader. Keep parser logic out of the metadata file.
  • Move shared constants, option defaults, and types needed by both metadata and parser files into neutral shared files to avoid cycles.
  • Keep writer entry points unchanged unless the package is intentionally splitting them as well.
  • In package.json, keep explicit subpath exports for parser entry points such as ./csv-loader and ./csv-arrow-loader. Root exports stay metadata-only; direct parser access happens through the subpath.
  • Core async APIs may accept metadata loaders and upgrade them through preload(). Sync parsing paths should continue to require a parser-bearing loader.

Core utility subpaths

  • Core utility subpaths may contain format-neutral scan, geometry construction, conversion, and codec helpers. Actual format loader/writer descriptors and format-specific source adapters belong in their format modules.

  • Keep scan, arrow-geometry, geoarrow, and wkt out of the core root exports. Core implementations must not import other loaders.gl packages; database backends register against core scan APIs from the SQL package.

  • The standalone scan, arrow-geometry, and geoarrow packages are removed. Do not restore forwarding packages or compatibility dependency edges.

  • LAS/LAZ, PCD and PLY implementations belong in @loaders.gl/pointclouds format subpaths; PLY retains both point-cloud and mesh/face support. COPC and Potree remain in tiles-3d.

  • Scene owns OBJ/MTL, glTF/GLB and USD through /obj, /gltf and /usd; geospatial owns WKT/WKB/TWKB loaders and writers. Do not restore their removed standalone packages.

  • Pointclouds, scene and Draco use Arrow transport directly from core/schema-utils/arrow-transport, without tables forwarding imports or dependencies.

  • Texture and video implementations belong in @loaders.gl/images. Keep its root loaders metadata-only and expose parsers, texture writers, schemas, and helpers through direct subpaths. Do not restore standalone texture/video compatibility packages.

  • Basic XML, HTML, YAML, TOML, BSON, and Markdown loaders belong in @loaders.gl/documents. Keep its root metadata-only and parser imports flat (/xml-loader, /bson-loader, /markdown-loader); BSON codecs and writers use /bson-codec and /bson-writer. Do not restore XML/config packages or tables BSON forwarding exports. Parquet uses the documents BSON codec.