@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.
- package/README.md +167 -7
- package/mille.wasm +0 -0
- 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
|