modwire 1.1.0__tar.gz → 2.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.
Files changed (93) hide show
  1. modwire-2.0.0/.github/ISSUE_TEMPLATE/bug_report.yml +106 -0
  2. modwire-2.0.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
  3. modwire-2.0.0/.github/ISSUE_TEMPLATE/feature_request.yml +70 -0
  4. modwire-2.0.0/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  5. modwire-2.0.0/CONTRIBUTING.md +42 -0
  6. modwire-2.0.0/PKG-INFO +252 -0
  7. modwire-2.0.0/README.md +219 -0
  8. modwire-2.0.0/docs/wiki/Development-checks.md +23 -0
  9. modwire-2.0.0/docs/wiki/Home.md +31 -0
  10. modwire-2.0.0/docs/wiki/Reporting-bugs.md +26 -0
  11. modwire-2.0.0/docs/wiki/Requesting-features.md +26 -0
  12. {modwire-1.1.0 → modwire-2.0.0}/pyproject.toml +3 -3
  13. modwire-2.0.0/src/modwire/__init__.py +86 -0
  14. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/_version.py +3 -3
  15. modwire-2.0.0/src/modwire/architecture/__init__.py +59 -0
  16. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/architecture/analyzers.py +19 -0
  17. modwire-2.0.0/src/modwire/architecture/config.py +126 -0
  18. modwire-2.0.0/src/modwire/architecture/insights.py +246 -0
  19. modwire-2.0.0/src/modwire/architecture/matching.py +153 -0
  20. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/architecture/policy.py +20 -14
  21. modwire-2.0.0/src/modwire/architecture/render.py +99 -0
  22. modwire-2.0.0/src/modwire/architecture/violations.py +47 -0
  23. modwire-2.0.0/src/modwire/extraction/__init__.py +33 -0
  24. modwire-2.0.0/src/modwire/extraction/cache.py +92 -0
  25. modwire-2.0.0/src/modwire/extraction/manifest.py +97 -0
  26. modwire-2.0.0/src/modwire/extraction/models.py +151 -0
  27. modwire-2.0.0/src/modwire/extraction/roots.py +100 -0
  28. modwire-2.0.0/src/modwire/extraction/serialization.py +106 -0
  29. modwire-2.0.0/src/modwire/extraction/service.py +100 -0
  30. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/base.py +15 -2
  31. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/loader.py +6 -1
  32. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/php.py +5 -1
  33. modwire-2.0.0/src/modwire/graph.py +116 -0
  34. modwire-2.0.0/src/modwire/metadata.py +128 -0
  35. modwire-2.0.0/src/modwire/shape/__init__.py +16 -0
  36. modwire-2.0.0/src/modwire/shape/config.py +93 -0
  37. modwire-2.0.0/src/modwire/shape/evaluator.py +32 -0
  38. modwire-2.0.0/src/modwire/shape/rules.py +389 -0
  39. modwire-2.0.0/src/modwire/shape/violations.py +23 -0
  40. modwire-2.0.0/src/modwire/testing/__init__.py +24 -0
  41. modwire-2.0.0/src/modwire/testing/factories.py +168 -0
  42. modwire-2.0.0/src/modwire.egg-info/PKG-INFO +252 -0
  43. {modwire-1.1.0 → modwire-2.0.0}/src/modwire.egg-info/SOURCES.txt +26 -1
  44. {modwire-1.1.0 → modwire-2.0.0}/tests/test_api.py +440 -1
  45. modwire-2.0.0/tests/test_architecture_api.py +360 -0
  46. modwire-1.1.0/PKG-INFO +0 -112
  47. modwire-1.1.0/README.md +0 -79
  48. modwire-1.1.0/src/modwire/__init__.py +0 -18
  49. modwire-1.1.0/src/modwire/architecture/__init__.py +0 -10
  50. modwire-1.1.0/src/modwire/architecture/matching.py +0 -58
  51. modwire-1.1.0/src/modwire/architecture/render.py +0 -98
  52. modwire-1.1.0/src/modwire/architecture/violations.py +0 -24
  53. modwire-1.1.0/src/modwire/extraction.py +0 -73
  54. modwire-1.1.0/src/modwire/graph.py +0 -56
  55. modwire-1.1.0/src/modwire.egg-info/PKG-INFO +0 -112
  56. modwire-1.1.0/tests/test_architecture_api.py +0 -43
  57. {modwire-1.1.0 → modwire-2.0.0}/.github/workflows/ci.yml +0 -0
  58. {modwire-1.1.0 → modwire-2.0.0}/.github/workflows/release.yml +0 -0
  59. {modwire-1.1.0 → modwire-2.0.0}/.gitignore +0 -0
  60. {modwire-1.1.0 → modwire-2.0.0}/LICENSE +0 -0
  61. {modwire-1.1.0 → modwire-2.0.0}/setup.cfg +0 -0
  62. {modwire-1.1.0 → modwire-2.0.0}/show_test_source_files.py +0 -0
  63. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/definitions.py +0 -0
  64. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/exports.py +0 -0
  65. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/__init__.py +0 -0
  66. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/python.py +0 -0
  67. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/scripts/php_extractor.php +0 -0
  68. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/scripts/python_extractor.py +0 -0
  69. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/scripts/typescript_extractor.js +0 -0
  70. {modwire-1.1.0 → modwire-2.0.0}/src/modwire/extractors/typescript.py +0 -0
  71. {modwire-1.1.0 → modwire-2.0.0}/src/modwire.egg-info/dependency_links.txt +0 -0
  72. {modwire-1.1.0 → modwire-2.0.0}/src/modwire.egg-info/requires.txt +0 -0
  73. {modwire-1.1.0 → modwire-2.0.0}/src/modwire.egg-info/top_level.txt +0 -0
  74. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/php/ignored/generated.php +0 -0
  75. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/php/src/application/use_cases/activate.php +0 -0
  76. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/php/src/domain/model/user.php +0 -0
  77. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/php/src/domain/services/policy.php +0 -0
  78. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/php/src/interfaces/http/controller.php +0 -0
  79. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/python/ignored/generated.py +0 -0
  80. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/python/src/application/use_cases/activate.py +0 -0
  81. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/python/src/domain/model/user.py +0 -0
  82. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/python/src/domain/services/policy.py +0 -0
  83. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/python/src/interfaces/http/controller.py +0 -0
  84. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/ignored/generated.ts +0 -0
  85. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/application/use_cases/activate.ts +0 -0
  86. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/domain/model/profile.tsx +0 -0
  87. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/domain/model/user.ts +0 -0
  88. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/domain/services/audit.js +0 -0
  89. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/domain/services/policy.ts +0 -0
  90. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/interfaces/http/controller.ts +0 -0
  91. {modwire-1.1.0 → modwire-2.0.0}/tests/apps/typescript/src/interfaces/http/view.jsx +0 -0
  92. {modwire-1.1.0 → modwire-2.0.0}/tests/test_standalone.py +0 -0
  93. {modwire-1.1.0 → modwire-2.0.0}/uv.lock +0 -0
