wexample-wex-addon-dev-javascript 8.0.0__tar.gz → 8.1.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 (54) hide show
  1. wexample_wex_addon_dev_javascript-8.1.0/PKG-INFO +309 -0
  2. wexample_wex_addon_dev_javascript-8.1.0/README.md +287 -0
  3. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/pyproject.toml +4 -4
  4. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/config_value/javascript_package_readme_config_value.py +5 -2
  5. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/formatter}/__init__.py +0 -0
  6. wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/formatter/javascript_code_formatter.py +43 -0
  7. wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py +37 -0
  8. wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/resources/design_rules/javascript_code.md +17 -0
  9. wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/resources/writing_rules/javascript_code.md +26 -0
  10. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/node/commands → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/services/node}/__init__.py +0 -0
  11. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/services/node/commands/service}/__init__.py +0 -0
  12. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/node/commands/service/refresh_lock.py +7 -2
  13. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/ai → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/services/vite}/__init__.py +0 -0
  14. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/vite/commands → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main}/__init__.py +0 -0
  15. wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/workdir/__init__.py +0 -0
  16. wexample_wex_addon_dev_javascript-8.1.0/tests/.gitkeep +0 -0
  17. wexample_wex_addon_dev_javascript-8.0.0/PKG-INFO +0 -475
  18. wexample_wex_addon_dev_javascript-8.0.0/README.md +0 -453
  19. wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py +0 -7
  20. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/__init__.py +0 -0
  21. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/__pycache__/__init__.py +0 -0
  22. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/common/__init__.py +0 -0
  23. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py +0 -0
  24. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/config_value/__init__.py +0 -0
  25. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/const/__init__.py +0 -0
  26. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/const/tags.py +0 -0
  27. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/file/__init__.py +0 -0
  28. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/file/javascript_package_json_file.py +0 -0
  29. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/file/javascript_tsconfig_json_file.py +0 -0
  30. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/file/node_package_json_file.py +0 -0
  31. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/py.typed +0 -0
  32. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/resources/.wex.yml +0 -0
  33. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/resources/package_publish.yml +0 -0
  34. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/services/node → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/services}/__init__.py +0 -0
  35. {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.0/src/wexample_wex_addon_dev_javascript/services/node/commands}/__init__.py +0 -0
  36. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py +0 -0
  37. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/node/docker/.wex.yml +0 -0
  38. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/node/docker/docker-compose.yml +0 -0
  39. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/node/service.yml +0 -0
  40. {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.0/src/wexample_wex_addon_dev_javascript/services/vite/ai}/__init__.py +0 -0
  41. {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.0/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents}/__init__.py +0 -0
  42. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/about-service.md +0 -0
  43. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/agent.yml +0 -0
  44. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/app_service.py +0 -0
  45. {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.0/src/wexample_wex_addon_dev_javascript/services/vite/commands}/__init__.py +0 -0
  46. {wexample_wex_addon_dev_javascript-8.0.0/src/wexample_wex_addon_dev_javascript/workdir → wexample_wex_addon_dev_javascript-8.1.0/src/wexample_wex_addon_dev_javascript/services/vite/commands/service}/__init__.py +0 -0
  47. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/commands/service/install.py +0 -0
  48. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/commands/service/ready.py +0 -0
  49. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/docker/.wex.yml +0 -0
  50. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/docker/docker-compose.yml +0 -0
  51. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/services/vite/service.yml +0 -0
  52. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py +0 -0
  53. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/src/wexample_wex_addon_dev_javascript/workdir/javascript_packages_suite_workdir.py +0 -0
  54. {wexample_wex_addon_dev_javascript-8.0.0 → wexample_wex_addon_dev_javascript-8.1.0}/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.0
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>=13.0.0
17
+ Requires-Dist: wexample-wex-addon-app>=30.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.0
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: >=13.0.0
255
+ - wexample-wex-addon-app: >=30.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.0
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: >=13.0.0
233
+ - wexample-wex-addon-app: >=30.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.
@@ -6,8 +6,8 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-wex-addon-dev-javascript"
9
- version = "8.0.0"
10
- description = "Python dev addon for wex"
9
+ version = "8.1.0"
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>=12.1.0",
26
- "wexample-wex-addon-app>=29.0.0",
25
+ "wexample-wex-addon-ai>=13.0.0",
26
+ "wexample-wex-addon-app>=30.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 self.workdir.get_app_config().get("description", "")
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
+ )