@makinzm/mille 0.0.10 → 0.0.12

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 (3) hide show
  1. package/README.md +162 -11
  2. package/mille.wasm +0 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -18,11 +18,11 @@ One TOML config. Rust-powered. CI-ready. Supports multiple languages from a sing
18
18
 
19
19
  ## What it checks
20
20
 
21
- | Check | Rust | Go | TypeScript | JavaScript | Python |
22
- |---|:---:|:---:|:---:|:---:|:---:|
23
- | Layer dependency rules (`dependency_mode`) | ✅ | ✅ | ✅ | ✅ | ✅ |
24
- | External library rules (`external_mode`) | ✅ | ✅ | ✅ | ✅ | ✅ |
25
- | DI method call rules (`allow_call_patterns`) | ✅ | ✅ | ✅ | ✅ | ✅ |
21
+ | Check | Rust | Go | TypeScript | JavaScript | Python | Java | Kotlin |
22
+ |---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
23
+ | Layer dependency rules (`dependency_mode`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
24
+ | External library rules (`external_mode`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
25
+ | DI method call rules (`allow_call_patterns`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
26
26
 
27
27
  ## Install
28
28
 
@@ -114,6 +114,32 @@ Generated 'mille.toml'
114
114
 
115
115
  The generated config includes `allow` (inferred internal dependencies) and `external_allow` (detected external packages) per layer. After generating, review the config and run `mille check` to see results.
116
116
 
117
+ **Naming in monorepos**: When multiple sub-projects contain a directory with the same name (e.g. `crawler/src/domain` and `server/src/domain`), `mille init` gives each its own layer with a distinguishing prefix (`crawler_domain`, `server_domain`). Merging is left to you.
118
+
119
+ **Excluded paths**: `mille check` automatically skips `.venv`, `venv`, `node_modules`, `target`, `dist`, `build`, and similar build/dependency directories, so generated `paths` patterns like `apps/**` are safe to use.
120
+
121
+ **Python submodule imports**: `external_allow = ["matplotlib"]` correctly allows both `import matplotlib` and `import matplotlib.pyplot`.
122
+
123
+ **Go projects**: `mille init` reads `go.mod` and generates `[resolve.go] module_name` automatically — internal module imports are classified correctly during `mille check`. External packages appear in `external_allow` with their full import paths (e.g. `"github.com/cilium/ebpf"`, `"fmt"`, `"net/http"`).
124
+
125
+ **TypeScript/JavaScript subpath imports**: `external_allow = ["vitest"]` correctly allows both `import "vitest"` and `import "vitest/config"`. Scoped packages (`@scope/name/sub`) are matched by `"@scope/name"`.
126
+
127
+ **Java/Kotlin projects**: `mille init` uses `package` declarations — not directory depth — to detect layers. This works correctly for Maven's `src/main/java/com/example/myapp/domain/` as well as flat `src/domain/` layouts. `pom.xml` (Maven) and `build.gradle` + `settings.gradle` (Gradle) are read automatically to generate `[resolve.java] module_name`. Layer paths use `**/layer/**` globs so `mille check` matches regardless of the source root depth.
128
+
129
+ ```
130
+ Detected languages: java
131
+ Scanning imports...
132
+
133
+ Inferred layer structure:
134
+ domain ← (no internal dependencies)
135
+ infrastructure → domain
136
+ external: java.util.List
137
+ usecase → domain
138
+ main → domain, infrastructure, usecase
139
+
140
+ Generated 'mille.toml'
141
+ ```
142
+
117
143
  ### 2. (Or) Create `mille.toml` manually
118
144
 
119
145
  Place `mille.toml` in your project root:
@@ -274,7 +300,85 @@ external_mode = "opt-out"
274
300
  external_deny = []
275
301
  ```
276
302
 
277
- ### 2. Run `mille check`
303
+ **Java / Kotlin:**
304
+
305
+ ```toml
306
+ [project]
307
+ name = "my-java-app"
308
+ root = "."
309
+ languages = ["java"] # or ["kotlin"] for Kotlin projects
310
+
311
+ [resolve.java]
312
+ module_name = "com.example.myapp"
313
+
314
+ [[layers]]
315
+ name = "domain"
316
+ paths = ["src/domain/**"]
317
+ dependency_mode = "opt-in"
318
+ allow = []
319
+ external_mode = "opt-out"
320
+
321
+ [[layers]]
322
+ name = "usecase"
323
+ paths = ["src/usecase/**"]
324
+ dependency_mode = "opt-in"
325
+ allow = ["domain"]
326
+ external_mode = "opt-out"
327
+
328
+ [[layers]]
329
+ name = "infrastructure"
330
+ paths = ["src/infrastructure/**"]
331
+ dependency_mode = "opt-in"
332
+ allow = ["domain"]
333
+ external_mode = "opt-in"
334
+ external_allow = ["java.util.List", "java.util.Map"]
335
+ ```
336
+
337
+ > `module_name` is the base package of your project (e.g. `com.example.myapp`). Imports starting with this prefix are classified as **Internal** and matched against layer globs. All other imports (including `java.util.*` stdlib) are classified as **External** and subject to `external_allow` / `external_deny` rules.
338
+
339
+ ### 2. Visualize with `mille analyze`
340
+
341
+ Before enforcing rules, you can inspect the actual dependency graph:
342
+
343
+ ```sh
344
+ mille analyze # human-readable terminal output (default)
345
+ mille analyze --format json # machine-readable JSON graph
346
+ mille analyze --format dot # Graphviz DOT (pipe to: dot -Tsvg -o graph.svg)
347
+ mille analyze --format svg # self-contained SVG image (open in a browser)
348
+ ```
349
+
350
+ Example SVG output (dark theme, green edges):
351
+
352
+ ```sh
353
+ mille analyze --format svg > graph.svg && open graph.svg
354
+ ```
355
+
356
+ `mille analyze` always exits `0` — it only visualizes, never enforces rules.
357
+
358
+ ### 3. Inspect external dependencies with `mille report external`
359
+
360
+ ```sh
361
+ mille report external # human-readable table (default)
362
+ mille report external --format json # machine-readable JSON
363
+ mille report external --output report.json --format json # write to file
364
+ ```
365
+
366
+ Shows which external packages each layer actually imports — useful for auditing `external_allow` lists or documenting your dependency footprint.
367
+
368
+ Example output:
369
+
370
+ ```
371
+ External Dependencies by Layer
372
+
373
+ domain (none)
374
+ usecase (none)
375
+ infrastructure database/sql
376
+ cmd fmt, os
377
+ ```
378
+
379
+ `mille report external` always exits `0` — it only reports, never enforces rules.
380
+
381
+ ### 4. Run `mille check`
278
382
 
279
383
  ```sh
280
384
  mille check
@@ -288,12 +392,20 @@ mille check --format github-actions # GitHub Actions annotations (::error file=
288
392
  mille check --format json # machine-readable JSON
289
393
  ```
290
394
 
395
+ Fail threshold:
396
+
397
+ ```sh
398
+ mille check # exit 1 on error-severity violations only (default)
399
+ mille check --fail-on warning # exit 1 on any violation (error or warning)
400
+ mille check --fail-on error # explicit default — same as no flag
401
+ ```
402
+
291
403
  Exit codes:
292
404
 
293
405
  | Code | Meaning |
294
406
  |---|---|
295
- | `0` | No violations |
296
- | `1` | One or more violations detected |
407
+ | `0` | No violations (or only warnings without `--fail-on warning`) |
408
+ | `1` | One or more violations at the configured fail threshold |
297
409
  | `3` | Configuration file error |
298
410
 
299
411
  ## Configuration Reference
@@ -304,7 +416,7 @@ Exit codes:
304
416
  |---|---|
305
417
  | `name` | Project name |
306
418
  | `root` | Root directory for analysis |
307
- | `languages` | Languages to check: `"rust"`, `"go"`, `"typescript"`, `"javascript"`, `"python"` |
419
+ | `languages` | Languages to check: `"rust"`, `"go"`, `"typescript"`, `"javascript"`, `"python"`, `"java"`, `"kotlin"` |
308
420
 
309
421
  ### `[[layers]]`
310
422
 
@@ -348,6 +460,27 @@ test_patterns = ["**/*_test.go", "**/*.spec.ts", "**/*.test.ts"]
348
460
  - `paths`: Files that should not be analyzed at all (generated code, vendor directories, mocks)
349
461
  - `test_patterns`: Test files that intentionally import across layers (e.g., integration tests that import both domain and infrastructure)
350
462
 
463
+ ### `[severity]`
464
+
465
+ Control the severity level of each violation type. Violations can be `"error"`, `"warning"`, or `"info"`.
466
+
467
+ | Key | Default | Description |
468
+ |---|---|---|
469
+ | `dependency_violation` | `"error"` | Layer dependency rule violated |
470
+ | `external_violation` | `"error"` | External library rule violated |
471
+ | `call_pattern_violation` | `"error"` | DI entrypoint method call rule violated |
472
+ | `unknown_import` | `"warning"` | Import that could not be classified |
473
+
474
+ ```toml
475
+ [severity]
476
+ dependency_violation = "warning" # treat as warning for gradual adoption
477
+ external_violation = "error"
478
+ call_pattern_violation = "error"
479
+ unknown_import = "warning"
480
+ ```
481
+
482
+ Use `--fail-on warning` to exit 1 even for warnings when integrating into CI gradually.
483
+
351
484
  ### `[resolve.typescript]`
352
485
 
353
486
  | Key | Description |
@@ -368,7 +501,7 @@ test_patterns = ["**/*_test.go", "**/*.spec.ts", "**/*.test.ts"]
368
501
 
369
502
  | Key | Description |
370
503
  |---|---|
371
- | `module_name` | Go module name (matches `go.mod`) |
504
+ | `module_name` | Go module name (matches `go.mod`). `mille init` generates this automatically from `go.mod`. |
372
505
 
373
506
  ### `[resolve.python]`
374
507
 
@@ -385,6 +518,24 @@ test_patterns = ["**/*_test.go", "**/*.spec.ts", "**/*.test.ts"]
385
518
  | `import domain.entity` (matches `package_names`) | Internal |
386
519
  | `import os`, `import sqlalchemy` | External |
387
520
 
521
+ ### `[resolve.java]`
522
+
523
+ | Key | Description |
524
+ |---|---|
525
+ | `module_name` | Base package of your project (e.g. `com.example.myapp`). Imports starting with this prefix are classified as Internal. Generated automatically by `mille init`. |
526
+ | `pom_xml` | Path to `pom.xml` (relative to `mille.toml`). `groupId.artifactId` is used as `module_name` when `module_name` is not set. |
527
+ | `build_gradle` | Path to `build.gradle` (relative to `mille.toml`). `group` + `rootProject.name` from `settings.gradle` is used as `module_name` when `module_name` is not set. |
528
+
529
+ **How Java imports are classified:**
530
+
531
+ | Import | Classification |
532
+ |---|---|
533
+ | `import com.example.myapp.domain.User` (starts with `module_name`) | Internal |
534
+ | `import static com.example.myapp.util.Helper.method` | Internal |
535
+ | `import java.util.List`, `import org.springframework.*` | External |
536
+
537
+ > Both regular and static imports are supported. Wildcard imports (`import java.util.*`) are not yet extracted by the parser.
538
+
388
539
  ## How it Works
389
540
 
390
541
  mille uses [tree-sitter](https://tree-sitter.github.io/) for AST-based import extraction — no regex heuristics.
@@ -395,7 +546,7 @@ mille.toml
395
546
 
396
547
  Layer definitions
397
548
 
398
- Source files (*.rs, *.go, *.py, *.ts, *.js, ...)
549
+ Source files (*.rs, *.go, *.py, *.ts, *.js, *.java, ...)
399
550
  │ tree-sitter parse
400
551
 
401
552
  RawImport list
package/mille.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makinzm/mille",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Architecture Checker — Rust-based multi-language architecture linter",
5
5
  "main": "index.js",
6
6
  "bin": {