modwire-extraction 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modwire_extraction-1.0.0/LICENSE +21 -0
- modwire_extraction-1.0.0/MANIFEST.in +5 -0
- modwire_extraction-1.0.0/PKG-INFO +98 -0
- modwire_extraction-1.0.0/README.md +72 -0
- modwire_extraction-1.0.0/pyproject.toml +78 -0
- modwire_extraction-1.0.0/setup.cfg +4 -0
- modwire_extraction-1.0.0/src/modwire_extraction/__init__.py +3 -0
- modwire_extraction-1.0.0/src/modwire_extraction/_version.py +6 -0
- modwire_extraction-1.0.0/src/modwire_extraction/code/__init__.py +20 -0
- modwire_extraction-1.0.0/src/modwire_extraction/code/code_map.py +30 -0
- modwire_extraction-1.0.0/src/modwire_extraction/code/query.py +223 -0
- modwire_extraction-1.0.0/src/modwire_extraction/dependency/__init__.py +6 -0
- modwire_extraction-1.0.0/src/modwire_extraction/dependency/graph.py +126 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extraction.py +35 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/__init__.py +2 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/__init__.py +7 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/base.py +219 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/loader.py +28 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/php/build.php +50 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/php/composer.json +14 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/php/composer.lock +77 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/php/script.php +0 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/php/script.src.php +785 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/php/source.py +26 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/python/script.py +1000 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/python/source.py +21 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/build.mjs +29 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/package-lock.json +351 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/package.json +16 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/script.js +234645 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/script.ts +1110 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/source.py +26 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/languages/typescript/tsconfig.json +14 -0
- modwire_extraction-1.0.0/src/modwire_extraction/extractors/source.py +200 -0
- modwire_extraction-1.0.0/src/modwire_extraction.egg-info/PKG-INFO +98 -0
- modwire_extraction-1.0.0/src/modwire_extraction.egg-info/SOURCES.txt +43 -0
- modwire_extraction-1.0.0/src/modwire_extraction.egg-info/dependency_links.txt +1 -0
- modwire_extraction-1.0.0/src/modwire_extraction.egg-info/requires.txt +7 -0
- modwire_extraction-1.0.0/src/modwire_extraction.egg-info/top_level.txt +1 -0
- modwire_extraction-1.0.0/tests/fixtures/python/ignored/generated.py +5 -0
- modwire_extraction-1.0.0/tests/fixtures/python/src/application/use_cases/activate.py +26 -0
- modwire_extraction-1.0.0/tests/fixtures/python/src/domain/model/user.py +11 -0
- modwire_extraction-1.0.0/tests/fixtures/python/src/domain/services/policy.py +10 -0
- modwire_extraction-1.0.0/tests/fixtures/python/src/interfaces/http/controller.py +14 -0
- modwire_extraction-1.0.0/tests/test_python_functional.py +215 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 9orky
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
recursive-include src/modwire_extraction/extractors/languages *.js *.json *.lock *.mjs *.php *.py *.ts
|
|
3
|
+
recursive-exclude src/modwire_extraction/extractors/languages/typescript/node_modules *
|
|
4
|
+
recursive-exclude src/modwire_extraction/extractors/languages/php/vendor *
|
|
5
|
+
recursive-include tests/fixtures *.py
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: modwire-extraction
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Extraction implementation for modwire.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/9orky/modwire-extraction
|
|
7
|
+
Project-URL: Repository, https://github.com/9orky/modwire-extraction
|
|
8
|
+
Project-URL: Issues, https://github.com/9orky/modwire-extraction/issues
|
|
9
|
+
Keywords: code-analysis,dependency-graph,extraction
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pydantic>=2.8
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
22
|
+
Requires-Dist: pyright>=1.1; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
24
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# modwire-extraction
|
|
28
|
+
|
|
29
|
+
Extraction implementation for Modwire.
|
|
30
|
+
|
|
31
|
+
The primary API starts from `ModwireExtraction`:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
|
|
36
|
+
from modwire_extraction import ModwireExtraction
|
|
37
|
+
|
|
38
|
+
queryable_map = ModwireExtraction(Path("src")).generate_queryable_map("python")
|
|
39
|
+
print(queryable_map.source_ids())
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Public data and query helpers are exported from:
|
|
43
|
+
|
|
44
|
+
- `modwire_extraction` for `ModwireExtraction`.
|
|
45
|
+
- `modwire_extraction.code` for `CodeMap`, `QueryableCodeMap`, and query result types.
|
|
46
|
+
- `modwire_extraction.dependency` for dependency graph helpers.
|
|
47
|
+
- `modwire_extraction.extractors` for extractor loading.
|
|
48
|
+
|
|
49
|
+
## Compatibility notes
|
|
50
|
+
|
|
51
|
+
The public Python import paths listed above are the supported API surface for
|
|
52
|
+
1.0.0.
|
|
53
|
+
|
|
54
|
+
Dependency graph edges use normalized import strings. Imports such as
|
|
55
|
+
`domain/model/user` are not represented as the source ID
|
|
56
|
+
`src/domain/model/user`.
|
|
57
|
+
|
|
58
|
+
Serialized `CodeMap` JSON is intended for same-version interchange in 1.0.0.
|
|
59
|
+
Do not treat the JSON shape as a cross-version compatibility contract yet.
|
|
60
|
+
|
|
61
|
+
TypeScript and PHP helper build files are included as package data because
|
|
62
|
+
they are part of the bundled extractor runtimes and reproducible maintenance
|
|
63
|
+
path.
|
|
64
|
+
|
|
65
|
+
## Install
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install modwire-extraction
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Python extraction works with the active Python interpreter. TypeScript,
|
|
72
|
+
JavaScript, TSX, and JSX extraction require `node` on `PATH`. PHP extraction
|
|
73
|
+
requires `php` on `PATH`.
|
|
74
|
+
|
|
75
|
+
## Development
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python -m pip install -e ".[dev]"
|
|
79
|
+
pytest
|
|
80
|
+
python -m build
|
|
81
|
+
twine check dist/*
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Before publishing manually, choose the release version in `pyproject.toml`,
|
|
85
|
+
remove stale local artifacts, build a fresh distribution, and upload only the
|
|
86
|
+
expected version files:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
rm -rf build dist src/*.egg-info
|
|
90
|
+
python -m build
|
|
91
|
+
twine check dist/*
|
|
92
|
+
twine upload dist/modwire_extraction-1.0.0*
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The preferred release path is GitHub Actions. Publish a GitHub Release tagged
|
|
96
|
+
`vX.Y.Z` or `X.Y.Z` after configuring PyPI Trusted Publishing for workflow
|
|
97
|
+
`workflow.yml` and GitHub Environment `pypi`. The release workflow sets the
|
|
98
|
+
package version from the release tag before building.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# modwire-extraction
|
|
2
|
+
|
|
3
|
+
Extraction implementation for Modwire.
|
|
4
|
+
|
|
5
|
+
The primary API starts from `ModwireExtraction`:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from modwire_extraction import ModwireExtraction
|
|
11
|
+
|
|
12
|
+
queryable_map = ModwireExtraction(Path("src")).generate_queryable_map("python")
|
|
13
|
+
print(queryable_map.source_ids())
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Public data and query helpers are exported from:
|
|
17
|
+
|
|
18
|
+
- `modwire_extraction` for `ModwireExtraction`.
|
|
19
|
+
- `modwire_extraction.code` for `CodeMap`, `QueryableCodeMap`, and query result types.
|
|
20
|
+
- `modwire_extraction.dependency` for dependency graph helpers.
|
|
21
|
+
- `modwire_extraction.extractors` for extractor loading.
|
|
22
|
+
|
|
23
|
+
## Compatibility notes
|
|
24
|
+
|
|
25
|
+
The public Python import paths listed above are the supported API surface for
|
|
26
|
+
1.0.0.
|
|
27
|
+
|
|
28
|
+
Dependency graph edges use normalized import strings. Imports such as
|
|
29
|
+
`domain/model/user` are not represented as the source ID
|
|
30
|
+
`src/domain/model/user`.
|
|
31
|
+
|
|
32
|
+
Serialized `CodeMap` JSON is intended for same-version interchange in 1.0.0.
|
|
33
|
+
Do not treat the JSON shape as a cross-version compatibility contract yet.
|
|
34
|
+
|
|
35
|
+
TypeScript and PHP helper build files are included as package data because
|
|
36
|
+
they are part of the bundled extractor runtimes and reproducible maintenance
|
|
37
|
+
path.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install modwire-extraction
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Python extraction works with the active Python interpreter. TypeScript,
|
|
46
|
+
JavaScript, TSX, and JSX extraction require `node` on `PATH`. PHP extraction
|
|
47
|
+
requires `php` on `PATH`.
|
|
48
|
+
|
|
49
|
+
## Development
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python -m pip install -e ".[dev]"
|
|
53
|
+
pytest
|
|
54
|
+
python -m build
|
|
55
|
+
twine check dist/*
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Before publishing manually, choose the release version in `pyproject.toml`,
|
|
59
|
+
remove stale local artifacts, build a fresh distribution, and upload only the
|
|
60
|
+
expected version files:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
rm -rf build dist src/*.egg-info
|
|
64
|
+
python -m build
|
|
65
|
+
twine check dist/*
|
|
66
|
+
twine upload dist/modwire_extraction-1.0.0*
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The preferred release path is GitHub Actions. Publish a GitHub Release tagged
|
|
70
|
+
`vX.Y.Z` or `X.Y.Z` after configuring PyPI Trusted Publishing for workflow
|
|
71
|
+
`workflow.yml` and GitHub Environment `pypi`. The release workflow sets the
|
|
72
|
+
package version from the release tag before building.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "modwire-extraction"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Extraction implementation for modwire."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"pydantic>=2.8",
|
|
14
|
+
]
|
|
15
|
+
keywords = ["code-analysis", "dependency-graph", "extraction"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/9orky/modwire-extraction"
|
|
27
|
+
Repository = "https://github.com/9orky/modwire-extraction"
|
|
28
|
+
Issues = "https://github.com/9orky/modwire-extraction/issues"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"build>=1.2",
|
|
33
|
+
"pyright>=1.1",
|
|
34
|
+
"pytest>=8",
|
|
35
|
+
"twine>=5",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"pyright>=1.1",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[tool.pyright]
|
|
44
|
+
include = ["src"]
|
|
45
|
+
extraPaths = ["src"]
|
|
46
|
+
venvPath = "."
|
|
47
|
+
venv = ".venv"
|
|
48
|
+
pythonVersion = "3.11"
|
|
49
|
+
typeCheckingMode = "strict"
|
|
50
|
+
reportAbstractUsage = "error"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools]
|
|
53
|
+
package-dir = {"" = "src"}
|
|
54
|
+
include-package-data = true
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
where = ["src"]
|
|
58
|
+
namespaces = true
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.package-data]
|
|
61
|
+
"modwire_extraction.extractors.languages.python" = [
|
|
62
|
+
"*.py",
|
|
63
|
+
]
|
|
64
|
+
"modwire_extraction.extractors.languages.php" = [
|
|
65
|
+
"*.php",
|
|
66
|
+
"*.json",
|
|
67
|
+
"*.lock",
|
|
68
|
+
]
|
|
69
|
+
"modwire_extraction.extractors.languages.typescript" = [
|
|
70
|
+
"*.js",
|
|
71
|
+
"*.json",
|
|
72
|
+
"*.mjs",
|
|
73
|
+
"*.ts",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
testpaths = ["tests"]
|
|
78
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .code_map import CodeMap
|
|
2
|
+
from .query import (
|
|
3
|
+
DependencyEdgeResult,
|
|
4
|
+
DependencyNodeResult,
|
|
5
|
+
QueryableCodeMap,
|
|
6
|
+
QueryBuilder,
|
|
7
|
+
SourceFileResult,
|
|
8
|
+
SourceItemResult,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"CodeMap",
|
|
14
|
+
"DependencyEdgeResult",
|
|
15
|
+
"DependencyNodeResult",
|
|
16
|
+
"QueryableCodeMap",
|
|
17
|
+
"QueryBuilder",
|
|
18
|
+
"SourceFileResult",
|
|
19
|
+
"SourceItemResult",
|
|
20
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict
|
|
6
|
+
|
|
7
|
+
from ..dependency.graph import DependencyGraph
|
|
8
|
+
from ..extractors.languages.base import SourceExtraction
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CodeMap(BaseModel):
|
|
12
|
+
model_config = ConfigDict(frozen=True)
|
|
13
|
+
|
|
14
|
+
language: str
|
|
15
|
+
extraction: SourceExtraction
|
|
16
|
+
dependency_graph: DependencyGraph
|
|
17
|
+
|
|
18
|
+
def to_dict(self) -> dict[str, Any]:
|
|
19
|
+
return self.model_dump(mode="python")
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def from_dict(cls, payload: object) -> CodeMap:
|
|
23
|
+
return cls.model_validate(payload)
|
|
24
|
+
|
|
25
|
+
def to_json(self) -> str:
|
|
26
|
+
return self.model_dump_json()
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_json(cls, payload: str | bytes) -> CodeMap:
|
|
30
|
+
return cls.model_validate_json(payload)
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Generic, TypeVar
|
|
6
|
+
|
|
7
|
+
from ..dependency.graph import Edge, Node
|
|
8
|
+
from ..extractors.source import (
|
|
9
|
+
SourceAbstractClass,
|
|
10
|
+
SourceCall,
|
|
11
|
+
SourceCallable,
|
|
12
|
+
SourceClass,
|
|
13
|
+
SourceExport,
|
|
14
|
+
SourceFile,
|
|
15
|
+
SourceFunction,
|
|
16
|
+
SourceImport,
|
|
17
|
+
SourceInterface,
|
|
18
|
+
SourceType,
|
|
19
|
+
SourceValue,
|
|
20
|
+
)
|
|
21
|
+
from .code_map import CodeMap
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
T = TypeVar("T")
|
|
25
|
+
SourceItem = TypeVar("SourceItem")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class QueryBuilder(Generic[T]):
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
items: Iterable[T],
|
|
32
|
+
predicates: tuple[Callable[[T], bool], ...] = (),
|
|
33
|
+
):
|
|
34
|
+
self._items = tuple(items)
|
|
35
|
+
self._predicates = predicates
|
|
36
|
+
|
|
37
|
+
def where(self, predicate: Callable[[T], bool]) -> QueryBuilder[T]:
|
|
38
|
+
return QueryBuilder(self._items, (*self._predicates, predicate))
|
|
39
|
+
|
|
40
|
+
def where_equal(
|
|
41
|
+
self,
|
|
42
|
+
selector: Callable[[T], object],
|
|
43
|
+
expected: object,
|
|
44
|
+
) -> QueryBuilder[T]:
|
|
45
|
+
return self.where(lambda item: selector(item) == expected)
|
|
46
|
+
|
|
47
|
+
def where_contains(
|
|
48
|
+
self,
|
|
49
|
+
selector: Callable[[T], str],
|
|
50
|
+
expected: str,
|
|
51
|
+
*,
|
|
52
|
+
case_sensitive: bool = True,
|
|
53
|
+
) -> QueryBuilder[T]:
|
|
54
|
+
if case_sensitive:
|
|
55
|
+
return self.where(lambda item: expected in selector(item))
|
|
56
|
+
|
|
57
|
+
lowered = expected.casefold()
|
|
58
|
+
return self.where(lambda item: lowered in selector(item).casefold())
|
|
59
|
+
|
|
60
|
+
def all(self) -> tuple[T, ...]:
|
|
61
|
+
return tuple(
|
|
62
|
+
item
|
|
63
|
+
for item in self._items
|
|
64
|
+
if all(predicate(item) for predicate in self._predicates)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def first(self) -> T | None:
|
|
68
|
+
for item in self.all():
|
|
69
|
+
return item
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
def count(self) -> int:
|
|
73
|
+
return len(self.all())
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass(frozen=True)
|
|
77
|
+
class SourceFileResult:
|
|
78
|
+
source_id: str
|
|
79
|
+
file: SourceFile
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(frozen=True)
|
|
83
|
+
class SourceItemResult(Generic[SourceItem]):
|
|
84
|
+
source_id: str
|
|
85
|
+
file: SourceFile
|
|
86
|
+
item: SourceItem
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass(frozen=True)
|
|
90
|
+
class DependencyNodeResult:
|
|
91
|
+
node_id: str
|
|
92
|
+
node: Node
|
|
93
|
+
file: SourceFile | None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True)
|
|
97
|
+
class DependencyEdgeResult:
|
|
98
|
+
edge: Edge
|
|
99
|
+
source_file: SourceFile | None
|
|
100
|
+
target_file: SourceFile | None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class QueryableCodeMap:
|
|
104
|
+
def __init__(self, code_map: CodeMap):
|
|
105
|
+
self.code_map = code_map
|
|
106
|
+
self.cm = code_map
|
|
107
|
+
|
|
108
|
+
def query(self, items: Iterable[T]) -> QueryBuilder[T]:
|
|
109
|
+
return QueryBuilder(items)
|
|
110
|
+
|
|
111
|
+
def source_ids(self) -> tuple[str, ...]:
|
|
112
|
+
return tuple(self.code_map.extraction.files)
|
|
113
|
+
|
|
114
|
+
def has_source_file(self, source_id: str) -> bool:
|
|
115
|
+
return source_id in self.code_map.extraction.files
|
|
116
|
+
|
|
117
|
+
def source_file(self, source_id: str) -> SourceFileResult | None:
|
|
118
|
+
source_file = self.code_map.extraction.files.get(source_id)
|
|
119
|
+
if source_file is None:
|
|
120
|
+
return None
|
|
121
|
+
return SourceFileResult(source_id=source_id, file=source_file)
|
|
122
|
+
|
|
123
|
+
def files(self) -> QueryBuilder[SourceFileResult]:
|
|
124
|
+
return self.source_files()
|
|
125
|
+
|
|
126
|
+
def source_files(self) -> QueryBuilder[SourceFileResult]:
|
|
127
|
+
return QueryBuilder(
|
|
128
|
+
SourceFileResult(source_id=source_id, file=source_file)
|
|
129
|
+
for source_id, source_file in self.code_map.extraction.files.items()
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def imports(self) -> QueryBuilder[SourceItemResult[SourceImport]]:
|
|
133
|
+
return self._source_items(lambda source_file: source_file.imports)
|
|
134
|
+
|
|
135
|
+
def exports(self) -> QueryBuilder[SourceItemResult[SourceExport]]:
|
|
136
|
+
return self._source_items(lambda source_file: source_file.exports)
|
|
137
|
+
|
|
138
|
+
def classes(self) -> QueryBuilder[SourceItemResult[SourceClass]]:
|
|
139
|
+
return self._source_items(lambda source_file: source_file.classes)
|
|
140
|
+
|
|
141
|
+
def interfaces(self) -> QueryBuilder[SourceItemResult[SourceInterface]]:
|
|
142
|
+
return self._source_items(lambda source_file: source_file.interfaces)
|
|
143
|
+
|
|
144
|
+
def types(self) -> QueryBuilder[SourceItemResult[SourceType]]:
|
|
145
|
+
return self._source_items(lambda source_file: source_file.types)
|
|
146
|
+
|
|
147
|
+
def abstract_classes(self) -> QueryBuilder[SourceItemResult[SourceAbstractClass]]:
|
|
148
|
+
return self._source_items(lambda source_file: source_file.abstract_classes)
|
|
149
|
+
|
|
150
|
+
def functions(self) -> QueryBuilder[SourceItemResult[SourceFunction]]:
|
|
151
|
+
return self._source_items(lambda source_file: source_file.functions)
|
|
152
|
+
|
|
153
|
+
def values(self) -> QueryBuilder[SourceItemResult[SourceValue]]:
|
|
154
|
+
return self._source_items(lambda source_file: source_file.values)
|
|
155
|
+
|
|
156
|
+
def callables(self) -> QueryBuilder[SourceItemResult[SourceCallable]]:
|
|
157
|
+
return self._source_items(lambda source_file: source_file.callables)
|
|
158
|
+
|
|
159
|
+
def calls(self) -> QueryBuilder[SourceItemResult[SourceCall]]:
|
|
160
|
+
return self._source_items(lambda source_file: source_file.calls)
|
|
161
|
+
|
|
162
|
+
def dependency_nodes(self) -> QueryBuilder[DependencyNodeResult]:
|
|
163
|
+
files = self.code_map.extraction.files
|
|
164
|
+
return QueryBuilder(
|
|
165
|
+
DependencyNodeResult(
|
|
166
|
+
node_id=node_id,
|
|
167
|
+
node=node,
|
|
168
|
+
file=files.get(node_id),
|
|
169
|
+
)
|
|
170
|
+
for node_id, node in self.code_map.dependency_graph.nodes.items()
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def dependency_edges(self) -> QueryBuilder[DependencyEdgeResult]:
|
|
174
|
+
return self._dependency_edges(self.code_map.dependency_graph.edges)
|
|
175
|
+
|
|
176
|
+
def outgoing_dependencies(self, source_id: str) -> QueryBuilder[DependencyEdgeResult]:
|
|
177
|
+
return self._dependency_edges(self.code_map.dependency_graph.outgoing(source_id))
|
|
178
|
+
|
|
179
|
+
def incoming_dependencies(self, source_id: str) -> QueryBuilder[DependencyEdgeResult]:
|
|
180
|
+
return self._dependency_edges(self.code_map.dependency_graph.incoming(source_id))
|
|
181
|
+
|
|
182
|
+
def dependencies_between(
|
|
183
|
+
self,
|
|
184
|
+
source_id: str,
|
|
185
|
+
target_id: str,
|
|
186
|
+
) -> QueryBuilder[DependencyEdgeResult]:
|
|
187
|
+
return self._dependency_edges(
|
|
188
|
+
self.code_map.dependency_graph.edges_between(source_id, target_id)
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def tracked_dependency_edges(self) -> QueryBuilder[DependencyEdgeResult]:
|
|
192
|
+
return self._dependency_edges(
|
|
193
|
+
self.code_map.dependency_graph.tracked_edges(self.source_ids())
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
def external_dependency_edges(self) -> QueryBuilder[DependencyEdgeResult]:
|
|
197
|
+
return self._dependency_edges(
|
|
198
|
+
self.code_map.dependency_graph.external_edges(self.source_ids())
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def _source_items(
|
|
202
|
+
self,
|
|
203
|
+
selector: Callable[[SourceFile], Iterable[SourceItem]],
|
|
204
|
+
) -> QueryBuilder[SourceItemResult[SourceItem]]:
|
|
205
|
+
return QueryBuilder(
|
|
206
|
+
SourceItemResult(source_id=source_id, file=source_file, item=item)
|
|
207
|
+
for source_id, source_file in self.code_map.extraction.files.items()
|
|
208
|
+
for item in selector(source_file)
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
def _dependency_edges(
|
|
212
|
+
self,
|
|
213
|
+
edges: Iterable[Edge],
|
|
214
|
+
) -> QueryBuilder[DependencyEdgeResult]:
|
|
215
|
+
files = self.code_map.extraction.files
|
|
216
|
+
return QueryBuilder(
|
|
217
|
+
DependencyEdgeResult(
|
|
218
|
+
edge=edge,
|
|
219
|
+
source_file=files.get(edge.from_id),
|
|
220
|
+
target_file=files.get(edge.to_id),
|
|
221
|
+
)
|
|
222
|
+
for edge in edges
|
|
223
|
+
)
|