@makinzm/mille 0.0.11 → 0.0.13

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 +167 -7
  2. package/mille.wasm +0 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -18,11 +18,12 @@ 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 | PHP |
22
+ |---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
23
+ | Layer dependency rules (`dependency_mode`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
24
+ | External library rules (`external_mode`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
25
+ | DI method call rules (`allow_call_patterns`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
26
+ | Naming convention rules (`name_deny`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
26
27
 
27
28
  ## Install
28
29
 
@@ -120,10 +121,28 @@ The generated config includes `allow` (inferred internal dependencies) and `exte
120
121
 
121
122
  **Python submodule imports**: `external_allow = ["matplotlib"]` correctly allows both `import matplotlib` and `import matplotlib.pyplot`.
122
123
 
124
+ **Python `src/` layout (namespace packages)**: When your project uses a `src/` layout and imports like `from src.domain.entity import Foo`, `mille init` detects that `src` is used as a top-level import prefix and automatically adds it to `package_names`. This means `from src.domain...` is classified as Internal and `src` does not appear in `external_allow`. Cross-layer imports like `from src.domain.entity import Foo` (written in `src/infrastructure/`) are correctly resolved to the `src/domain` layer and appear as an `allow` dependency in the generated `mille.toml`. Files at the project root of a sub-tree (e.g. `src/main.py`) are included in the `src` layer rather than being silently skipped.
125
+
123
126
  **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
127
 
125
128
  **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
129
 
130
+ **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.
131
+
132
+ ```
133
+ Detected languages: java
134
+ Scanning imports...
135
+
136
+ Inferred layer structure:
137
+ domain ← (no internal dependencies)
138
+ infrastructure → domain
139
+ external: java.util.List
140
+ usecase → domain
141
+ main → domain, infrastructure, usecase
142
+
143
+ Generated 'mille.toml'
144
+ ```
145
+
127
146
  ### 2. (Or) Create `mille.toml` manually
128
147
 
129
148
  Place `mille.toml` in your project root:
@@ -284,6 +303,42 @@ external_mode = "opt-out"
284
303
  external_deny = []
285
304
  ```
286
305
 
306
+ **Java / Kotlin:**
307
+
308
+ ```toml
309
+ [project]
310
+ name = "my-java-app"
311
+ root = "."
312
+ languages = ["java"] # or ["kotlin"] for Kotlin projects
313
+
314
+ [resolve.java]
315
+ module_name = "com.example.myapp"
316
+
317
+ [[layers]]
318
+ name = "domain"
319
+ paths = ["src/domain/**"]
320
+ dependency_mode = "opt-in"
321
+ allow = []
322
+ external_mode = "opt-out"
323
+
324
+ [[layers]]
325
+ name = "usecase"
326
+ paths = ["src/usecase/**"]
327
+ dependency_mode = "opt-in"
328
+ allow = ["domain"]
329
+ external_mode = "opt-out"
330
+
331
+ [[layers]]
332
+ name = "infrastructure"
333
+ paths = ["src/infrastructure/**"]
334
+ dependency_mode = "opt-in"
335
+ allow = ["domain"]
336
+ external_mode = "opt-in"
337
+ external_allow = ["java.util.List", "java.util.Map"]
338
+ ```
339
+
340
+ > `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.
341
+
287
342
  ### 2. Visualize with `mille analyze`
288
343
 
289
344
  Before enforcing rules, you can inspect the actual dependency graph:
@@ -364,7 +419,7 @@ Exit codes:
364
419
  |---|---|
365
420
  | `name` | Project name |
366
421
  | `root` | Root directory for analysis |
367
- | `languages` | Languages to check: `"rust"`, `"go"`, `"typescript"`, `"javascript"`, `"python"` |
422
+ | `languages` | Languages to check: `"rust"`, `"go"`, `"typescript"`, `"javascript"`, `"python"`, `"java"`, `"kotlin"`, `"php"` |
368
423
 
369
424
  ### `[[layers]]`
370
425
 
@@ -378,6 +433,43 @@ Exit codes:
378
433
  | `external_mode` | `"opt-in"` or `"opt-out"` for external library usage |
379
434
  | `external_allow` | Allowed external packages (when `external_mode = "opt-in"`) |
380
435
  | `external_deny` | Forbidden external packages (when `external_mode = "opt-out"`) |
436
+ | `name_deny` | Forbidden keywords for naming convention check (case-insensitive partial match) |
437
+ | `name_allow` | Substrings to strip before `name_deny` check (e.g. `"category"` prevents `"go"` match inside it) |
438
+ | `name_targets` | Targets to check: `"file"`, `"symbol"`, `"variable"`, `"comment"` (default: all) |
439
+ | `name_deny_ignore` | Glob patterns for files to exclude from naming checks (e.g. `"**/test_*.rs"`) |
440
+
441
+ #### Naming Convention Check (`name_deny`)
442
+
443
+ Forbid infrastructure-specific keywords from appearing in a layer's names.
444
+
445
+ ```toml
446
+ [[layers]]
447
+ name = "usecase"
448
+ paths = ["src/usecase/**"]
449
+ dependency_mode = "opt-out"
450
+ deny = []
451
+ external_mode = "opt-out"
452
+ external_deny = []
453
+
454
+ # Usecase layer must not reference specific infrastructure technologies
455
+ name_deny = ["gcp", "aws", "azure", "mysql", "postgres"]
456
+ name_allow = ["category"] # "category" contains "go" but should not be flagged
457
+ name_targets = ["file", "symbol", "variable", "comment"] # default: all targets
458
+ name_deny_ignore = ["**/test_*.rs", "tests/**"] # exclude test files from naming checks
459
+ ```
460
+
461
+ **Rules:**
462
+ - Case-insensitive (`GCP` = `gcp` = `Gcp`)
463
+ - Partial match (`ManageGcp` also matches `gcp`)
464
+ - `name_allow` strips listed substrings before matching (e.g. `"category"` prevents false positive on `"go"`)
465
+ - `name_deny_ignore` excludes files matching glob patterns from naming checks entirely
466
+ - `name_targets` restricts which entity types are checked:
467
+ - `"file"`: file basename (e.g. `aws_client.rs`)
468
+ - `"symbol"`: function, class, struct, enum, trait, interface, type alias names
469
+ - `"variable"`: variable, const, let, static declaration names
470
+ - `"comment"`: inline comment content
471
+ - Supported languages: Rust, TypeScript, JavaScript, Python, Go, Java, Kotlin, PHP
472
+ - Severity is controlled by `severity.naming_violation` (default: `"error"`)
381
473
 
382
474
  ### `[[layers.allow_call_patterns]]`
383
475
 
@@ -418,6 +510,7 @@ Control the severity level of each violation type. Violations can be `"error"`,
418
510
  | `external_violation` | `"error"` | External library rule violated |
419
511
  | `call_pattern_violation` | `"error"` | DI entrypoint method call rule violated |
420
512
  | `unknown_import` | `"warning"` | Import that could not be classified |
513
+ | `naming_violation` | `"error"` | Naming convention rule violated (`name_deny`) |
421
514
 
422
515
  ```toml
423
516
  [severity]
@@ -425,6 +518,7 @@ dependency_violation = "warning" # treat as warning for gradual adoption
425
518
  external_violation = "error"
426
519
  call_pattern_violation = "error"
427
520
  unknown_import = "warning"
521
+ naming_violation = "warning" # treat as warning while rolling out naming rules
428
522
  ```
429
523
 
430
524
  Use `--fail-on warning` to exit 1 even for warnings when integrating into CI gradually.
@@ -466,6 +560,72 @@ Use `--fail-on warning` to exit 1 even for warnings when integrating into CI gra
466
560
  | `import domain.entity` (matches `package_names`) | Internal |
467
561
  | `import os`, `import sqlalchemy` | External |
468
562
 
563
+ ### `[resolve.java]`
564
+
565
+ | Key | Description |
566
+ |---|---|
567
+ | `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`. |
568
+ | `pom_xml` | Path to `pom.xml` (relative to `mille.toml`). `groupId.artifactId` is used as `module_name` when `module_name` is not set. |
569
+ | `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. |
570
+
571
+ **How Java imports are classified:**
572
+
573
+ | Import | Classification |
574
+ |---|---|
575
+ | `import com.example.myapp.domain.User` (starts with `module_name`) | Internal |
576
+ | `import static com.example.myapp.util.Helper.method` | Internal |
577
+ | `import java.util.List`, `import org.springframework.*` | External |
578
+
579
+ > Both regular and static imports are supported. Wildcard imports (`import java.util.*`) are not yet extracted by the parser.
580
+
581
+ ### `[resolve.php]`
582
+
583
+ | Key | Description |
584
+ |---|---|
585
+ | `namespace` | Base namespace of your project (e.g. `App`). Imports starting with this prefix are classified as Internal. |
586
+ | `composer_json` | Path to `composer.json` (relative to `mille.toml`). The first PSR-4 key in `autoload.psr-4` is used as the base namespace when `namespace` is not set. |
587
+
588
+ **How PHP imports are classified:**
589
+
590
+ | Import | Classification |
591
+ |---|---|
592
+ | `use App\Models\User` (starts with `namespace`) | Internal |
593
+ | `use App\Services\{Auth, Logger}` (group use, expanded) | Internal |
594
+ | `use function App\Helpers\format_date` | Internal |
595
+ | `use DateTime`, `use PDO`, `use Exception` | Stdlib |
596
+ | `use Illuminate\Http\Request` | External |
597
+
598
+ > Supported use forms: simple, aliased (`as`), grouped (`{}`), `use function`, `use const`.
599
+ > PHP stdlib classes (DateTime, PDO, Exception, etc.) are automatically classified as Stdlib without any configuration.
600
+
601
+ **Example `mille.toml` for a Laravel project:**
602
+
603
+ ```toml
604
+ [project]
605
+ name = "my-laravel-app"
606
+ root = "."
607
+ languages = ["php"]
608
+
609
+ [[layers]]
610
+ name = "domain"
611
+ paths = ["app/Domain/**"]
612
+
613
+ [[layers]]
614
+ name = "application"
615
+ paths = ["app/Application/**"]
616
+ dependency_mode = "opt-in"
617
+ allow = ["domain"]
618
+
619
+ [[layers]]
620
+ name = "infrastructure"
621
+ paths = ["app/Infrastructure/**"]
622
+ dependency_mode = "opt-in"
623
+ allow = ["domain", "application"]
624
+
625
+ [resolve.php]
626
+ composer_json = "composer.json" # auto-detects "App\\" from autoload.psr-4
627
+ ```
628
+
469
629
  ## How it Works
470
630
 
471
631
  mille uses [tree-sitter](https://tree-sitter.github.io/) for AST-based import extraction — no regex heuristics.
@@ -476,7 +636,7 @@ mille.toml
476
636
 
477
637
  Layer definitions
478
638
 
479
- Source files (*.rs, *.go, *.py, *.ts, *.js, ...)
639
+ Source files (*.rs, *.go, *.py, *.ts, *.js, *.java, ...)
480
640
  │ tree-sitter parse
481
641
 
482
642
  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.11",
3
+ "version": "0.0.13",
4
4
  "description": "Architecture Checker — Rust-based multi-language architecture linter",
5
5
  "main": "index.js",
6
6
  "bin": {