diff --git a/.gitignore b/.gitignore index 8165fa159..bce2eee4d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ vendor/ .idea/ .phpstan/ /.phpunit.cache/test-results +/.claude/settings.local.json diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 000000000..6c727694e --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,93 @@ +# swagger-php + +A PHP library that generates OpenAPI specification documents from PHP source code +by scanning annotations (attributes and docblocks) and processing them into a +complete spec. + +## Language + +### Core Concepts + +**Annotation**: +An OpenAPI specification element declared as a PHP 8+ attribute or legacy docblock comment on a class, method, or property. +_Avoid_: Attribute (too narrow), decorator, metadata + +**Analysis**: +The aggregate result of scanning source code — contains all discovered annotations and structural definitions, before processing. +_Avoid_: Result, scan output + +**Context**: +Nested metadata describing where an annotation was found in the source hierarchy (file, namespace, class, method, property). +_Avoid_: Location, position + +**Generator**: +The orchestrator that coordinates scanning, processing, and output — it generates an OpenAPI spec from annotations, not code from a spec. +_Avoid_: Builder, compiler + +**Processor**: +A single transformation step in an ordered pipeline that converts raw Analysis into a valid, complete OpenAPI specification. +_Avoid_: Handler, middleware, transformer + +### Annotation Lifecycle + +**Unmerged**: +An annotation that has been discovered but not yet incorporated into the target OpenAPI root object. +_Avoid_: Pending, orphaned + +**Merge**: +Incorporating an annotation into its correct position within the OpenAPI object tree, guided by the nesting map. +_Avoid_: Combine, attach + +**Augment**: +Filling in missing annotation fields with values inferred from code (e.g. deriving a schema type from a PHP type hint). +_Avoid_: Enrich, hydrate + +**Expand**: +Resolving PHP inheritance (classes, interfaces, traits, enums) by copying parent annotations into child schemas. +_Avoid_: Inherit, flatten + +### Structural Concepts + +**Nesting**: +The declarative parent-child mapping (`$_nested`) that defines which annotation types can belong inside other annotation types — distinct from PHP class inheritance. +_Avoid_: Hierarchy (ambiguous with class hierarchy) + +**Component**: +A reusable named definition stored in `#/components/` and referenced via `$ref` elsewhere in the spec. +_Avoid_: Shared schema, template + +**Ref**: +A JSON Pointer (`$ref`) linking to another part of the spec, resolved by processors into `#/components/...` paths. +_Avoid_: Link (means something else in OpenAPI), pointer + +### Scanning + +**Analyser**: +Reflects on PHP source files to discover annotations and produce an Analysis. +_Avoid_: Scanner (too narrow — TokenScanner is a sub-component), parser + +**AnnotationFactory**: +Creates annotation objects from discovered PHP attributes or docblock comments during analysis. +_Avoid_: Builder, constructor + +## Relationships + +- A **Generator** uses an **Analyser** to produce an **Analysis** +- An **Analysis** contains **Annotations**, each carrying a **Context** +- **Processors** run sequentially on an **Analysis**, first **merging** unmerged annotations, then **expanding** inheritance, then **augmenting** missing fields +- **Nesting** defines where an **Annotation** can be merged within the OpenAPI tree +- A **Component** is an **Annotation** that has been merged into `#/components/` and is reachable by **Ref** + +## Example dialogue + +> **Dev:** "I added a `@OA\Schema` on a class but it's not appearing in the output." +> **Domain expert:** "Is it still **unmerged**? Check that the **nesting** map allows it to be **merged** into Components, and that a **processor** hasn't filtered it out." + +> **Dev:** "Why does the child class schema include the parent's properties?" +> **Domain expert:** "That's **expansion** — the ExpandClasses **processor** copies parent **annotations** into the child during the pipeline." + +## Flagged ambiguities + +- "generate" — resolved: reserve for the full end-to-end pipeline (`Generator::generate()`). Use **analyse** for the discovery phase and **serialize** for producing JSON/YAML output. +- "merge" — resolved: reserve for tree-placement (moving an annotation into its correct position in the OpenAPI object). Combining multiple annotations' fields into one (e.g. Properties into a Schema) is part of **augment**. +- "nested" — resolved: use **nesting map** when referring to the `$_nested` declaration. Use **enclosing** when talking about the physical source code structure (file, class, method) that Context tracks. \ No newline at end of file diff --git a/docs/guide/under-the-hood.md b/docs/guide/under-the-hood.md index 69a0c3e12..732b7cfc3 100644 --- a/docs/guide/under-the-hood.md +++ b/docs/guide/under-the-hood.md @@ -4,8 +4,7 @@ - The `Generator` iterates over the given sources (Symfony `Finder`, file/directory list, etc.) - The configured analyser (`AnalyserInterface`) reads the files and builds an `Analysis` object. - Default (as of v4) is the `ReflectionAnalyser`. Alternatively, there is the `TokenAnalyser` which was the default in v3. -- The legacy `TokenAnalyser` was removed in v5. + The default is the `ReflectionAnalyser`. - The `Analysis` object and its annotations are then processed by the configured processors. - If enabled, the analysis/annotations are validated. - The root `OpenApi` annotation then contains all annotations and is serialized into YAML/JSON. @@ -15,7 +14,7 @@ Each annotation is associated with a unique `Context` instance. This contains details, collected by the parser/analyser, about the PHP context where the annotation was found. -Typically, there will be a processor that uses the data to augment/enrich the annotation. +Typically, there will be a processor that uses the data to augment the annotation. **Examples of the data collected:** - class/interface/trait/enum names