wexample-wex-addon-dev-javascript 8.0.0__tar.gz → 8.1.1__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.
- wexample_wex_addon_dev_javascript-8.1.1/PKG-INFO +309 -0
- wexample_wex_addon_dev_javascript-8.1.1/README.md +287 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/pyproject.toml +4 -4
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/config_value/javascript_package_readme_config_value.py +5 -2
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/formatter}/__init__.py +0 -0
- wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/formatter/javascript_code_formatter.py +43 -0
- wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py +37 -0
- wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/resources/design_rules/javascript_code.md +17 -0
- wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/resources/writing_rules/javascript_code.md +26 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/node/commands → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/node}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/node/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/node/commands/service/refresh_lock.py +7 -2
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/ai → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/vite}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/commands → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main}/__init__.py +0 -0
- wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/workdir/__init__.py +0 -0
- wexample_wex_addon_dev_javascript-8.1.1/tests/.gitkeep +0 -0
- wexample_wex_addon_dev_javascript-8.0.0/PKG-INFO +0 -475
- wexample_wex_addon_dev_javascript-8.0.0/README.md +0 -453
- wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py +0 -7
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/common/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/config_value/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/const/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/const/tags.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/file/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/file/javascript_package_json_file.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/file/javascript_tsconfig_json_file.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/file/node_package_json_file.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/py.typed +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/resources/.wex.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/resources/package_publish.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/node → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/node/commands/service → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/node/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/node/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/node/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/node/service.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/vite/ai}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/about-service.md +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/agent.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/app_service.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/commands/service → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/vite/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/workdir → wexample_wex_addon_dev_javascript-8.1.1/src/wexample_wex_addon_dev_javascript/services/vite/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/commands/service/install.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/commands/service/ready.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/services/vite/service.yml +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/workdir/javascript_packages_suite_workdir.py +0 -0
- {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/src/wexample_wex_addon_dev_javascript/workdir/javascript_workdir.py +0 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: wexample-wex-addon-dev-javascript
|
|
3
|
+
Version: 8.1.1
|
|
4
|
+
Summary: Extends wex with JavaScript support: enforces JS/TS project layout and symlinks local npm packages into node_modules
|
|
5
|
+
Author-Email: weeger <contact@wexample.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Project-URL: homepage, https://github.com/wexample/python-wex-dev-python
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Requires-Dist: attrs>=23.1.0
|
|
13
|
+
Requires-Dist: cattrs>=23.1.0
|
|
14
|
+
Requires-Dist: wexample-api>=6.8.0
|
|
15
|
+
Requires-Dist: wexample-filestate-javascript>=6.6.0
|
|
16
|
+
Requires-Dist: wexample-wex-addon-ai>=14.0.0
|
|
17
|
+
Requires-Dist: wexample-wex-addon-app>=31.0.0
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# wex_addon_dev_javascript
|
|
24
|
+
|
|
25
|
+
Version: 8.1.1
|
|
26
|
+
|
|
27
|
+
`wex-addon-dev-javascript` extends wex for JavaScript and TypeScript developers: it enforces a standard project layout — requiring `package.json`, `tsconfig.json`, `.npmrc`, `src/`, `tests/`, and the corresponding `.gitignore` rules — and in local environments symlinks locally-developed npm packages directly into a running container's `node_modules/` so monorepo packages resolve without a registry publish cycle. It also contributes a `node` service and a `vite` service, each backed by Docker Compose, where the vite service patches `allowedHosts` in `vite.config.ts` for reverse-proxy use and the node service handles lockfile refresh, annotated-tag release, and registry polling for npm package suites managed through wex.
|
|
28
|
+
|
|
29
|
+
## Table of Contents
|
|
30
|
+
|
|
31
|
+
- [Installation](#installation)
|
|
32
|
+
- [Quickstart](#quickstart)
|
|
33
|
+
- [Tests](#tests)
|
|
34
|
+
- [Architecture](#architecture)
|
|
35
|
+
- [Integration in the Suite](#integration-in-the-suite)
|
|
36
|
+
- [Dependencies](#dependencies)
|
|
37
|
+
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
|
|
38
|
+
- [License](#license)
|
|
39
|
+
- [About us](#about-us)
|
|
40
|
+
- [Known Limitations & Roadmap](#known-limitations--roadmap)
|
|
41
|
+
- [Status & Compatibility](#status--compatibility)
|
|
42
|
+
- [Useful Links](#useful-links)
|
|
43
|
+
- [Migration Notes](#migration-notes)
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install wexample-wex-addon-dev-javascript
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Requires Python >=3.10.
|
|
52
|
+
|
|
53
|
+
## Quickstart
|
|
54
|
+
|
|
55
|
+
Install the package:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install wexample-wex-addon-dev-javascript
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The public entry point is `JavascriptAddonManager`, defined in src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from wexample_wex_addon_dev_javascript.javascript_addon_manager import JavascriptAddonManager
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Pass it to the kernel's `setup()` call to register the JavaScript addon slot:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from wexample_wex_core.common.kernel import Kernel
|
|
71
|
+
|
|
72
|
+
kernel = Kernel()
|
|
73
|
+
kernel.setup(addons=[JavascriptAddonManager])
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
After `setup()` returns, the kernel recognises three workdir types: `javascript`, `javascript-package`, and `javascript-packages-suite`. Any workdir resolved against a directory holding a `package.json` will be matched to the appropriate class.
|
|
77
|
+
|
|
78
|
+
The addon also contributes four service commands to the `node` and `vite` namespaces. Wire locally-developed npm packages into a running container's `node_modules/` — replacing the registry copy with a live symlink — with:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
wex node::service/install_local
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Refresh the lockfile in the container after a `package.json` dependency change (the command detects whether the project uses npm, pnpm, or Yarn from whichever lockfile is present):
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
wex node::service/refresh_lock --npm_packages "@vendor/my-lib"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Patch `vite.config.ts` so the Vite dev server accepts requests from any host — required when the service runs behind a reverse proxy:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
wex vite::service/install
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Check whether the Vite dev server inside its container is responding:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
wex vite::service/ready
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Tests
|
|
103
|
+
|
|
104
|
+
This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
|
|
105
|
+
|
|
106
|
+
### Installation
|
|
107
|
+
|
|
108
|
+
First, install the required testing dependencies:
|
|
109
|
+
```bash
|
|
110
|
+
.venv/bin/python -m pip install pytest pytest-cov
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Basic Usage
|
|
114
|
+
|
|
115
|
+
Run all tests with coverage:
|
|
116
|
+
```bash
|
|
117
|
+
.venv/bin/python -m pytest --cov --cov-report=html
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Common Commands
|
|
121
|
+
```bash
|
|
122
|
+
# Run tests with coverage for a specific module
|
|
123
|
+
.venv/bin/python -m pytest --cov=your_module
|
|
124
|
+
|
|
125
|
+
# Show which lines are not covered
|
|
126
|
+
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
|
|
127
|
+
|
|
128
|
+
# Generate an HTML coverage report
|
|
129
|
+
.venv/bin/python -m pytest --cov=your_module --cov-report=html
|
|
130
|
+
|
|
131
|
+
# Combine terminal and HTML reports
|
|
132
|
+
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
|
|
133
|
+
|
|
134
|
+
# Run specific test file with coverage
|
|
135
|
+
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Viewing HTML Reports
|
|
139
|
+
|
|
140
|
+
After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
|
|
141
|
+
|
|
142
|
+
### Coverage Threshold
|
|
143
|
+
|
|
144
|
+
To enforce a minimum coverage percentage:
|
|
145
|
+
```bash
|
|
146
|
+
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This will cause the test suite to fail if coverage drops below 80%.
|
|
150
|
+
|
|
151
|
+
## Architecture
|
|
152
|
+
|
|
153
|
+
The addon is a pure Python package that extends wex with JavaScript and TypeScript support. It has four layers: an addon manager that registers workdir types, a workdir hierarchy that enforces project layout and owns the release lifecycle, a file layer that controls what `package.json` and `tsconfig.json` contain when written to disk, and a service layer that contributes `node` and `vite` Docker service definitions with their commands.
|
|
154
|
+
|
|
155
|
+
### Entry point
|
|
156
|
+
|
|
157
|
+
src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py is the only class the host kernel needs. It extends `AbstractAddonManager` and returns three workdir types from `get_workdir_types()`:
|
|
158
|
+
|
|
159
|
+
| key | class |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `javascript` | `JavascriptWorkdir` |
|
|
162
|
+
| `javascript-package` | `JavascriptPackageWorkdir` |
|
|
163
|
+
| `javascript-packages-suite` | `JavascriptPackagesSuiteWorkdir` |
|
|
164
|
+
|
|
165
|
+
The kernel resolves a directory to the right class by matching that key against the workdir type declared in the project's wex config.
|
|
166
|
+
|
|
167
|
+
### Workdir layer
|
|
168
|
+
|
|
169
|
+
The three classes form a linear inheritance chain.
|
|
170
|
+
|
|
171
|
+
#### `JavascriptWorkdir`
|
|
172
|
+
|
|
173
|
+
src/wexample_wex_addon_dev_javascript/workdir/javascript_workdir.py is the base. It extends `CodeBaseWorkdir` (from `wexample-wex-addon-app`) and `WithAiWorkdirMixin`. Its `prepare_value()` declares the required filesystem layout that wex will enforce: `package.json`, `tsconfig.json`, `.npmrc`, a `src/` tree, a `tests/` tree, and `.gitignore` rules covering `node_modules/`, `dist/`, `build/`, `.npm`, and `.eslintcache`. JS/TS files under `src/` and `tests/` are captured by a `ChildrenFilterOption` that matches `*.js|jsx|ts|tsx` and applies the `BiomeOption` from `wexample-filestate-javascript`. The class also appends `JavascriptOptionsProvider` to the options chain and returns a `JavascriptPackageJsonFile` from `get_app_config_file()`.
|
|
174
|
+
|
|
175
|
+
#### `JavascriptPackageWorkdir`
|
|
176
|
+
|
|
177
|
+
src/wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py extends `JavascriptWorkdir` and adds everything a publishable npm package needs.
|
|
178
|
+
|
|
179
|
+
**Naming.** `get_project_name()` returns `@{vendor}/{kebab-case-name}`, giving packages their scoped npm identity.
|
|
180
|
+
|
|
181
|
+
**Layout addition.** `prepare_value()` appends `.github/workflows/publish.yml` to the enforced file tree. The content is read from the bundled resource src/wexample_wex_addon_dev_javascript/resources/package_publish.yml — a GitHub Actions workflow that publishes to npm on any `v*` tag push.
|
|
182
|
+
|
|
183
|
+
**Release lifecycle.** `release()` runs three steps in order:
|
|
184
|
+
1. `_refresh_lockfile()` — detects which lockfile is present (`package-lock.json`, `pnpm-lock.yaml`, or `yarn.lock`) and runs the matching lock-only refresh command on the host machine.
|
|
185
|
+
2. `super().release()` — inherited bump, commit, and publish flow; `_publish()` overrides the publish step to create an annotated git tag (`v{version}`) and push it to the configured deployment remote, which triggers the CI workflow above.
|
|
186
|
+
3. `_wait_for_registry()` — polls `NpmRegistryGateway.has_version()` every 30 s for up to 20 minutes before the suite loop advances to the next dependent package.
|
|
187
|
+
|
|
188
|
+
**Version bump classification.** `_classify_version_bump()` inspects the git diff of `src/` since the last tag: no changes → minor bump; whitespace-only diff → minor; non-TypeScript files only → intermediate; any `.ts`/`.tsx` change → major.
|
|
189
|
+
|
|
190
|
+
#### `JavascriptPackagesSuiteWorkdir`
|
|
191
|
+
|
|
192
|
+
src/wexample_wex_addon_dev_javascript/workdir/javascript_packages_suite_workdir.py extends `FrameworkPackageSuiteWorkdir`. It discovers child packages by looking for directories inside `npm/` that contain a `package.json`, and resolves each child as a `JavascriptPackageWorkdir`.
|
|
193
|
+
|
|
194
|
+
### File layer
|
|
195
|
+
|
|
196
|
+
#### `NodePackageJsonFile`
|
|
197
|
+
|
|
198
|
+
src/wexample_wex_addon_dev_javascript/file/node_package_json_file.py composes `AppDependenciesConfigFileMixin` with `JsonFile`. It exposes the dependency-manifest API (`add_dependency`, `add_dependency_from_string`, `get_dependencies_versions`) and reads `dependencies` plus `peerDependencies` as the set of declared runtime constraints. Any workdir that ships a `package.json` — including polyglot app manifests — can attach this class.
|
|
199
|
+
|
|
200
|
+
#### `JavascriptPackageJsonFile`
|
|
201
|
+
|
|
202
|
+
src/wexample_wex_addon_dev_javascript/file/javascript_package_json_file.py extends `NodePackageJsonFile`. Its `dumps()` stamps `name`, `version`, and `repository` from the parent workdir before delegating to the JSON serialiser. It also calls `_apply_default_publish_config()`, which sets `type: "module"`, ensures `publishConfig.access` defaults to `"public"`, and — when neither `exports` nor a `dist`-targeting `files` array is already present — injects a default `exports` map (`"./*": { types: "./dist/*.d.ts", default: "./dist/*.js" }`), a `files: ["dist"]` list, and a `typesVersions` block so consumers can import without transpiling sources.
|
|
203
|
+
|
|
204
|
+
#### `JavascriptTsconfigJsonFile`
|
|
205
|
+
|
|
206
|
+
src/wexample_wex_addon_dev_javascript/file/javascript_tsconfig_json_file.py extends `JsonFile`. Its `dumps()` fills in `compilerOptions` defaults (`target: ES2020`, `module: NodeNext`, `moduleResolution: NodeNext`, `rootDir: src`, `outDir: dist`, `declaration: true`, `declarationMap: true`, `sourceMap: true`, `strict: false`, `esModuleInterop: true`, `skipLibCheck: true`, `forceConsistentCasingInFileNames: true`) and sets `include: ["src"]`, `exclude: ["dist", "node_modules", "tests"]`. All defaults use `setdefault`, so anything already in the file is left untouched.
|
|
207
|
+
|
|
208
|
+
### Service layer
|
|
209
|
+
|
|
210
|
+
Two service namespaces ship as self-contained directories, each containing a `service.yml`, a `docker/docker-compose.yml`, and a `commands/service/` package.
|
|
211
|
+
|
|
212
|
+
#### `vite` service
|
|
213
|
+
|
|
214
|
+
Defined in src/wexample_wex_addon_dev_javascript/services/vite/service.yml. The container (`${APP_PROJECT_NAME}_vite`) runs `oven/bun:latest`, mounts the app path to `/app`, persists `node_modules` in a named volume `vite_node_modules`, and starts with `bun install --no-cache && bun run dev --host`. The exposed port is controlled by the `VITE_PORT` var (default `8080`), which the compose file also passes to `nginx-proxy` via `VIRTUAL_PORT`.
|
|
215
|
+
|
|
216
|
+
src/wexample_wex_addon_dev_javascript/services/vite/app_service.py composes the base `AppService` with `AgentContributingServiceMixin`, which makes the AI agent declared in src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/agent.yml discoverable by `wex talk`. The agent's system prompt lives in src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/about-service.md.
|
|
217
|
+
|
|
218
|
+
**`vite::service/install`** — src/wexample_wex_addon_dev_javascript/services/vite/commands/service/install.py patches `vite.config.ts` or `vite.config.js` to add `server: { allowedHosts: true }` inside `defineConfig`. It handles two shapes: a bare `defineConfig()` call and a `defineConfig({ ... })` block. The patch is idempotent (skips if `allowedHosts` is already present).
|
|
219
|
+
|
|
220
|
+
**`vite::service/ready`** — src/wexample_wex_addon_dev_javascript/services/vite/commands/service/ready.py reads `app.project_name` from the runtime config, resolves the container name as `{project_name}_vite`, reads `VITE_PORT` from the service manifest vars, then runs `docker exec {container} bun -e "await fetch('http://localhost:{port}')"` and returns a `BooleanResponse`.
|
|
221
|
+
|
|
222
|
+
#### `node` service
|
|
223
|
+
|
|
224
|
+
Defined in src/wexample_wex_addon_dev_javascript/services/node/service.yml. The container (`${APP_PROJECT_NAME}_node`) runs `node:20-alpine`, mounts the app path to `/var/www/html`, and stays alive with `tail -f /dev/null` so subsequent `docker exec` calls can run inside it.
|
|
225
|
+
|
|
226
|
+
**`node::service/install_local`** — src/wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py reads the `local_packages.javascript` key from the runtime config (a map of vendor names to package directories). It builds a shell script that first installs the full `node_modules` tree (using whichever of yarn, pnpm, or npm the project's lockfile identifies), then iterates every directory under `/var/www/javascript-dev/{vendor}/`, reads its `package.json` to get the `name` field, removes the corresponding entry from `node_modules/`, and replaces it with a symlink to the local source. The script runs inside the service container via `docker exec`.
|
|
227
|
+
|
|
228
|
+
**`node::service/refresh_lock`** — src/wexample_wex_addon_dev_javascript/services/node/commands/service/refresh_lock.py accepts a `--npm_packages` option listing the changed packages (for logging), then runs a lockfile-only install inside the container: `yarn install` if `yarn.lock` is present, `pnpm install --lockfile-only` if `pnpm-lock.yaml`, or `npm install --package-lock-only` if `package-lock.json`.
|
|
229
|
+
|
|
230
|
+
### Common utilities
|
|
231
|
+
|
|
232
|
+
src/wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py is a thin HTTP client over `AbstractGateway`. Its single public method `has_version(package, version)` fetches `/{encoded_package_name}` from the configured registry URL, parses the JSON manifest, and returns `True` if `version` appears in the `versions` map. It accepts an optional `token` for Bearer auth on private registries. `JavascriptPackageWorkdir._wait_for_registry()` calls it in a polling loop with a 30-second delay and a 40-attempt ceiling (20 minutes total).
|
|
233
|
+
|
|
234
|
+
### Constants
|
|
235
|
+
|
|
236
|
+
src/wexample_wex_addon_dev_javascript/const/tags.py declares `DomainTag` with three values — `domain:dev-server`, `domain:frontend`, `domain:service` — which the service commands attach via the `@command(tags=[...])` decorator. Tags govern how `wex talk` and automated agents filter and describe available commands.
|
|
237
|
+
|
|
238
|
+
## Integration in the Suite
|
|
239
|
+
|
|
240
|
+
This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
|
|
241
|
+
|
|
242
|
+
### Related Packages
|
|
243
|
+
|
|
244
|
+
The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
|
|
245
|
+
|
|
246
|
+
Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
|
|
247
|
+
|
|
248
|
+
## Dependencies
|
|
249
|
+
|
|
250
|
+
- attrs: >=23.1.0
|
|
251
|
+
- cattrs: >=23.1.0
|
|
252
|
+
- wexample-api: >=6.8.0
|
|
253
|
+
- wexample-filestate-javascript: >=6.6.0
|
|
254
|
+
- wexample-wex-addon-ai: >=14.0.0
|
|
255
|
+
- wexample-wex-addon-app: >=31.0.0
|
|
256
|
+
|
|
257
|
+
## Versioning & Compatibility Policy
|
|
258
|
+
|
|
259
|
+
Wexample packages follow **Semantic Versioning** (SemVer):
|
|
260
|
+
|
|
261
|
+
- **MAJOR**: Breaking changes
|
|
262
|
+
- **MINOR**: New features, backward compatible
|
|
263
|
+
- **PATCH**: Bug fixes, backward compatible
|
|
264
|
+
|
|
265
|
+
We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
270
|
+
|
|
271
|
+
Free to use in both personal and commercial projects.
|
|
272
|
+
|
|
273
|
+
## About us
|
|
274
|
+
|
|
275
|
+
[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
|
|
276
|
+
|
|
277
|
+
This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
|
|
278
|
+
|
|
279
|
+
Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
|
|
280
|
+
|
|
281
|
+
## Known Limitations & Roadmap
|
|
282
|
+
|
|
283
|
+
Current limitations and planned features are tracked in the GitHub issues.
|
|
284
|
+
|
|
285
|
+
See the [project roadmap](https://github.com/wexample/python-wex_addon_dev_javascript/issues) for upcoming features and improvements.
|
|
286
|
+
|
|
287
|
+
## Status & Compatibility
|
|
288
|
+
|
|
289
|
+
**Maturity**: Production-ready
|
|
290
|
+
|
|
291
|
+
**Python Support**: >=3.10
|
|
292
|
+
|
|
293
|
+
**OS Support**: Linux, macOS, Windows
|
|
294
|
+
|
|
295
|
+
**Status**: Actively maintained
|
|
296
|
+
|
|
297
|
+
## Useful Links
|
|
298
|
+
|
|
299
|
+
- **Homepage**: https://github.com/wexample/python-wex-addon-dev-javascript
|
|
300
|
+
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
|
|
301
|
+
- **Issue Tracker**: https://github.com/wexample/python-wex-addon-dev-javascript/issues
|
|
302
|
+
- **Discussions**: https://github.com/wexample/python-wex-addon-dev-javascript/discussions
|
|
303
|
+
- **PyPI**: [pypi.org/project/wexample-wex-addon-dev-javascript](https://pypi.org/project/wexample-wex-addon-dev-javascript/)
|
|
304
|
+
|
|
305
|
+
## Migration Notes
|
|
306
|
+
|
|
307
|
+
When upgrading between major versions, refer to the migration guides in the documentation.
|
|
308
|
+
|
|
309
|
+
Breaking changes are clearly documented with upgrade paths and examples.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# wex_addon_dev_javascript
|
|
2
|
+
|
|
3
|
+
Version: 8.1.1
|
|
4
|
+
|
|
5
|
+
`wex-addon-dev-javascript` extends wex for JavaScript and TypeScript developers: it enforces a standard project layout — requiring `package.json`, `tsconfig.json`, `.npmrc`, `src/`, `tests/`, and the corresponding `.gitignore` rules — and in local environments symlinks locally-developed npm packages directly into a running container's `node_modules/` so monorepo packages resolve without a registry publish cycle. It also contributes a `node` service and a `vite` service, each backed by Docker Compose, where the vite service patches `allowedHosts` in `vite.config.ts` for reverse-proxy use and the node service handles lockfile refresh, annotated-tag release, and registry polling for npm package suites managed through wex.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quickstart](#quickstart)
|
|
11
|
+
- [Tests](#tests)
|
|
12
|
+
- [Architecture](#architecture)
|
|
13
|
+
- [Integration in the Suite](#integration-in-the-suite)
|
|
14
|
+
- [Dependencies](#dependencies)
|
|
15
|
+
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
|
|
16
|
+
- [License](#license)
|
|
17
|
+
- [About us](#about-us)
|
|
18
|
+
- [Known Limitations & Roadmap](#known-limitations--roadmap)
|
|
19
|
+
- [Status & Compatibility](#status--compatibility)
|
|
20
|
+
- [Useful Links](#useful-links)
|
|
21
|
+
- [Migration Notes](#migration-notes)
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install wexample-wex-addon-dev-javascript
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Requires Python >=3.10.
|
|
30
|
+
|
|
31
|
+
## Quickstart
|
|
32
|
+
|
|
33
|
+
Install the package:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install wexample-wex-addon-dev-javascript
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The public entry point is `JavascriptAddonManager`, defined in src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from wexample_wex_addon_dev_javascript.javascript_addon_manager import JavascriptAddonManager
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Pass it to the kernel's `setup()` call to register the JavaScript addon slot:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from wexample_wex_core.common.kernel import Kernel
|
|
49
|
+
|
|
50
|
+
kernel = Kernel()
|
|
51
|
+
kernel.setup(addons=[JavascriptAddonManager])
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
After `setup()` returns, the kernel recognises three workdir types: `javascript`, `javascript-package`, and `javascript-packages-suite`. Any workdir resolved against a directory holding a `package.json` will be matched to the appropriate class.
|
|
55
|
+
|
|
56
|
+
The addon also contributes four service commands to the `node` and `vite` namespaces. Wire locally-developed npm packages into a running container's `node_modules/` — replacing the registry copy with a live symlink — with:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
wex node::service/install_local
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Refresh the lockfile in the container after a `package.json` dependency change (the command detects whether the project uses npm, pnpm, or Yarn from whichever lockfile is present):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
wex node::service/refresh_lock --npm_packages "@vendor/my-lib"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Patch `vite.config.ts` so the Vite dev server accepts requests from any host — required when the service runs behind a reverse proxy:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
wex vite::service/install
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Check whether the Vite dev server inside its container is responding:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
wex vite::service/ready
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Tests
|
|
81
|
+
|
|
82
|
+
This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
|
|
83
|
+
|
|
84
|
+
### Installation
|
|
85
|
+
|
|
86
|
+
First, install the required testing dependencies:
|
|
87
|
+
```bash
|
|
88
|
+
.venv/bin/python -m pip install pytest pytest-cov
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Basic Usage
|
|
92
|
+
|
|
93
|
+
Run all tests with coverage:
|
|
94
|
+
```bash
|
|
95
|
+
.venv/bin/python -m pytest --cov --cov-report=html
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Common Commands
|
|
99
|
+
```bash
|
|
100
|
+
# Run tests with coverage for a specific module
|
|
101
|
+
.venv/bin/python -m pytest --cov=your_module
|
|
102
|
+
|
|
103
|
+
# Show which lines are not covered
|
|
104
|
+
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
|
|
105
|
+
|
|
106
|
+
# Generate an HTML coverage report
|
|
107
|
+
.venv/bin/python -m pytest --cov=your_module --cov-report=html
|
|
108
|
+
|
|
109
|
+
# Combine terminal and HTML reports
|
|
110
|
+
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
|
|
111
|
+
|
|
112
|
+
# Run specific test file with coverage
|
|
113
|
+
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Viewing HTML Reports
|
|
117
|
+
|
|
118
|
+
After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
|
|
119
|
+
|
|
120
|
+
### Coverage Threshold
|
|
121
|
+
|
|
122
|
+
To enforce a minimum coverage percentage:
|
|
123
|
+
```bash
|
|
124
|
+
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This will cause the test suite to fail if coverage drops below 80%.
|
|
128
|
+
|
|
129
|
+
## Architecture
|
|
130
|
+
|
|
131
|
+
The addon is a pure Python package that extends wex with JavaScript and TypeScript support. It has four layers: an addon manager that registers workdir types, a workdir hierarchy that enforces project layout and owns the release lifecycle, a file layer that controls what `package.json` and `tsconfig.json` contain when written to disk, and a service layer that contributes `node` and `vite` Docker service definitions with their commands.
|
|
132
|
+
|
|
133
|
+
### Entry point
|
|
134
|
+
|
|
135
|
+
src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py is the only class the host kernel needs. It extends `AbstractAddonManager` and returns three workdir types from `get_workdir_types()`:
|
|
136
|
+
|
|
137
|
+
| key | class |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `javascript` | `JavascriptWorkdir` |
|
|
140
|
+
| `javascript-package` | `JavascriptPackageWorkdir` |
|
|
141
|
+
| `javascript-packages-suite` | `JavascriptPackagesSuiteWorkdir` |
|
|
142
|
+
|
|
143
|
+
The kernel resolves a directory to the right class by matching that key against the workdir type declared in the project's wex config.
|
|
144
|
+
|
|
145
|
+
### Workdir layer
|
|
146
|
+
|
|
147
|
+
The three classes form a linear inheritance chain.
|
|
148
|
+
|
|
149
|
+
#### `JavascriptWorkdir`
|
|
150
|
+
|
|
151
|
+
src/wexample_wex_addon_dev_javascript/workdir/javascript_workdir.py is the base. It extends `CodeBaseWorkdir` (from `wexample-wex-addon-app`) and `WithAiWorkdirMixin`. Its `prepare_value()` declares the required filesystem layout that wex will enforce: `package.json`, `tsconfig.json`, `.npmrc`, a `src/` tree, a `tests/` tree, and `.gitignore` rules covering `node_modules/`, `dist/`, `build/`, `.npm`, and `.eslintcache`. JS/TS files under `src/` and `tests/` are captured by a `ChildrenFilterOption` that matches `*.js|jsx|ts|tsx` and applies the `BiomeOption` from `wexample-filestate-javascript`. The class also appends `JavascriptOptionsProvider` to the options chain and returns a `JavascriptPackageJsonFile` from `get_app_config_file()`.
|
|
152
|
+
|
|
153
|
+
#### `JavascriptPackageWorkdir`
|
|
154
|
+
|
|
155
|
+
src/wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py extends `JavascriptWorkdir` and adds everything a publishable npm package needs.
|
|
156
|
+
|
|
157
|
+
**Naming.** `get_project_name()` returns `@{vendor}/{kebab-case-name}`, giving packages their scoped npm identity.
|
|
158
|
+
|
|
159
|
+
**Layout addition.** `prepare_value()` appends `.github/workflows/publish.yml` to the enforced file tree. The content is read from the bundled resource src/wexample_wex_addon_dev_javascript/resources/package_publish.yml — a GitHub Actions workflow that publishes to npm on any `v*` tag push.
|
|
160
|
+
|
|
161
|
+
**Release lifecycle.** `release()` runs three steps in order:
|
|
162
|
+
1. `_refresh_lockfile()` — detects which lockfile is present (`package-lock.json`, `pnpm-lock.yaml`, or `yarn.lock`) and runs the matching lock-only refresh command on the host machine.
|
|
163
|
+
2. `super().release()` — inherited bump, commit, and publish flow; `_publish()` overrides the publish step to create an annotated git tag (`v{version}`) and push it to the configured deployment remote, which triggers the CI workflow above.
|
|
164
|
+
3. `_wait_for_registry()` — polls `NpmRegistryGateway.has_version()` every 30 s for up to 20 minutes before the suite loop advances to the next dependent package.
|
|
165
|
+
|
|
166
|
+
**Version bump classification.** `_classify_version_bump()` inspects the git diff of `src/` since the last tag: no changes → minor bump; whitespace-only diff → minor; non-TypeScript files only → intermediate; any `.ts`/`.tsx` change → major.
|
|
167
|
+
|
|
168
|
+
#### `JavascriptPackagesSuiteWorkdir`
|
|
169
|
+
|
|
170
|
+
src/wexample_wex_addon_dev_javascript/workdir/javascript_packages_suite_workdir.py extends `FrameworkPackageSuiteWorkdir`. It discovers child packages by looking for directories inside `npm/` that contain a `package.json`, and resolves each child as a `JavascriptPackageWorkdir`.
|
|
171
|
+
|
|
172
|
+
### File layer
|
|
173
|
+
|
|
174
|
+
#### `NodePackageJsonFile`
|
|
175
|
+
|
|
176
|
+
src/wexample_wex_addon_dev_javascript/file/node_package_json_file.py composes `AppDependenciesConfigFileMixin` with `JsonFile`. It exposes the dependency-manifest API (`add_dependency`, `add_dependency_from_string`, `get_dependencies_versions`) and reads `dependencies` plus `peerDependencies` as the set of declared runtime constraints. Any workdir that ships a `package.json` — including polyglot app manifests — can attach this class.
|
|
177
|
+
|
|
178
|
+
#### `JavascriptPackageJsonFile`
|
|
179
|
+
|
|
180
|
+
src/wexample_wex_addon_dev_javascript/file/javascript_package_json_file.py extends `NodePackageJsonFile`. Its `dumps()` stamps `name`, `version`, and `repository` from the parent workdir before delegating to the JSON serialiser. It also calls `_apply_default_publish_config()`, which sets `type: "module"`, ensures `publishConfig.access` defaults to `"public"`, and — when neither `exports` nor a `dist`-targeting `files` array is already present — injects a default `exports` map (`"./*": { types: "./dist/*.d.ts", default: "./dist/*.js" }`), a `files: ["dist"]` list, and a `typesVersions` block so consumers can import without transpiling sources.
|
|
181
|
+
|
|
182
|
+
#### `JavascriptTsconfigJsonFile`
|
|
183
|
+
|
|
184
|
+
src/wexample_wex_addon_dev_javascript/file/javascript_tsconfig_json_file.py extends `JsonFile`. Its `dumps()` fills in `compilerOptions` defaults (`target: ES2020`, `module: NodeNext`, `moduleResolution: NodeNext`, `rootDir: src`, `outDir: dist`, `declaration: true`, `declarationMap: true`, `sourceMap: true`, `strict: false`, `esModuleInterop: true`, `skipLibCheck: true`, `forceConsistentCasingInFileNames: true`) and sets `include: ["src"]`, `exclude: ["dist", "node_modules", "tests"]`. All defaults use `setdefault`, so anything already in the file is left untouched.
|
|
185
|
+
|
|
186
|
+
### Service layer
|
|
187
|
+
|
|
188
|
+
Two service namespaces ship as self-contained directories, each containing a `service.yml`, a `docker/docker-compose.yml`, and a `commands/service/` package.
|
|
189
|
+
|
|
190
|
+
#### `vite` service
|
|
191
|
+
|
|
192
|
+
Defined in src/wexample_wex_addon_dev_javascript/services/vite/service.yml. The container (`${APP_PROJECT_NAME}_vite`) runs `oven/bun:latest`, mounts the app path to `/app`, persists `node_modules` in a named volume `vite_node_modules`, and starts with `bun install --no-cache && bun run dev --host`. The exposed port is controlled by the `VITE_PORT` var (default `8080`), which the compose file also passes to `nginx-proxy` via `VIRTUAL_PORT`.
|
|
193
|
+
|
|
194
|
+
src/wexample_wex_addon_dev_javascript/services/vite/app_service.py composes the base `AppService` with `AgentContributingServiceMixin`, which makes the AI agent declared in src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/agent.yml discoverable by `wex talk`. The agent's system prompt lives in src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/about-service.md.
|
|
195
|
+
|
|
196
|
+
**`vite::service/install`** — src/wexample_wex_addon_dev_javascript/services/vite/commands/service/install.py patches `vite.config.ts` or `vite.config.js` to add `server: { allowedHosts: true }` inside `defineConfig`. It handles two shapes: a bare `defineConfig()` call and a `defineConfig({ ... })` block. The patch is idempotent (skips if `allowedHosts` is already present).
|
|
197
|
+
|
|
198
|
+
**`vite::service/ready`** — src/wexample_wex_addon_dev_javascript/services/vite/commands/service/ready.py reads `app.project_name` from the runtime config, resolves the container name as `{project_name}_vite`, reads `VITE_PORT` from the service manifest vars, then runs `docker exec {container} bun -e "await fetch('http://localhost:{port}')"` and returns a `BooleanResponse`.
|
|
199
|
+
|
|
200
|
+
#### `node` service
|
|
201
|
+
|
|
202
|
+
Defined in src/wexample_wex_addon_dev_javascript/services/node/service.yml. The container (`${APP_PROJECT_NAME}_node`) runs `node:20-alpine`, mounts the app path to `/var/www/html`, and stays alive with `tail -f /dev/null` so subsequent `docker exec` calls can run inside it.
|
|
203
|
+
|
|
204
|
+
**`node::service/install_local`** — src/wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py reads the `local_packages.javascript` key from the runtime config (a map of vendor names to package directories). It builds a shell script that first installs the full `node_modules` tree (using whichever of yarn, pnpm, or npm the project's lockfile identifies), then iterates every directory under `/var/www/javascript-dev/{vendor}/`, reads its `package.json` to get the `name` field, removes the corresponding entry from `node_modules/`, and replaces it with a symlink to the local source. The script runs inside the service container via `docker exec`.
|
|
205
|
+
|
|
206
|
+
**`node::service/refresh_lock`** — src/wexample_wex_addon_dev_javascript/services/node/commands/service/refresh_lock.py accepts a `--npm_packages` option listing the changed packages (for logging), then runs a lockfile-only install inside the container: `yarn install` if `yarn.lock` is present, `pnpm install --lockfile-only` if `pnpm-lock.yaml`, or `npm install --package-lock-only` if `package-lock.json`.
|
|
207
|
+
|
|
208
|
+
### Common utilities
|
|
209
|
+
|
|
210
|
+
src/wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py is a thin HTTP client over `AbstractGateway`. Its single public method `has_version(package, version)` fetches `/{encoded_package_name}` from the configured registry URL, parses the JSON manifest, and returns `True` if `version` appears in the `versions` map. It accepts an optional `token` for Bearer auth on private registries. `JavascriptPackageWorkdir._wait_for_registry()` calls it in a polling loop with a 30-second delay and a 40-attempt ceiling (20 minutes total).
|
|
211
|
+
|
|
212
|
+
### Constants
|
|
213
|
+
|
|
214
|
+
src/wexample_wex_addon_dev_javascript/const/tags.py declares `DomainTag` with three values — `domain:dev-server`, `domain:frontend`, `domain:service` — which the service commands attach via the `@command(tags=[...])` decorator. Tags govern how `wex talk` and automated agents filter and describe available commands.
|
|
215
|
+
|
|
216
|
+
## Integration in the Suite
|
|
217
|
+
|
|
218
|
+
This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
|
|
219
|
+
|
|
220
|
+
### Related Packages
|
|
221
|
+
|
|
222
|
+
The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
|
|
223
|
+
|
|
224
|
+
Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
|
|
225
|
+
|
|
226
|
+
## Dependencies
|
|
227
|
+
|
|
228
|
+
- attrs: >=23.1.0
|
|
229
|
+
- cattrs: >=23.1.0
|
|
230
|
+
- wexample-api: >=6.8.0
|
|
231
|
+
- wexample-filestate-javascript: >=6.6.0
|
|
232
|
+
- wexample-wex-addon-ai: >=14.0.0
|
|
233
|
+
- wexample-wex-addon-app: >=31.0.0
|
|
234
|
+
|
|
235
|
+
## Versioning & Compatibility Policy
|
|
236
|
+
|
|
237
|
+
Wexample packages follow **Semantic Versioning** (SemVer):
|
|
238
|
+
|
|
239
|
+
- **MAJOR**: Breaking changes
|
|
240
|
+
- **MINOR**: New features, backward compatible
|
|
241
|
+
- **PATCH**: Bug fixes, backward compatible
|
|
242
|
+
|
|
243
|
+
We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
248
|
+
|
|
249
|
+
Free to use in both personal and commercial projects.
|
|
250
|
+
|
|
251
|
+
## About us
|
|
252
|
+
|
|
253
|
+
[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
|
|
254
|
+
|
|
255
|
+
This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
|
|
256
|
+
|
|
257
|
+
Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
|
|
258
|
+
|
|
259
|
+
## Known Limitations & Roadmap
|
|
260
|
+
|
|
261
|
+
Current limitations and planned features are tracked in the GitHub issues.
|
|
262
|
+
|
|
263
|
+
See the [project roadmap](https://github.com/wexample/python-wex_addon_dev_javascript/issues) for upcoming features and improvements.
|
|
264
|
+
|
|
265
|
+
## Status & Compatibility
|
|
266
|
+
|
|
267
|
+
**Maturity**: Production-ready
|
|
268
|
+
|
|
269
|
+
**Python Support**: >=3.10
|
|
270
|
+
|
|
271
|
+
**OS Support**: Linux, macOS, Windows
|
|
272
|
+
|
|
273
|
+
**Status**: Actively maintained
|
|
274
|
+
|
|
275
|
+
## Useful Links
|
|
276
|
+
|
|
277
|
+
- **Homepage**: https://github.com/wexample/python-wex-addon-dev-javascript
|
|
278
|
+
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
|
|
279
|
+
- **Issue Tracker**: https://github.com/wexample/python-wex-addon-dev-javascript/issues
|
|
280
|
+
- **Discussions**: https://github.com/wexample/python-wex-addon-dev-javascript/discussions
|
|
281
|
+
- **PyPI**: [pypi.org/project/wexample-wex-addon-dev-javascript](https://pypi.org/project/wexample-wex-addon-dev-javascript/)
|
|
282
|
+
|
|
283
|
+
## Migration Notes
|
|
284
|
+
|
|
285
|
+
When upgrading between major versions, refer to the migration guides in the documentation.
|
|
286
|
+
|
|
287
|
+
Breaking changes are clearly documented with upgrade paths and examples.
|
{wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.1}/pyproject.toml
RENAMED
|
@@ -6,8 +6,8 @@ build-backend = "pdm.backend"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "wexample-wex-addon-dev-javascript"
|
|
9
|
-
version = "8.
|
|
10
|
-
description = "
|
|
9
|
+
version = "8.1.1"
|
|
10
|
+
description = "Extends wex with JavaScript support: enforces JS/TS project layout and symlinks local npm packages into node_modules"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "weeger", email = "contact@wexample.com" },
|
|
13
13
|
]
|
|
@@ -22,8 +22,8 @@ dependencies = [
|
|
|
22
22
|
"cattrs>=23.1.0",
|
|
23
23
|
"wexample-api>=6.8.0",
|
|
24
24
|
"wexample-filestate-javascript>=6.6.0",
|
|
25
|
-
"wexample-wex-addon-ai>=
|
|
26
|
-
"wexample-wex-addon-app>=
|
|
25
|
+
"wexample-wex-addon-ai>=14.0.0",
|
|
26
|
+
"wexample-wex-addon-app>=31.0.0",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.readme]
|
|
@@ -10,5 +10,8 @@ from wexample_wex_addon_app.config_value.app_readme_config_value import (
|
|
|
10
10
|
class JavascriptPackageReadmeContentConfigValue(AppReadmeConfigValue):
|
|
11
11
|
"""README generation for Javascript packages."""
|
|
12
12
|
|
|
13
|
-
def _get_app_description(self) -> str:
|
|
14
|
-
return
|
|
13
|
+
def _get_app_description(self) -> str | None:
|
|
14
|
+
return (
|
|
15
|
+
self.workdir.get_app_config().get("description")
|
|
16
|
+
or super()._get_app_description()
|
|
17
|
+
)
|