vite-plugin-app-boundaries 0.1.0
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 +240 -0
- package/dist/index.cjs +69 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.mjs +41 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# vite-plugin-app-boundaries
|
|
2
|
+
|
|
3
|
+
Enforce **strict architectural boundaries** between application folders
|
|
4
|
+
in Vite.
|
|
5
|
+
|
|
6
|
+
This plugin prevents one app (e.g. `Front`) from importing code from
|
|
7
|
+
another app (e.g. `Pro`) at **build time and dev time**, not just via
|
|
8
|
+
linting.
|
|
9
|
+
|
|
10
|
+
If a boundary is violated, **Vite errors immediately**.
|
|
11
|
+
|
|
12
|
+
------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
## Why this exists
|
|
15
|
+
|
|
16
|
+
Lint rules are easy to bypass. Aliases hide real paths. Large multi-front apps rot over time.
|
|
17
|
+
|
|
18
|
+
This plugin makes architecture **non-negotiable** by enforcing rules
|
|
19
|
+
directly in Vite's module resolution graph.
|
|
20
|
+
|
|
21
|
+
------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- ✅ Enforce boundaries between **any number of apps**
|
|
26
|
+
- ✅ Errors in **dev AND build**
|
|
27
|
+
- ✅ Alias-aware (uses Vite's resolver)
|
|
28
|
+
- ✅ Configurable allowlists
|
|
29
|
+
- ✅ Zero runtime cost
|
|
30
|
+
- ✅ Works with Vite 5 / 6 / 7
|
|
31
|
+
|
|
32
|
+
------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
## Example use case
|
|
35
|
+
|
|
36
|
+
``` txt
|
|
37
|
+
resources/js/Apps/
|
|
38
|
+
├── Front/
|
|
39
|
+
├── Pro/
|
|
40
|
+
└── Shared/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Rules:
|
|
44
|
+
- ❌ `Front` cannot import from `Pro`
|
|
45
|
+
- ❌ `Pro` cannot import from `Front`
|
|
46
|
+
- ✅ Both can import from `Shared`
|
|
47
|
+
|
|
48
|
+
------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
``` bash
|
|
53
|
+
npm install -D vite-plugin-app-boundaries
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
or
|
|
57
|
+
|
|
58
|
+
``` bash
|
|
59
|
+
pnpm add -D vite-plugin-app-boundaries
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
## Basic usage
|
|
65
|
+
|
|
66
|
+
### `vite.config.ts`
|
|
67
|
+
|
|
68
|
+
``` ts
|
|
69
|
+
import { defineConfig } from "vite";
|
|
70
|
+
import react from "@vitejs/plugin-react";
|
|
71
|
+
import { enforceAppBoundaries } from "vite-plugin-app-boundaries";
|
|
72
|
+
|
|
73
|
+
export default defineConfig({
|
|
74
|
+
plugins: [
|
|
75
|
+
enforceAppBoundaries({
|
|
76
|
+
root: "resources/js/Apps",
|
|
77
|
+
|
|
78
|
+
apps: {
|
|
79
|
+
Front: {
|
|
80
|
+
path: "Front",
|
|
81
|
+
allowImportsFrom: ["Shared"],
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
Pro: {
|
|
85
|
+
path: "Pro",
|
|
86
|
+
allowImportsFrom: ["Shared"],
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
Shared: {
|
|
90
|
+
path: "Shared",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
|
|
95
|
+
react(),
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
## What happens on violation
|
|
103
|
+
|
|
104
|
+
``` ts
|
|
105
|
+
// Apps/Front/pages/welcome.tsx
|
|
106
|
+
import Editor from "@/Apps/Pro/components/editorjs";
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
⬇️
|
|
110
|
+
|
|
111
|
+
``` txt
|
|
112
|
+
🚫 App boundary violation
|
|
113
|
+
|
|
114
|
+
Importer:
|
|
115
|
+
.../Apps/Front/pages/welcome.tsx
|
|
116
|
+
(app: Front)
|
|
117
|
+
|
|
118
|
+
Imported:
|
|
119
|
+
.../Apps/Pro/components/editorjs.tsx
|
|
120
|
+
(app: Pro)
|
|
121
|
+
|
|
122
|
+
Allowed imports for Front:
|
|
123
|
+
Shared
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Vite stops immediately.
|
|
127
|
+
|
|
128
|
+
------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
## Configuration reference
|
|
131
|
+
|
|
132
|
+
### `root`
|
|
133
|
+
|
|
134
|
+
Root directory that contains all apps.
|
|
135
|
+
|
|
136
|
+
``` ts
|
|
137
|
+
root: "resources/js/Apps"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
### `apps`
|
|
143
|
+
|
|
144
|
+
Each app has:
|
|
145
|
+
|
|
146
|
+
- `path`: folder name under `root`
|
|
147
|
+
- `allowImportsFrom`: optional list of app names it may import from
|
|
148
|
+
|
|
149
|
+
``` ts
|
|
150
|
+
apps: {
|
|
151
|
+
Front: {
|
|
152
|
+
path: "Front",
|
|
153
|
+
allowImportsFrom: ["Shared"],
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
Admin: {
|
|
157
|
+
path: "Admin",
|
|
158
|
+
allowImportsFrom: ["Shared", "Pro"],
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
### `debug` (optional)
|
|
166
|
+
|
|
167
|
+
Enable verbose logging to see exactly how Vite resolves imports.
|
|
168
|
+
|
|
169
|
+
``` ts
|
|
170
|
+
enforceAppBoundaries({
|
|
171
|
+
debug: true,
|
|
172
|
+
...
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Useful when diagnosing aliases or unexpected resolution.
|
|
177
|
+
|
|
178
|
+
------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
## ESLint mirror rules (recommended)
|
|
181
|
+
|
|
182
|
+
This plugin enforces boundaries at **build time**.\
|
|
183
|
+
For **editor errors**, mirror the rules using ESLint.
|
|
184
|
+
|
|
185
|
+
### Install
|
|
186
|
+
|
|
187
|
+
``` bash
|
|
188
|
+
npm install -D eslint-plugin-boundaries
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Example `.eslintrc.cjs`
|
|
192
|
+
|
|
193
|
+
``` js
|
|
194
|
+
module.exports = {
|
|
195
|
+
plugins: ["boundaries"],
|
|
196
|
+
|
|
197
|
+
settings: {
|
|
198
|
+
"boundaries/include": ["resources/js/**/*"],
|
|
199
|
+
|
|
200
|
+
"boundaries/elements": [
|
|
201
|
+
{ type: "front", pattern: "resources/js/Apps/Front/**" },
|
|
202
|
+
{ type: "pro", pattern: "resources/js/Apps/Pro/**" },
|
|
203
|
+
{ type: "shared", pattern: "resources/js/Apps/Shared/**" },
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
rules: {
|
|
208
|
+
"boundaries/element-types": [
|
|
209
|
+
"error",
|
|
210
|
+
{
|
|
211
|
+
default: "disallow",
|
|
212
|
+
rules: [
|
|
213
|
+
{ from: "front", allow: ["shared"] },
|
|
214
|
+
{ from: "pro", allow: ["shared"] },
|
|
215
|
+
{ from: "shared", allow: ["shared"] },
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
## What this plugin does NOT do
|
|
226
|
+
|
|
227
|
+
- ❌ It does not replace ESLint
|
|
228
|
+
- ❌ It does not rewrite imports
|
|
229
|
+
- ❌ It does not enforce runtime isolation
|
|
230
|
+
|
|
231
|
+
Recommended setup:
|
|
232
|
+
|
|
233
|
+
- **This plugin** → build-time enforcement
|
|
234
|
+
- **ESLint boundaries rules** → editor feedback
|
|
235
|
+
|
|
236
|
+
------------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
let node_path = require("node:path");
|
|
29
|
+
node_path = __toESM(node_path);
|
|
30
|
+
|
|
31
|
+
//#region src/plugin.ts
|
|
32
|
+
function normalize(p) {
|
|
33
|
+
return p.split(node_path.default.sep).join("/");
|
|
34
|
+
}
|
|
35
|
+
function enforceAppBoundaries(options) {
|
|
36
|
+
const root = normalize(node_path.default.resolve(options.root));
|
|
37
|
+
const apps = Object.entries(options.apps).map(([name, cfg]) => ({
|
|
38
|
+
name,
|
|
39
|
+
root: normalize(node_path.default.join(root, cfg.path)),
|
|
40
|
+
allow: new Set(cfg.allowImportsFrom ?? [])
|
|
41
|
+
}));
|
|
42
|
+
function findApp(file) {
|
|
43
|
+
return apps.find((app) => file.startsWith(app.root));
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
name: "vite-plugin-app-boundaries",
|
|
47
|
+
enforce: "pre",
|
|
48
|
+
async resolveId(source, importer) {
|
|
49
|
+
if (!importer) return null;
|
|
50
|
+
const importerPath = normalize(importer);
|
|
51
|
+
if (!importerPath.startsWith(root)) return null;
|
|
52
|
+
const importerApp = findApp(importerPath);
|
|
53
|
+
if (!importerApp) return null;
|
|
54
|
+
const resolved = await this.resolve(source, importer, { skipSelf: true });
|
|
55
|
+
if (!resolved) return null;
|
|
56
|
+
const resolvedPath = normalize(resolved.id);
|
|
57
|
+
if (!resolvedPath.startsWith(root)) return null;
|
|
58
|
+
const importedApp = findApp(resolvedPath);
|
|
59
|
+
if (!importedApp) return null;
|
|
60
|
+
if (importedApp.name === importerApp.name) return null;
|
|
61
|
+
if (importerApp.allow.has(importedApp.name)) return null;
|
|
62
|
+
throw new Error(`🚫 App boundary violation\n\n${importerPath}\n→ ${resolvedPath}`);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
exports.enforceAppBoundaries = enforceAppBoundaries;
|
|
69
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["path"],"sources":["../src/plugin.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { Plugin } from \"vite\";\nimport type { AppBoundariesOptions } from \"./types\";\n\nfunction normalize(p: string) {\n return p.split(path.sep).join(\"/\");\n}\n\nexport function enforceAppBoundaries(\n options: AppBoundariesOptions\n): Plugin {\n const root = normalize(path.resolve(options.root));\n\n const apps = Object.entries(options.apps).map(\n ([name, cfg]) => ({\n name,\n root: normalize(path.join(root, cfg.path)),\n allow: new Set(cfg.allowImportsFrom ?? []),\n })\n );\n\n function findApp(file: string) {\n return apps.find(app => file.startsWith(app.root));\n }\n\n function log(...args: any[]) {\n if (options.debug) {\n console.log(\"[vite-app-boundaries]\", ...args);\n }\n }\n\n return {\n name: \"vite-plugin-app-boundaries\",\n enforce: \"pre\",\n\n async resolveId(source, importer) {\n if (!importer) return null;\n\n const importerPath = normalize(importer);\n if (!importerPath.startsWith(root)) return null;\n\n const importerApp = findApp(importerPath);\n if (!importerApp) return null;\n\n const resolved = await this.resolve(source, importer, {\n skipSelf: true,\n });\n\n if (!resolved) return null;\n\n const resolvedPath = normalize(resolved.id);\n if (!resolvedPath.startsWith(root)) return null;\n\n const importedApp = findApp(resolvedPath);\n if (!importedApp) return null;\n\n if (importedApp.name === importerApp.name) return null;\n if (importerApp.allow.has(importedApp.name)) return null;\n\n throw new Error(\n `🚫 App boundary violation\\n\\n${importerPath}\\n→ ${resolvedPath}`\n );\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAAS,UAAU,GAAW;AAC5B,QAAO,EAAE,MAAMA,kBAAK,IAAI,CAAC,KAAK,IAAI;;AAGpC,SAAgB,qBACd,SACQ;CACR,MAAM,OAAO,UAAUA,kBAAK,QAAQ,QAAQ,KAAK,CAAC;CAElD,MAAM,OAAO,OAAO,QAAQ,QAAQ,KAAK,CAAC,KACvC,CAAC,MAAM,UAAU;EAChB;EACA,MAAM,UAAUA,kBAAK,KAAK,MAAM,IAAI,KAAK,CAAC;EAC1C,OAAO,IAAI,IAAI,IAAI,oBAAoB,EAAE,CAAC;EAC3C,EACF;CAED,SAAS,QAAQ,MAAc;AAC7B,SAAO,KAAK,MAAK,QAAO,KAAK,WAAW,IAAI,KAAK,CAAC;;AASpD,QAAO;EACL,MAAM;EACN,SAAS;EAET,MAAM,UAAU,QAAQ,UAAU;AAChC,OAAI,CAAC,SAAU,QAAO;GAEtB,MAAM,eAAe,UAAU,SAAS;AACxC,OAAI,CAAC,aAAa,WAAW,KAAK,CAAE,QAAO;GAE3C,MAAM,cAAc,QAAQ,aAAa;AACzC,OAAI,CAAC,YAAa,QAAO;GAEzB,MAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,UAAU,EACpD,UAAU,MACX,CAAC;AAEF,OAAI,CAAC,SAAU,QAAO;GAEtB,MAAM,eAAe,UAAU,SAAS,GAAG;AAC3C,OAAI,CAAC,aAAa,WAAW,KAAK,CAAE,QAAO;GAE3C,MAAM,cAAc,QAAQ,aAAa;AACzC,OAAI,CAAC,YAAa,QAAO;AAEzB,OAAI,YAAY,SAAS,YAAY,KAAM,QAAO;AAClD,OAAI,YAAY,MAAM,IAAI,YAAY,KAAK,CAAE,QAAO;AAEpD,SAAM,IAAI,MACR,gCAAgC,aAAa,MAAM,eACpD;;EAEJ"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type AppConfig = {
|
|
5
|
+
path: string;
|
|
6
|
+
allowImportsFrom?: string[];
|
|
7
|
+
};
|
|
8
|
+
type AppBoundariesOptions = {
|
|
9
|
+
root: string;
|
|
10
|
+
apps: Record<string, AppConfig>;
|
|
11
|
+
debug?: boolean;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/plugin.d.ts
|
|
15
|
+
declare function enforceAppBoundaries(options: AppBoundariesOptions): Plugin;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { type AppBoundariesOptions, type AppConfig, enforceAppBoundaries };
|
|
18
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type AppConfig = {
|
|
5
|
+
path: string;
|
|
6
|
+
allowImportsFrom?: string[];
|
|
7
|
+
};
|
|
8
|
+
type AppBoundariesOptions = {
|
|
9
|
+
root: string;
|
|
10
|
+
apps: Record<string, AppConfig>;
|
|
11
|
+
debug?: boolean;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/plugin.d.ts
|
|
15
|
+
declare function enforceAppBoundaries(options: AppBoundariesOptions): Plugin;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { type AppBoundariesOptions, type AppConfig, enforceAppBoundaries };
|
|
18
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/plugin.ts
|
|
4
|
+
function normalize(p) {
|
|
5
|
+
return p.split(path.sep).join("/");
|
|
6
|
+
}
|
|
7
|
+
function enforceAppBoundaries(options) {
|
|
8
|
+
const root = normalize(path.resolve(options.root));
|
|
9
|
+
const apps = Object.entries(options.apps).map(([name, cfg]) => ({
|
|
10
|
+
name,
|
|
11
|
+
root: normalize(path.join(root, cfg.path)),
|
|
12
|
+
allow: new Set(cfg.allowImportsFrom ?? [])
|
|
13
|
+
}));
|
|
14
|
+
function findApp(file) {
|
|
15
|
+
return apps.find((app) => file.startsWith(app.root));
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name: "vite-plugin-app-boundaries",
|
|
19
|
+
enforce: "pre",
|
|
20
|
+
async resolveId(source, importer) {
|
|
21
|
+
if (!importer) return null;
|
|
22
|
+
const importerPath = normalize(importer);
|
|
23
|
+
if (!importerPath.startsWith(root)) return null;
|
|
24
|
+
const importerApp = findApp(importerPath);
|
|
25
|
+
if (!importerApp) return null;
|
|
26
|
+
const resolved = await this.resolve(source, importer, { skipSelf: true });
|
|
27
|
+
if (!resolved) return null;
|
|
28
|
+
const resolvedPath = normalize(resolved.id);
|
|
29
|
+
if (!resolvedPath.startsWith(root)) return null;
|
|
30
|
+
const importedApp = findApp(resolvedPath);
|
|
31
|
+
if (!importedApp) return null;
|
|
32
|
+
if (importedApp.name === importerApp.name) return null;
|
|
33
|
+
if (importerApp.allow.has(importedApp.name)) return null;
|
|
34
|
+
throw new Error(`🚫 App boundary violation\n\n${importerPath}\n→ ${resolvedPath}`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { enforceAppBoundaries };
|
|
41
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { Plugin } from \"vite\";\nimport type { AppBoundariesOptions } from \"./types\";\n\nfunction normalize(p: string) {\n return p.split(path.sep).join(\"/\");\n}\n\nexport function enforceAppBoundaries(\n options: AppBoundariesOptions\n): Plugin {\n const root = normalize(path.resolve(options.root));\n\n const apps = Object.entries(options.apps).map(\n ([name, cfg]) => ({\n name,\n root: normalize(path.join(root, cfg.path)),\n allow: new Set(cfg.allowImportsFrom ?? []),\n })\n );\n\n function findApp(file: string) {\n return apps.find(app => file.startsWith(app.root));\n }\n\n function log(...args: any[]) {\n if (options.debug) {\n console.log(\"[vite-app-boundaries]\", ...args);\n }\n }\n\n return {\n name: \"vite-plugin-app-boundaries\",\n enforce: \"pre\",\n\n async resolveId(source, importer) {\n if (!importer) return null;\n\n const importerPath = normalize(importer);\n if (!importerPath.startsWith(root)) return null;\n\n const importerApp = findApp(importerPath);\n if (!importerApp) return null;\n\n const resolved = await this.resolve(source, importer, {\n skipSelf: true,\n });\n\n if (!resolved) return null;\n\n const resolvedPath = normalize(resolved.id);\n if (!resolvedPath.startsWith(root)) return null;\n\n const importedApp = findApp(resolvedPath);\n if (!importedApp) return null;\n\n if (importedApp.name === importerApp.name) return null;\n if (importerApp.allow.has(importedApp.name)) return null;\n\n throw new Error(\n `🚫 App boundary violation\\n\\n${importerPath}\\n→ ${resolvedPath}`\n );\n },\n };\n}\n"],"mappings":";;;AAIA,SAAS,UAAU,GAAW;AAC5B,QAAO,EAAE,MAAM,KAAK,IAAI,CAAC,KAAK,IAAI;;AAGpC,SAAgB,qBACd,SACQ;CACR,MAAM,OAAO,UAAU,KAAK,QAAQ,QAAQ,KAAK,CAAC;CAElD,MAAM,OAAO,OAAO,QAAQ,QAAQ,KAAK,CAAC,KACvC,CAAC,MAAM,UAAU;EAChB;EACA,MAAM,UAAU,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC;EAC1C,OAAO,IAAI,IAAI,IAAI,oBAAoB,EAAE,CAAC;EAC3C,EACF;CAED,SAAS,QAAQ,MAAc;AAC7B,SAAO,KAAK,MAAK,QAAO,KAAK,WAAW,IAAI,KAAK,CAAC;;AASpD,QAAO;EACL,MAAM;EACN,SAAS;EAET,MAAM,UAAU,QAAQ,UAAU;AAChC,OAAI,CAAC,SAAU,QAAO;GAEtB,MAAM,eAAe,UAAU,SAAS;AACxC,OAAI,CAAC,aAAa,WAAW,KAAK,CAAE,QAAO;GAE3C,MAAM,cAAc,QAAQ,aAAa;AACzC,OAAI,CAAC,YAAa,QAAO;GAEzB,MAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,UAAU,EACpD,UAAU,MACX,CAAC;AAEF,OAAI,CAAC,SAAU,QAAO;GAEtB,MAAM,eAAe,UAAU,SAAS,GAAG;AAC3C,OAAI,CAAC,aAAa,WAAW,KAAK,CAAE,QAAO;GAE3C,MAAM,cAAc,QAAQ,aAAa;AACzC,OAAI,CAAC,YAAa,QAAO;AAEzB,OAAI,YAAY,SAAS,YAAY,KAAM,QAAO;AAClD,OAAI,YAAY,MAAM,IAAI,YAAY,KAAK,CAAE,QAAO;AAEpD,SAAM,IAAI,MACR,gCAAgC,aAAa,MAAM,eACpD;;EAEJ"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-plugin-app-boundaries",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Enforce architectural boundaries between app folders in Vite",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsdown",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"prepublishOnly": "npm run test && npm run build"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"vite": ">=5"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.3.0",
|
|
22
|
+
"tsdown": "^0.19.0-beta.1",
|
|
23
|
+
"vitest": "^1.2.0",
|
|
24
|
+
"vite": "^7.0.0"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT"
|
|
27
|
+
}
|