@@ -0,0 +1,106 @@
1
+ name: Bug report
2
+ description: Report incorrect extraction, graph output, architecture analysis, packaging, or runtime behavior.
3
+ title: "Bug: "
4
+ labels:
5
+ - bug
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: |
10
+ Thanks for reporting a bug. Clear reproduction details make it much easier to fix issues in extractors and graph analysis.
11
+
12
+ - type: textarea
13
+ id: summary
14
+ attributes:
15
+ label: What happened?
16
+ description: Describe the bug and the behavior you expected instead.
17
+ placeholder: Modwire returned...
18
+ validations:
19
+ required: true
20
+
21
+ - type: dropdown
22
+ id: area
23
+ attributes:
24
+ label: Affected area
25
+ options:
26
+ - Python extractor
27
+ - TypeScript/JavaScript extractor
28
+ - PHP extractor
29
+ - Dependency graph
30
+ - Architecture policy API
31
+ - Packaging or installation
32
+ - Documentation
33
+ - Other
34
+ validations:
35
+ required: true
36
+
37
+ - type: textarea
38
+ id: reproduce
39
+ attributes:
40
+ label: How can we reproduce it?
41
+ description: Include the smallest source tree, snippet, command, or test case that shows the problem.
42
+ placeholder: |
43
+ 1. Create this file...
44
+ 2. Run this code...
45
+ 3. Observe...
46
+ validations:
47
+ required: true
48
+
49
+ - type: textarea
50
+ id: actual
51
+ attributes:
52
+ label: Actual output
53
+ description: Paste the returned objects, graph edges, violation output, traceback, or command output.
54
+ render: text
55
+ validations:
56
+ required: false
57
+
58
+ - type: textarea
59
+ id: expected
60
+ attributes:
61
+ label: Expected output
62
+ description: Describe the graph, source IDs, symbols, imports, or violations you expected.
63
+ validations:
64
+ required: false
65
+
66
+ - type: input
67
+ id: modwire-version
68
+ attributes:
69
+ label: Modwire version
70
+ description: Run `python -m pip show modwire` or identify the commit SHA if installed from source.
71
+ placeholder: 0.0.0 or commit SHA
72
+ validations:
73
+ required: false
74
+
75
+ - type: input
76
+ id: python-version
77
+ attributes:
78
+ label: Python version
79
+ placeholder: "3.11, 3.12, or 3.13"
80
+ validations:
81
+ required: true
82
+
83
+ - type: input
84
+ id: runtime-versions
85
+ attributes:
86
+ label: Node.js or PHP version, if relevant
87
+ description: TypeScript/JavaScript extraction requires Node.js. PHP extraction requires PHP.
88
+ placeholder: "Node.js 20.x, PHP 8.3, or not applicable"
89
+ validations:
90
+ required: false
91
+
92
+ - type: input
93
+ id: os
94
+ attributes:
95
+ label: Operating system
96
+ placeholder: "macOS 15, Ubuntu 24.04, Windows 11, etc."
97
+ validations:
98
+ required: false
99
+
100
+ - type: textarea
101
+ id: context
102
+ attributes:
103
+ label: Additional context
104
+ description: Add anything else that may help explain the problem.
105
+ validations:
106
+ required: false
@@ -0,0 +1 @@
1
+ blank_issues_enabled: false
@@ -0,0 +1,70 @@
1
+ name: Feature request
2
+ description: Suggest a new capability, supported language, extractor improvement, graph API, or architecture rule.
3
+ title: "Feature: "
4
+ labels:
5
+ - enhancement
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: |
10
+ Use this form for new capabilities or behavior changes. For incorrect current behavior, please open a bug report instead.
11
+
12
+ - type: textarea
13
+ id: problem
14
+ attributes:
15
+ label: What problem should this solve?
16
+ description: Describe the workflow, codebase shape, or analysis gap that motivates the request.
17
+ placeholder: I want to use Modwire to...
18
+ validations:
19
+ required: true
20
+
21
+ - type: dropdown
22
+ id: area
23
+ attributes:
24
+ label: Feature area
25
+ options:
26
+ - New language support
27
+ - Python extractor
28
+ - TypeScript/JavaScript extractor
29
+ - PHP extractor
30
+ - Dependency graph
31
+ - Architecture policy API
32
+ - Exports or integrations
33
+ - Documentation
34
+ - Other
35
+ validations:
36
+ required: true
37
+
38
+ - type: textarea
39
+ id: proposal
40
+ attributes:
41
+ label: Proposed behavior
42
+ description: Explain the API, CLI, output shape, analyzer, or documentation you would like to see.
43
+ placeholder: Modwire should...
44
+ validations:
45
+ required: true
46
+
47
+ - type: textarea
48
+ id: example
49
+ attributes:
50
+ label: Example usage or input
51
+ description: Include a short source snippet, desired graph shape, policy example, or Python API sketch if useful.
52
+ render: python
53
+ validations:
54
+ required: false
55
+
56
+ - type: textarea
57
+ id: alternatives
58
+ attributes:
59
+ label: Alternatives considered
60
+ description: Mention any workaround or different API shape you have considered.
61
+ validations:
62
+ required: false
63
+
64
+ - type: checkboxes
65
+ id: contribution
66
+ attributes:
67
+ label: Contribution
68
+ options:
69
+ - label: I would be interested in working on this.
70
+ required: false
@@ -0,0 +1,14 @@
1
+ ## Summary
2
+
3
+ -
4
+
5
+ ## Validation
6
+
7
+ - [ ] `uv run ruff check`
8
+ - [ ] `uv run pytest`
9
+ - [ ] `uv run python -m build --outdir dist`
10
+ - [ ] `uv run twine check dist/*`
11
+
12
+ ## Notes
13
+
14
+ -
@@ -0,0 +1,42 @@
1
+ # Contributing to Modwire
2
+
3
+ Modwire is a Python package for extracting source-code dependencies and
4
+ evaluating architecture rules across Python, TypeScript/JavaScript, and PHP
5
+ projects.
6
+
7
+ ## Requesting Features
8
+
9
+ Use the `Feature request` issue form for new capabilities, such as:
10
+
11
+ - support for another language or framework convention
12
+ - richer symbol, import, or graph metadata
13
+ - new architecture analyzers or policy matching behavior
14
+ - export formats or integrations with other tools
15
+ - documentation examples for common workflows
16
+
17
+ Feature requests are easiest to evaluate when they include the problem being
18
+ solved, a small example input, and the desired API or output shape.
19
+
20
+ ## Reporting Bugs
21
+
22
+ Use the `Bug report` issue form for incorrect current behavior, such as:
23
+
24
+ - missing or incorrect imports, symbols, source IDs, or graph edges
25
+ - incorrect architecture-policy violations
26
+ - extractor crashes or runtime failures
27
+ - packaging, installation, or compatibility problems
28
+ - documentation that contradicts the implemented behavior
29
+
30
+ Bug reports should include a minimal reproduction, the expected output, the
31
+ actual output, and relevant versions for Python, Modwire, Node.js, or PHP.
32
+
33
+ ## Pull Requests
34
+
35
+ Before opening a pull request, run the local checks documented in
36
+ [Development checks](docs/wiki/Development-checks.md).
37
+
38
+ Extractor changes should include focused tests under `tests/` and, when
39
+ relevant, a small fixture under `tests/apps/`.
40
+
41
+ Keep pull requests scoped to one behavior change. If an issue exists, link it in
42
+ the pull request description.
modwire-2.0.0/PKG-INFO ADDED
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: modwire
3
+ Version: 2.0.0
4
+ Summary: Extract source-code dependencies and build dependency graphs.
5
+ Author: Tomasz Szpak
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/9orky/modwire
8
+ Project-URL: Repository, https://github.com/9orky/modwire
9
+ Project-URL: Issues, https://github.com/9orky/modwire/issues
10
+ Keywords: architecture,code-analysis,dependency-graph,static-analysis
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Requires-Python: >=3.11
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: pydantic>=2.8
27
+ Provides-Extra: dev
28
+ Requires-Dist: build>=1.2; extra == "dev"
29
+ Requires-Dist: pytest>=8.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.8; extra == "dev"
31
+ Requires-Dist: twine>=5.1; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # modwire
35
+
36
+ `modwire` extracts source-code structure and import dependencies from Python,
37
+ TypeScript/JavaScript, and PHP projects. It returns typed Python objects that
38
+ you can use to build dependency graphs, inspect symbols, and evaluate
39
+ architecture rules.
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ python -m pip install modwire
45
+ ```
46
+
47
+ The Python extractor works with Python alone. TypeScript/JavaScript extraction
48
+ requires Node.js at runtime, and PHP extraction requires PHP at runtime.
49
+
50
+ ## Quick Start
51
+
52
+ ```python
53
+ from pathlib import Path
54
+
55
+ from modwire import discover_sources, extract_code
56
+
57
+ manifest = discover_sources(
58
+ "python",
59
+ Path("src"),
60
+ exclusions=("**/__pycache__/**",),
61
+ )
62
+ result = extract_code("python", Path("src"), exclusions=manifest.exclusions)
63
+
64
+ print(result.extraction_result.summary.files_checked)
65
+ print(result.graph.node_ids())
66
+ print([(edge.from_id, edge.to_id) for edge in result.graph.edges])
67
+ ```
68
+
69
+ Graph nodes use canonical extensionless source IDs, so equivalent Python,
70
+ TypeScript, and PHP projects can be compared through the same graph shape.
71
+
72
+ ## Supported Languages
73
+
74
+
75
+ ```python
76
+ from modwire import supported_languages
77
+
78
+ print(supported_languages())
79
+ # ("python", "typescript", "php")
80
+ ```
81
+
82
+ Language-specific source IDs can be normalized without running a full
83
+ extraction:
84
+
85
+ ```python
86
+ from modwire import normalize_source_id
87
+
88
+ print(normalize_source_id("typescript", "src/view.tsx"))
89
+ # "src/view"
90
+ ```
91
+
92
+ ## Extraction Options
93
+
94
+ Use `SourceRoots` when source IDs should be relative to a workspace root or to a
95
+ logical package prefix:
96
+
97
+ ```python
98
+ from pathlib import Path
99
+
100
+ from modwire import SourceRoots, extract_code
101
+
102
+ code_map = extract_code(
103
+ "python",
104
+ Path("packages/billing/src"),
105
+ source_roots=SourceRoots(
106
+ workspace_root=Path("."),
107
+ source_id_mode="relative_to_workspace_root",
108
+ ),
109
+ )
110
+ ```
111
+
112
+ Use `ExtractionCache` to reuse extraction output when files and extractor
113
+ implementations have not changed:
114
+
115
+ ```python
116
+ from pathlib import Path
117
+
118
+ from modwire import ExtractionCache, extract_code
119
+
120
+ code_map = extract_code(
121
+ "python",
122
+ Path("src"),
123
+ cache=ExtractionCache(Path(".modwire-cache")),
124
+ )
125
+
126
+ print(code_map.cache_status)
127
+ ```
128
+
129
+ ## Architecture Policy API
130
+
131
+ `modwire.architecture` exposes policy evaluation helpers for checking import
132
+ boundaries and common dependency-flow rules.
133
+
134
+ ```python
135
+ from modwire import extract_code
136
+ from modwire.architecture import (
137
+ ArchitectureBoundaryRule,
138
+ ArchitectureConfig,
139
+ ArchitectureFlowRules,
140
+ ArchitecturePolicyEvaluator,
141
+ ArchitectureRules,
142
+ ArchitectureTagRule,
143
+ render_violations,
144
+ supported_analyzers,
145
+ )
146
+
147
+ print(supported_analyzers())
148
+ # ("backward-flow", "no-reentry", "no-cycles")
149
+
150
+ code_map = extract_code("python", "src")
151
+ config = ArchitectureConfig(
152
+ language="python",
153
+ architecture_root="src",
154
+ rules=ArchitectureRules(
155
+ tags=(
156
+ ArchitectureTagRule(name="module", match="features/*"),
157
+ ArchitectureTagRule(name="ui", match="features/*/ui"),
158
+ ArchitectureTagRule(name="domain", match="features/*/domain"),
159
+ ),
160
+ boundaries=(
161
+ ArchitectureBoundaryRule(
162
+ source="features/*/ui",
163
+ disallow=("features/*/domain",),
164
+ allow_same_match=True,
165
+ ),
166
+ ),
167
+ flow=ArchitectureFlowRules(
168
+ layers=("domain", "ui"),
169
+ module_tag="module",
170
+ analyzers=("no-cycles",),
171
+ ),
172
+ ),
173
+ )
174
+
175
+ violations = ArchitecturePolicyEvaluator().evaluate(code_map.graph, config)
176
+ print(render_violations(tuple(violations)))
177
+ ```
178
+
179
+ Architecture insight helpers summarize ownership and graph pressure:
180
+
181
+ ```python
182
+ from modwire.architecture import coherence_summary, find_hotspots, map_code
183
+
184
+ architecture_map = map_code(code_map, config)
185
+ hotspots = find_hotspots(code_map, limit=5)
186
+ coherence = coherence_summary(code_map)
187
+
188
+ print(architecture_map.cross_module_dependencies)
189
+ print(hotspots)
190
+ print(coherence.external_dependencies)
191
+ ```
192
+
193
+ ## Shape Policy API
194
+
195
+ Shape policies evaluate file, symbol, callable, property, and import metadata:
196
+
197
+ ```python
198
+ from modwire import ShapePolicyEvaluator, evaluate_shape
199
+
200
+ violations = evaluate_shape(
201
+ code_map,
202
+ {
203
+ "max_functions_per_file": 5,
204
+ "max_methods_per_class": 10,
205
+ "allow_import_aliases": False,
206
+ "require_joined_imports": True,
207
+ },
208
+ )
209
+
210
+ same_result = ShapePolicyEvaluator().evaluate(code_map, {})
211
+ print([violation.to_dict() for violation in violations])
212
+ print(same_result)
213
+ ```
214
+
215
+ ## Serialization And Exports
216
+
217
+ `CodeMap` results can be serialized for later analysis, and export metadata can
218
+ be used to find currently unused public symbols:
219
+
220
+ ```python
221
+ from modwire import (
222
+ deserialize_code_map,
223
+ find_unused_exports,
224
+ serialize_code_map,
225
+ )
226
+
227
+ payload = serialize_code_map(code_map)
228
+ loaded = deserialize_code_map(payload)
229
+
230
+ unused = find_unused_exports(loaded.extraction_result)
231
+ print([(export.source_id, export.name) for export in unused])
232
+ ```
233
+
234
+ ## Development
235
+
236
+ See [Development checks](docs/wiki/Development-checks.md) for the local command
237
+ set used before pull requests and releases.
238
+
239
+ ## Contributing
240
+
241
+ Feature requests and bug reports are tracked through GitHub Issues:
242
+
243
+ - Open a feature request for new language support, graph metadata, architecture
244
+ rules, export formats, or documentation examples.
245
+ - Open a bug report for incorrect extraction results, graph edges, architecture
246
+ violations, packaging problems, or runtime failures.
247
+
248
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the information to include and the
249
+ checks to run before opening a pull request.
250
+
251
+ Starter wiki pages are tracked under [docs/wiki](docs/wiki) so the GitHub Wiki
252
+ can be initialized with the same guidance.
@@ -0,0 +1,219 @@
1
+ # modwire
2
+
3
+ `modwire` extracts source-code structure and import dependencies from Python,
4
+ TypeScript/JavaScript, and PHP projects. It returns typed Python objects that
5
+ you can use to build dependency graphs, inspect symbols, and evaluate
6
+ architecture rules.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ python -m pip install modwire
12
+ ```
13
+
14
+ The Python extractor works with Python alone. TypeScript/JavaScript extraction
15
+ requires Node.js at runtime, and PHP extraction requires PHP at runtime.
16
+
17
+ ## Quick Start
18
+
19
+ ```python
20
+ from pathlib import Path
21
+
22
+ from modwire import discover_sources, extract_code
23
+
24
+ manifest = discover_sources(
25
+ "python",
26
+ Path("src"),
27
+ exclusions=("**/__pycache__/**",),
28
+ )
29
+ result = extract_code("python", Path("src"), exclusions=manifest.exclusions)
30
+
31
+ print(result.extraction_result.summary.files_checked)
32
+ print(result.graph.node_ids())
33
+ print([(edge.from_id, edge.to_id) for edge in result.graph.edges])
34
+ ```
35
+
36
+ Graph nodes use canonical extensionless source IDs, so equivalent Python,
37
+ TypeScript, and PHP projects can be compared through the same graph shape.
38
+
39
+ ## Supported Languages
40
+
41
+
42
+ ```python
43
+ from modwire import supported_languages
44
+
45
+ print(supported_languages())
46
+ # ("python", "typescript", "php")
47
+ ```
48
+
49
+ Language-specific source IDs can be normalized without running a full
50
+ extraction:
51
+
52
+ ```python
53
+ from modwire import normalize_source_id
54
+
55
+ print(normalize_source_id("typescript", "src/view.tsx"))
56
+ # "src/view"
57
+ ```
58
+
59
+ ## Extraction Options
60
+
61
+ Use `SourceRoots` when source IDs should be relative to a workspace root or to a
62
+ logical package prefix:
63
+
64
+ ```python
65
+ from pathlib import Path
66
+
67
+ from modwire import SourceRoots, extract_code
68
+
69
+ code_map = extract_code(
70
+ "python",
71
+ Path("packages/billing/src"),
72
+ source_roots=SourceRoots(
73
+ workspace_root=Path("."),
74
+ source_id_mode="relative_to_workspace_root",
75
+ ),
76
+ )
77
+ ```
78
+
79
+ Use `ExtractionCache` to reuse extraction output when files and extractor
80
+ implementations have not changed:
81
+
82
+ ```python
83
+ from pathlib import Path
84
+
85
+ from modwire import ExtractionCache, extract_code
86
+
87
+ code_map = extract_code(
88
+ "python",
89
+ Path("src"),
90
+ cache=ExtractionCache(Path(".modwire-cache")),
91
+ )
92
+
93
+ print(code_map.cache_status)
94
+ ```
95
+
96
+ ## Architecture Policy API
97
+
98
+ `modwire.architecture` exposes policy evaluation helpers for checking import
99
+ boundaries and common dependency-flow rules.
100
+
101
+ ```python
102
+ from modwire import extract_code
103
+ from modwire.architecture import (
104
+ ArchitectureBoundaryRule,
105
+ ArchitectureConfig,
106
+ ArchitectureFlowRules,
107
+ ArchitecturePolicyEvaluator,
108
+ ArchitectureRules,
109
+ ArchitectureTagRule,
110
+ render_violations,
111
+ supported_analyzers,
112
+ )
113
+
114
+ print(supported_analyzers())
115
+ # ("backward-flow", "no-reentry", "no-cycles")
116
+
117
+ code_map = extract_code("python", "src")
118
+ config = ArchitectureConfig(
119
+ language="python",
120
+ architecture_root="src",
121
+ rules=ArchitectureRules(
122
+ tags=(
123
+ ArchitectureTagRule(name="module", match="features/*"),
124
+ ArchitectureTagRule(name="ui", match="features/*/ui"),
125
+ ArchitectureTagRule(name="domain", match="features/*/domain"),
126
+ ),
127
+ boundaries=(
128
+ ArchitectureBoundaryRule(
129
+ source="features/*/ui",
130
+ disallow=("features/*/domain",),
131
+ allow_same_match=True,
132
+ ),
133
+ ),
134
+ flow=ArchitectureFlowRules(
135
+ layers=("domain", "ui"),
136
+ module_tag="module",
137
+ analyzers=("no-cycles",),
138
+ ),
139
+ ),
140
+ )
141
+
142
+ violations = ArchitecturePolicyEvaluator().evaluate(code_map.graph, config)
143
+ print(render_violations(tuple(violations)))
144
+ ```
145
+
146
+ Architecture insight helpers summarize ownership and graph pressure:
147
+
148
+ ```python
149
+ from modwire.architecture import coherence_summary, find_hotspots, map_code
150
+
151
+ architecture_map = map_code(code_map, config)
152
+ hotspots = find_hotspots(code_map, limit=5)
153
+ coherence = coherence_summary(code_map)
154
+
155
+ print(architecture_map.cross_module_dependencies)
156
+ print(hotspots)
157
+ print(coherence.external_dependencies)
158
+ ```
159
+
160
+ ## Shape Policy API
161
+
162
+ Shape policies evaluate file, symbol, callable, property, and import metadata:
163
+
164
+ ```python
165
+ from modwire import ShapePolicyEvaluator, evaluate_shape
166
+
167
+ violations = evaluate_shape(
168
+ code_map,
169
+ {
170
+ "max_functions_per_file": 5,
171
+ "max_methods_per_class": 10,
172
+ "allow_import_aliases": False,
173
+ "require_joined_imports": True,
174
+ },
175
+ )
176
+
177
+ same_result = ShapePolicyEvaluator().evaluate(code_map, {})
178
+ print([violation.to_dict() for violation in violations])
179
+ print(same_result)
180
+ ```
181
+
182
+ ## Serialization And Exports
183
+
184
+ `CodeMap` results can be serialized for later analysis, and export metadata can
185
+ be used to find currently unused public symbols:
186
+
187
+ ```python
188
+ from modwire import (
189
+ deserialize_code_map,
190
+ find_unused_exports,
191
+ serialize_code_map,
192
+ )
193
+
194
+ payload = serialize_code_map(code_map)
195
+ loaded = deserialize_code_map(payload)
196
+
197
+ unused = find_unused_exports(loaded.extraction_result)
198
+ print([(export.source_id, export.name) for export in unused])
199
+ ```
200
+
201
+ ## Development
202
+
203
+ See [Development checks](docs/wiki/Development-checks.md) for the local command
204
+ set used before pull requests and releases.
205
+
206
+ ## Contributing
207
+
208
+ Feature requests and bug reports are tracked through GitHub Issues:
209
+
210
+ - Open a feature request for new language support, graph metadata, architecture
211
+ rules, export formats, or documentation examples.
212
+ - Open a bug report for incorrect extraction results, graph edges, architecture
213
+ violations, packaging problems, or runtime failures.
214
+
215
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the information to include and the
216
+ checks to run before opening a pull request.
217
+
218
+ Starter wiki pages are tracked under [docs/wiki](docs/wiki) so the GitHub Wiki
219
+ can be initialized with the same guidance.