-
Notifications
You must be signed in to change notification settings - Fork 7
✨ Add TypeScript and JavaScript comment type support (issue #69) #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 14 commits
d569bff
61468bf
4e9ef51
4d85094
28e12e1
5e7d48b
b36c271
5fbc0e7
089816f
6b726c6
852e50c
0330c0b
2ceb5b4
279c935
41fb7a9
0cc642d
4ba26b7
22322cf
f16b61c
45d6d1e
90ca459
dd7554c
2da4c49
de4dfda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| This repository already has a detailed **AGENTS.md** at the repo root — read it first for | ||
| full architecture diagrams, event-handler tables, commit/PR conventions, and common-pattern | ||
| recipes (adding a language, a marker type, a CLI command, a config option). This file only | ||
| covers what's needed to get moving quickly. | ||
|
|
||
| ## What this project is | ||
|
|
||
| sphinx-codelinks is a Sphinx extension providing fast source-code traceability for | ||
| Sphinx-Needs: it scans source files (C++, Python, C#, Rust, TypeScript, Go, YAML, JSON) for | ||
| marker comments via tree-sitter, and generates Sphinx-Needs items / RST that link | ||
| documentation back to exact source locations. | ||
|
|
||
| ## Commands | ||
|
|
||
| All commands run through `tox` (uses `tox-uv`). | ||
|
|
||
| ```bash | ||
| # Run default test env (py312-sphinx8-needs5) | ||
| tox | ||
|
|
||
| # List all test env combinations (py{312,313,314}-sphinx{7,8,9}-needs{5,6,7,8}) | ||
| tox -a | ||
|
|
||
| # Run a specific env / file / test | ||
| tox -e py312-sphinx8-needs5 | ||
| tox -e py312-sphinx8-needs5 -- tests/test_analyse.py | ||
| tox -e py312-sphinx8-needs5 -- tests/test_analyse.py::test_function_name | ||
|
|
||
| # Update syrupy snapshots | ||
| tox -e py312-sphinx8-needs5 -- --snapshot-update | ||
|
|
||
| # Type check / lint / format | ||
| tox -e mypy | ||
| tox -e ruff-check | ||
| tox -e ruff-fmt | ||
| pre-commit run --all-files | ||
|
|
||
| # Docs | ||
| tox -e docs-clean | ||
| tox -e docs-update | ||
| BUILDER=linkcheck tox -e docs-clean | ||
| tox -e docs-live | ||
|
|
||
| # End-to-end demo (analyse -> write RST -> build docs) | ||
| tox -e demo | ||
| ``` | ||
|
|
||
| The CLI itself is installed as `codelinks` (`codelinks analyse <config.toml>`, | ||
| `codelinks write rst <input.json> --outpath <file>`). | ||
|
|
||
| ## Architecture | ||
|
|
||
| Pipeline: **Source Files → Discovery → Parsing → Analysis → Results (JSON) → RST Generation** | ||
|
|
||
| - `source_discover/` — finds source files by include/exclude patterns, respects `.gitignore`. | ||
| - `analyse/oneline_parser.py` — tree-sitter based parser extracting comment marker nodes. | ||
| - `analyse/projects.py` — per-language analyzers, registered in a `LANGUAGE_ANALYZERS` dict. | ||
| - `analyse/analyse.py` — orchestrates discovery + parsing + analysis into `analyse/models.py` | ||
| Pydantic result models. | ||
| - `needextend_write.py` — turns analysis JSON into RST with Sphinx-Needs `needextend` | ||
| directives. | ||
| - `config.py` — Pydantic v2 config models (`AnalyseConfig` etc.), loadable from TOML. | ||
| - `sphinx_extension/source_tracing.py` — the Sphinx extension `setup()`; wires into Sphinx | ||
| build events (`config-inited`, `builder-inited`, `env-before-read-docs`, | ||
| `html-collect-pages`, `html-page-context`, `build-finished`) to register sphinx-needs extra | ||
| options/types, generate standalone traced-source HTML pages, and inject CSS | ||
| (`sphinx_extension/ub_sct.css`). See AGENTS.md for the full event table and mermaid diagram. | ||
|
|
||
| Adding a new language analyzer, marker type, CLI command, or config option each follow a | ||
| short recipe documented in AGENTS.md under "Common Patterns" — follow those rather than | ||
| inventing a new approach. | ||
|
|
||
| ## Code style | ||
|
|
||
| - Ruff for lint/format (strict rule set incl. `S`, `PL`, `PTH`, `SIM`, `SLF`; see | ||
| `pyproject.toml` for per-file ignores). | ||
| - Mypy strict mode (`disallow_any_*`, `disallow_untyped_*`); relaxed for `tests/*` and | ||
| `sphinx_codelinks.*` via overrides in `pyproject.toml`. | ||
| - Full type annotations everywhere; Pydantic models (frozen where possible) for config/data. | ||
| - Sphinx-style docstrings (`:param:`, `:return:`, `:raises:`), no types in docstrings. | ||
| - Prefer pure functions and immutable data structures. | ||
|
|
||
| ## Testing | ||
|
|
||
| - `pytest` with fixtures in `tests/conftest.py`; test data in `tests/data/`; Sphinx | ||
| integration tests use real minimal Sphinx projects in `tests/doc_test/`. | ||
| - `syrupy` for snapshot testing of complex outputs (JSON, doctrees) — use | ||
| `snapshot.assert_match()` and re-run with `--snapshot-update` when output intentionally | ||
| changes. | ||
| - Use `@pytest.mark.parametrize` for multi-language / multi-scenario tests. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -266,6 +266,34 @@ Features | |
| .. fault:: Sphinx-codelinks hallucinates traceability objects in Bash | ||
| :id: FAULT_BASH_2 | ||
|
|
||
| .. feature:: TypeScript Language Support | ||
| :id: FE_TS | ||
|
|
||
| Support for defining traceability objects in TypeScript and JavaScript source | ||
| files via one-line comment annotations. | ||
|
|
||
| The TypeScript language parser leverages tree-sitter to accurately identify and | ||
| extract comments from TypeScript and JavaScript sources, including single-line | ||
| (``//``) and multi-line (``/* */``) comment styles. All files are parsed with | ||
| the TSX grammar — a strict superset of the TypeScript grammar, which is in turn | ||
| a superset of JavaScript — so ``.tsx`` files (including JSX comments such as | ||
| ``{/* ... */}``) and plain JavaScript sources need no per-file grammar choice. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The advertised Inside JSX children const App = () => (
<div>
{/* @Tsx Title, IMPL_TSX, impl, [REQ_TSX] */}
</div>
);The default
|
||
|
|
||
| Key capabilities: | ||
|
|
||
| * Detection of inline and block comments | ||
| * Association of comments with function, class, and method declarations | ||
| * ``const``/``let``/``var`` declarations count as scopes only when they assign | ||
| a function or arrow function | ||
| * File extensions ``.ts``, ``.tsx``, ``.mts``, ``.cts``, ``.js``, ``.jsx``, | ||
| ``.mjs`` and ``.cjs`` auto-discovered when ``comment_type = "ts"`` | ||
|
|
||
| .. fault:: Traceability objects are not detected in TypeScript language | ||
| :id: FAULT_TS_1 | ||
|
|
||
| .. fault:: Sphinx-codelinks hallucinates traceability objects in TypeScript | ||
| :id: FAULT_TS_2 | ||
|
|
||
| .. feature:: Preprocessor-Aware C/C++ Extraction | ||
| :id: FE_PREPROC | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,19 @@ | |||||||
| Changelog | ||||||||
| ========= | ||||||||
|
|
||||||||
| Under development | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heading deviates from the established convention. Every prior pre-release cycle in this file used Unreleased
----------The PR description also says the entry was added "under
Suggested change
|
||||||||
| ----------------- | ||||||||
|
|
||||||||
| New and Improved | ||||||||
| ................ | ||||||||
|
|
||||||||
| - ✨ Added TypeScript comment type support for source discovery and analysis. | ||||||||
|
|
||||||||
| TypeScript and JavaScript files can now be processed using ``comment_type = "ts"``, | ||||||||
| since the TSX grammar used to parse them is a superset of both languages. | ||||||||
| Source discovery supports ``.ts``, ``.tsx``, ``.mts``, ``.cts``, ``.js``, | ||||||||
| ``.jsx``, ``.mjs`` and ``.cjs`` extensions by default. | ||||||||
|
|
||||||||
| .. _`release:1.4.0`: | ||||||||
|
|
||||||||
| 1.4.0 | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -28,6 +28,14 @@ | |||||||||||||||||||||||||||||
| # @C and C++ Scope Node Types, IMPL_C_2, impl, [FE_C_SUPPORT, FE_CPP] | ||||||||||||||||||||||||||||||
| CommentType.cpp: {"function_definition", "class_definition"}, | ||||||||||||||||||||||||||||||
| CommentType.cs: {"method_declaration", "class_declaration", "property_declaration"}, | ||||||||||||||||||||||||||||||
| # @TypeScript Scope Node Types, IMPL_TS_2, impl, [FE_TS] | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That is FAULT_TS_2 ("hallucinates traceability objects") for five of the most common TS declaration forms. Missing node types: |
||||||||||||||||||||||||||||||
| CommentType.ts: { | ||||||||||||||||||||||||||||||
|
ubmarco marked this conversation as resolved.
|
||||||||||||||||||||||||||||||
| "function_declaration", | ||||||||||||||||||||||||||||||
| "class_declaration", | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Class-field arrow functions resolve to the enclosing class instead of the field.
class A {
// @m
handler = () => {};
}
|
||||||||||||||||||||||||||||||
| "method_definition", | ||||||||||||||||||||||||||||||
| "lexical_declaration", | ||||||||||||||||||||||||||||||
|
ubmarco marked this conversation as resolved.
|
||||||||||||||||||||||||||||||
| "variable_declaration", | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JavaScript's dominant function-definition forms are not scope types, so markers on them mis-associate — and The scope set covers only ES declaration syntax. Assignment-based definitions — the norm in CommonJS, which is precisely what // @m
module.exports = function f(){};
function unrelated(){} // -> tagged_scope = "function unrelated(){}"
// @m
Foo.prototype.bar = function(){};
function unrelated(){} // -> tagged_scope = "function unrelated(){}"Anonymous default exports (the standard shape for React/Next.js page modules) get no scope at all: // @m
export default () => {}; // -> tagged_scope = None
// @m
export default function () {}; // -> tagged_scope = NoneWidening |
||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| # @Rust Scope Node Types, IMPL_RUST_2, impl, [FE_RUST]; | ||||||||||||||||||||||||||||||
| CommentType.rust: { | ||||||||||||||||||||||||||||||
| "function_item", | ||||||||||||||||||||||||||||||
|
|
@@ -66,6 +74,8 @@ | |||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
| CPP_QUERY = """(comment) @comment""" | ||||||||||||||||||||||||||||||
| C_SHARP_QUERY = """(comment) @comment""" | ||||||||||||||||||||||||||||||
| # @TypeScript comment query for tree-sitter, IMPL_TS_3, impl, [FE_TS] | ||||||||||||||||||||||||||||||
| TYPE_SCRIPT_QUERY = """(comment) @comment""" | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sixth verbatim copy of the same query string.
Relatedly, the |
||||||||||||||||||||||||||||||
| YAML_QUERY = """(comment) @comment""" | ||||||||||||||||||||||||||||||
| RUST_QUERY = """ | ||||||||||||||||||||||||||||||
| (line_comment) @comment | ||||||||||||||||||||||||||||||
|
|
@@ -107,7 +117,7 @@ def is_text_file(filepath: Path, sample_size: int = 2048) -> bool: | |||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # @Tree-sitter parser initialization for multiple languages, IMPL_LANG_1, impl, [FE_C_SUPPORT, FE_CPP, FE_PY, FE_YAML, FE_RUST, FE_GO, FE_JSONC, FE_BASH] | ||||||||||||||||||||||||||||||
| # @Tree-sitter parser initialization for multiple languages, IMPL_LANG_1, impl, [FE_C_SUPPORT, FE_CPP, FE_PY, FE_YAML, FE_RUST, FE_GO, FE_JSONC, FE_BASH, FE_TS] | ||||||||||||||||||||||||||||||
| def init_tree_sitter(comment_type: CommentType) -> tuple[Parser, Query]: | ||||||||||||||||||||||||||||||
| if comment_type == CommentType.cpp: | ||||||||||||||||||||||||||||||
| import tree_sitter_cpp # noqa: PLC0415 | ||||||||||||||||||||||||||||||
|
|
@@ -124,6 +134,15 @@ def init_tree_sitter(comment_type: CommentType) -> tuple[Parser, Query]: | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| parsed_language = Language(tree_sitter_c_sharp.language()) | ||||||||||||||||||||||||||||||
| query = Query(parsed_language, C_SHARP_QUERY) | ||||||||||||||||||||||||||||||
| elif comment_type == CommentType.ts: | ||||||||||||||||||||||||||||||
| import tree_sitter_typescript # noqa: PLC0415 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # The TSX grammar is a strict superset of the TypeScript grammar, which is | ||||||||||||||||||||||||||||||
| # itself a superset of JavaScript, so it also parses plain .ts and the | ||||||||||||||||||||||||||||||
| # whole JavaScript family fine. Use it for all of them to avoid needing a | ||||||||||||||||||||||||||||||
| # per-file grammar choice. | ||||||||||||||||||||||||||||||
| parsed_language = Language(tree_sitter_typescript.language_tsx()) | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The TSX grammar is not a superset of the TypeScript grammar — TypeScript deliberately forbids Reproduced against this branch: // @m1
function a() {}
const x = <string>value; // legal .ts, illegal .tsx
// @m2
function b() {}
// @m3
class C {}This is silent data loss (FAULT_TS_1), not a degraded scope. The same false "strict superset" claim is repeated in Fix: pick the grammar from the file suffix — |
||||||||||||||||||||||||||||||
| query = Query(parsed_language, TYPE_SCRIPT_QUERY) | ||||||||||||||||||||||||||||||
| elif comment_type == CommentType.yaml: | ||||||||||||||||||||||||||||||
| import tree_sitter_yaml # noqa: PLC0415 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
@@ -177,14 +196,46 @@ def extract_comments( | |||||||||||||||||||||||||||||
| return captures.get("comment") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| TS_FUNCTION_VALUE_TYPES = {"arrow_function", "function_expression"} | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The guard correctly stops a plain // @m
const gen = function* () {}; // value type: generator_function
function unrelated() {} // -> tagged_scope = "function unrelated() {}"
// @m
const A = class {}; // value type: class
function unrelated() {} // -> tagged_scope = "function unrelated() {}"
// @m
const f = (() => {}) as Handler; // value type: as_expression
function unrelated() {} // -> tagged_scope = "function unrelated() {}"Suggest adding
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def _is_function_like_lexical_declaration(node: TreeSitterNode) -> bool: | ||||||||||||||||||||||||||||||
| """True if a TS lexical/variable declaration's declarator is a function. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ``const``/``let``/``var`` declarations are only treated as scopes when they | ||||||||||||||||||||||||||||||
| assign a function or arrow function, so a leading comment doesn't bind to an | ||||||||||||||||||||||||||||||
| unrelated ``const`` that merely precedes the function it documents. | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
| for declarator in node.named_children: | ||||||||||||||||||||||||||||||
| if declarator.type != "variable_declarator": | ||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||
| value = declarator.child_by_field_name("value") | ||||||||||||||||||||||||||||||
| if value is not None and value.type in TS_FUNCTION_VALUE_TYPES: | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def _matches_scope( | ||||||||||||||||||||||||||||||
| node: TreeSitterNode, scope_types: set[str], comment_type: CommentType | ||||||||||||||||||||||||||||||
| ) -> bool: | ||||||||||||||||||||||||||||||
| if node.type not in scope_types: | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
| if comment_type == CommentType.ts and node.type in { | ||||||||||||||||||||||||||||||
| "lexical_declaration", | ||||||||||||||||||||||||||||||
| "variable_declaration", | ||||||||||||||||||||||||||||||
| }: | ||||||||||||||||||||||||||||||
| return _is_function_like_lexical_declaration(node) | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def find_enclosing_scope( | ||||||||||||||||||||||||||||||
| node: TreeSitterNode, comment_type: CommentType = CommentType.cpp | ||||||||||||||||||||||||||||||
| ) -> TreeSitterNode | None: | ||||||||||||||||||||||||||||||
| """Find the enclosing scope of a comment.""" | ||||||||||||||||||||||||||||||
| scope_types = SCOPE_NODE_TYPES.get(comment_type, SCOPE_NODE_TYPES[CommentType.cpp]) | ||||||||||||||||||||||||||||||
| current: TreeSitterNode = node | ||||||||||||||||||||||||||||||
| while current: | ||||||||||||||||||||||||||||||
| if current.type in scope_types: | ||||||||||||||||||||||||||||||
| if _matches_scope(current, scope_types, comment_type): | ||||||||||||||||||||||||||||||
| return current | ||||||||||||||||||||||||||||||
| current: TreeSitterNode | None = current.parent # type: ignore[no-redef] # required for node traversal | ||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||
|
|
@@ -197,12 +248,12 @@ def find_next_scope( | |||||||||||||||||||||||||||||
| scope_types = SCOPE_NODE_TYPES.get(comment_type, SCOPE_NODE_TYPES[CommentType.cpp]) | ||||||||||||||||||||||||||||||
| current: TreeSitterNode = node | ||||||||||||||||||||||||||||||
| while current: | ||||||||||||||||||||||||||||||
| if current.type in scope_types: | ||||||||||||||||||||||||||||||
| if _matches_scope(current, scope_types, comment_type): | ||||||||||||||||||||||||||||||
| return current | ||||||||||||||||||||||||||||||
| current: TreeSitterNode | None = current.next_named_sibling # type: ignore[no-redef] # required for node traversal | ||||||||||||||||||||||||||||||
| if current and current.type == "block": | ||||||||||||||||||||||||||||||
| if current and current.type in {"block", "export_statement"}: | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A TypeScript-only container type is hardcoded into the shared traversal, applied to every language.
Suggest a parallel per-language table so the next language adds a dict entry instead of another |
||||||||||||||||||||||||||||||
| for child in current.named_children: | ||||||||||||||||||||||||||||||
| if child.type in scope_types: | ||||||||||||||||||||||||||||||
| if _matches_scope(child, scope_types, comment_type): | ||||||||||||||||||||||||||||||
| return child | ||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,12 @@ | |
| "cpp": ["c", "ci", "cpp", "cc", "cxx", "h", "hpp", "hxx", "hh", "ihl"], | ||
| "python": ["py"], | ||
| "cs": ["cs"], | ||
| # ".mts"/".cts" are TypeScript's own ESM/CJS module variants. ".js"/".jsx"/ | ||
| # ".mjs"/".cjs" are JavaScript, covered by the same comment type because the | ||
| # TSX grammar used to parse "ts" sources is a strict superset of the | ||
| # TypeScript grammar, which is itself a superset of JavaScript, so no | ||
| # separate grammar or comment_type value is needed. | ||
| "ts": ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"], | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
declare function f(): void; // ambient_declaration > function_signature -> None
declare module "x" { } // ambient_declaration > module -> None
interface I { doThing(): void; } // -> NoneEither add |
||
| "yaml": ["yml", "yaml"], | ||
| "rust": ["rs"], | ||
| "go": ["go"], | ||
|
|
@@ -26,6 +32,8 @@ class CommentType(str, Enum): | |
| python = "python" | ||
| cpp = "cpp" | ||
| cs = "cs" | ||
| # @Support TypeScript style comments, IMPL_TS_1, impl, [FE_TS]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding one language now requires five unsynchronised edits, and divergence fails with a bare
A single per-language record (extensions + grammar module + query + scope types), with the enum derived from it, would collapse the five edits into one and make the fallback impossible. At minimum, a test asserting |
||
| ts = "ts" | ||
| yaml = "yaml" | ||
| # @Support Rust style comments, IMPL_RUST_1, impl, [FE_RUST]; | ||
| rust = "rust" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "needs": [ | ||
| { | ||
| "id": "IMPL_TS", | ||
| "title": "Ts Title", | ||
| "type": "impl", | ||
| "links": { | ||
| "links": [ | ||
| "REQ_TS" | ||
| ] | ||
| }, | ||
| "metadata": {}, | ||
| "line": 1 | ||
| } | ||
| ], | ||
| "need_refs": [], | ||
| "marked_rst": [], | ||
| "warnings": [] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "needs": [ | ||
| { | ||
| "id": "IMPL_TSX", | ||
| "title": "Tsx Title", | ||
| "type": "impl", | ||
| "links": { | ||
| "links": [ | ||
| "REQ_TSX" | ||
| ] | ||
| }, | ||
| "metadata": {}, | ||
| "line": 4 | ||
| } | ||
| ], | ||
| "need_refs": [], | ||
| "marked_rst": [], | ||
| "warnings": [] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This describes an architecture that does not exist, and points future agents at a recipe that cannot be followed.
analyse/projects.pyis 78 lines containing a singleAnalyseProjectsclass. There is noLANGUAGE_ANALYZERSdict and no per-language analyzer class anywhere in the repo:Line 66 then tells the reader that adding a language "follow[s] a short recipe documented in AGENTS.md ... follow those rather than inventing a new approach" — but that recipe (
AGENTS.md:400-417) instructs creating aBaseAnalyzersubclass and registering it inLANGUAGE_ANALYZERS, which is fiction. This PR itself could not follow it; TypeScript support landed viaSCOPE_NODE_TYPES+init_tree_sitterinanalyse/utils.py, which the new file never mentions.Also: line 13's language list omits Bash, which shipped in 1.4.0.
Since a wrong CLAUDE.md actively misdirects, it is worth either correcting these two sections against
analyse/utils.py, or dropping the architecture section and deferring to AGENTS.md. Separately, adding CLAUDE.md is unrelated to issue #69 and would be easier to review as its own PR.