Skip to content

Commit b3cd037

Browse files
committed
🔨 add AI Coding Agent Guide to .github directory
1 parent 3f89390 commit b3cd037

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

.github/copilot-instructions.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
## qs_dart – AI Coding Agent Guide
2+
3+
Purpose: Provide just enough project context so an AI assistant can make correct, idiomatic edits fast. Keep responses concrete, reflect existing patterns, and avoid generic advice.
4+
5+
### 1. Architecture & Core Concepts
6+
* Library type: Pure Dart package (query string codec) ported from Node.js `qs` with near‑parity semantics.
7+
* Public surface (`lib/qs_dart.dart`) re‑exports:
8+
- Top‑level `decode` / `encode` (wrappers around `QS.decode` / `QS.encode`).
9+
- Option models: `DecodeOptions`, `EncodeOptions`, enums (`Duplicates`, `ListFormat`, `Format`, `Sentinel`, `DecodeKind`).
10+
- `Undefined` sentinel (marks intentionally omitted values during encoding/merging).
11+
- `Uri` extensions (`src/uri.dart`) for ergonomic integration.
12+
* Implementation split:
13+
- `src/qs.dart` orchestrates encode/decode; heavy lifting delegated to private `part` files `extensions/decode.dart` & `extensions/encode.dart` and utility helpers in `utils.dart`.
14+
- `utils.dart` centralizes low‑level merging (`Utils.merge`), compaction (`Utils.compact`), scalar detection, percent encoding, HTML entity handling.
15+
- Option classes encode guard‑rails: depth, parameterLimit, listLimit, charsetSentinel, etc.
16+
* Design principle: mirror Node `qs` behavior while remaining Dart‑idiomatic (ordered `Map<String, dynamic>`, explicit options objects, strong enums instead of magic strings).
17+
18+
### 2. Key Behavioral Nuances (Don’t Break These)
19+
* Decode limits: default `depth=5`, `parameterLimit=1000`, `listLimit=20`; exceeding may coerce indices into object keys or (with strict flags) throw.
20+
* List vs Map merging mimics Node: duplicate keys accumulate to lists unless `duplicates` option changes strategy.
21+
* `Undefined` entries are placeholders stripped by `Utils.compact` post‑decode / during encode pruning; never serialize `Undefined` itself.
22+
* Charset sentinel: when `charsetSentinel=true`, `utf8=✓` token (encoded differently per charset) overrides provided `charset` and is omitted from output.
23+
* `allowDots` & `decodeDotInKeys`: invalid combination (`decodeDotInKeys: true` with `allowDots: false`) must throw (constructor asserts). Preserve that invariant.
24+
* Negative `listLimit` disables numeric indexing; with `throwOnLimitExceeded` certain pushes must throw `RangeError` (match existing patterns in decode logic—consult decode part file before altering behavior).
25+
* Encoding pipeline can inject custom encoder/decoder hooks; preserve argument order and named params (`charset`, `format`, `kind`).
26+
27+
### 3. Source Conventions
28+
* Public APIs: lowerCamelCase; files: snake_case; enums: PascalCase members.
29+
* Avoid printing (`avoid_print` lint); no side‑effects outside encode/decode.
30+
* Keep option constructors const & validating invariants via `assert`.
31+
* Prefer extension methods & small helpers over large monolithic functions.
32+
* Maintain iteration order: when converting iterables to maps use string indices (`Utils.createIndexMap`); merging may temporarily use `SplayTreeMap` for deterministic ordering.
33+
34+
### 4. Testing Strategy
35+
* Unit tests in `test/unit/` mirror README examples & edge cases (list formats, depth, duplicates, charsets, null handling, custom hooks).
36+
* E2E tests in `test/e2e/` exercise higher‑level URI extensions.
37+
* Comparison tests (`test/comparison/`) ensure parity with the JS implementation via fixture JSON & a Node script; run `test/comparison/compare_outputs.sh` after semantic changes to core encode/decode logic.
38+
* When adding behavior, first add/modify a unit test replicating the JS `qs` behavior (consult upstream if uncertain), then adjust implementation.
39+
40+
### 5. Dev Workflow / Commands
41+
* Install deps: `make install` (wraps `dart pub get`).
42+
* Quality gate before commits/PR: `make sure` (analyze + format check + tests). Always keep CI green.
43+
* Run tests: `make test` (VM platform). Add coverage: `make show_test_coverage` → opens HTML at `coverage/html/index.html`.
44+
* Formatting: `make format` (or `dart format .`); never commit unformatted code.
45+
* Dependency upgrades: `make upgrade`; check outdated: `make check_outdated`.
46+
47+
### 6. Adding / Modifying Features (Checklist)
48+
1. Write or update a focused test under `test/unit/` (mirroring file/module naming).
49+
2. If changing cross‑language semantics, update comparison fixtures & run the comparison script.
50+
3. Implement minimal changes: prefer editing encode/decode parts or localized helpers in `utils.dart` rather than inflating public API.
51+
4. Update README only if user‑visible behavior changes (options, defaults, new enum values). Keep examples minimal and consistent with test expectations.
52+
5. Run `make sure`; fix lint warnings as errors.
53+
54+
### 7. Common Pitfalls for Agents
55+
* DO NOT expose new symbols via `qs_dart.dart` unless intentionally part of the public contract.
56+
* Avoid broad refactors of `utils.dart`; many subtle invariants (Undefined pruning, ordering, surrogate pair handling) are covered by tests—modify surgically.
57+
* Keep percent‑encoding logic streaming & segment‑aware (`_segmentLimit=1024`) to preserve performance.
58+
* When adding an option: ensure const constructor, add to `copyWith` (if present in file—verify before editing), equality via `EquatableMixin`, and README table/example.
59+
* Ensure new enums get exported in `qs_dart.dart` only if needed by library consumers (options signatures, return types).
60+
61+
### 8. Performance Considerations
62+
* Encoding avoids splitting surrogate pairs when chunking strings; preserve that loop structure.
63+
* Merge uses structural checks to decide list append vs map merge; naive rebuilding can degrade performance & ordering.
64+
* Avoid recursive deep traversal for compaction—current iterative approach prevents stack overflows on adversarial inputs.
65+
66+
### 9. Error Handling Expectations
67+
* Input type validation: non‑String/non‑Map to `QS.decode` must throw `ArgumentError.value` (message currently: 'The input must be a String or a Map<String, dynamic>'). Keep wording for stable tests.
68+
* Depth/list/parameter overflows toggle between soft limiting or throwing depending on `strictDepth` / `throwOnLimitExceeded` flags; never silently ignore an explicit strict flag.
69+
70+
### 10. Documentation & Examples
71+
* README examples double as test patterns—when you change semantics, sync both.
72+
* Keep code comments concise; prefer section banners only where logic is subtle (merging, encoding loops).
73+
74+
### 11. Commit / PR Style
75+
* Commit subject prefix emoji (e.g., `:sparkles: Add X`, `:bug:` etc.) aligned with existing history.
76+
* PRs: link issues, state behavior changes, mention any parity deviations from Node `qs`.
77+
78+
### 12. Safe Extension Ideas (Low Risk)
79+
* Additional list formats or duplicate strategies: introduce enum value + guarded branch + tests.
80+
* Extra utility for selective key removal during encode (implemented via `filter` lambda) — prefer documenting patterns rather than expanding API unless necessary.
81+
82+
If anything above is unclear or you need deeper decode/encode part internals, request those specific files before editing them.
83+
84+
---
85+
Feedback welcome: highlight unclear invariants or missing edge cases so we can refine this guide.

0 commit comments

Comments
 (0)