directory-lint 2.0.1 → 2.0.3
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/dist/index.cjs +73 -24
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +73 -24
- package/package.json +38 -38
package/dist/index.cjs
CHANGED
|
@@ -91,32 +91,49 @@ var DirectoryLint = class {
|
|
|
91
91
|
cwd,
|
|
92
92
|
paths: {}
|
|
93
93
|
};
|
|
94
|
-
if (!this.backend.exists(cwd))
|
|
94
|
+
if (!this.backend.exists(cwd)) {
|
|
95
|
+
this.backend.makeDirectory(cwd, options?.recursive);
|
|
96
|
+
}
|
|
95
97
|
for (const [name, node] of Object.entries(schema)) {
|
|
96
98
|
const isRegexLiteral = name.startsWith("/") && name.endsWith("/");
|
|
97
99
|
if (isRegexLiteral) throw new RegexNotSupported(name);
|
|
98
100
|
const fullPath = (0, import_path.join)(cwd, name);
|
|
99
101
|
if (node.type === "directory") {
|
|
100
|
-
let childrenResult
|
|
102
|
+
let childrenResult;
|
|
101
103
|
if (!this.backend.exists(fullPath)) {
|
|
102
104
|
this.backend.makeDirectory(fullPath, options?.recursive);
|
|
103
105
|
}
|
|
104
106
|
if (node.children) {
|
|
105
|
-
childrenResult = await this.generate(
|
|
107
|
+
childrenResult = await this.generate(
|
|
108
|
+
fullPath,
|
|
109
|
+
node.children,
|
|
110
|
+
options
|
|
111
|
+
);
|
|
106
112
|
}
|
|
107
113
|
result.paths[name] = {
|
|
108
|
-
type:
|
|
114
|
+
type: "directory",
|
|
109
115
|
path: fullPath,
|
|
110
|
-
...childrenResult?.paths && {
|
|
116
|
+
...childrenResult?.paths && {
|
|
117
|
+
children: childrenResult.paths
|
|
118
|
+
}
|
|
111
119
|
};
|
|
112
|
-
}
|
|
120
|
+
}
|
|
121
|
+
if (node.type === "file") {
|
|
113
122
|
if (!this.backend.exists(fullPath)) {
|
|
114
|
-
this.backend.writeFile(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
this.backend.writeFile(
|
|
124
|
+
fullPath,
|
|
125
|
+
node.content ?? ""
|
|
126
|
+
);
|
|
127
|
+
} else if (options?.overwrite) {
|
|
128
|
+
this.backend.writeFile(
|
|
129
|
+
fullPath,
|
|
130
|
+
node.content ?? ""
|
|
131
|
+
);
|
|
119
132
|
}
|
|
133
|
+
result.paths[name] = {
|
|
134
|
+
type: "file",
|
|
135
|
+
path: fullPath
|
|
136
|
+
};
|
|
120
137
|
}
|
|
121
138
|
}
|
|
122
139
|
return result;
|
|
@@ -127,29 +144,61 @@ var DirectoryLint = class {
|
|
|
127
144
|
paths: {}
|
|
128
145
|
};
|
|
129
146
|
const items = this.backend.getAllItems(cwd);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
147
|
+
const processedNames = /* @__PURE__ */ new Set();
|
|
148
|
+
const sortedEntries = Object.entries(schema).sort(([a], [b]) => {
|
|
149
|
+
const aHasWildcard = String(a).includes("*");
|
|
150
|
+
const bHasWildcard = String(b).includes("*");
|
|
151
|
+
if (!aHasWildcard && bHasWildcard) return -1;
|
|
152
|
+
if (aHasWildcard && !bHasWildcard) return 1;
|
|
153
|
+
return 0;
|
|
154
|
+
});
|
|
155
|
+
for (const [pattern, node] of sortedEntries) {
|
|
156
|
+
const regex = this.patternToRegex(String(pattern));
|
|
157
|
+
const matchedItems = items.filter(
|
|
158
|
+
(item) => regex.test(item.name) && !processedNames.has(item.name)
|
|
159
|
+
);
|
|
160
|
+
const isRequired = node.required ?? true;
|
|
161
|
+
if (matchedItems.length === 0 && isRequired) {
|
|
162
|
+
throw new InvalidStructure(String(pattern));
|
|
163
|
+
}
|
|
134
164
|
for (const { name, type } of matchedItems) {
|
|
135
165
|
if (options?.ignore.includes(name)) continue;
|
|
166
|
+
processedNames.add(name);
|
|
136
167
|
const fullPath = (0, import_path.join)(cwd, name);
|
|
137
168
|
if (node.type === "directory") {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
169
|
+
if (type !== "directory") {
|
|
170
|
+
throw new InvalidStructure(fullPath);
|
|
171
|
+
}
|
|
172
|
+
let childrenResult;
|
|
173
|
+
if (node.children) {
|
|
174
|
+
childrenResult = await this.validate(
|
|
175
|
+
fullPath,
|
|
176
|
+
node.children,
|
|
177
|
+
options
|
|
178
|
+
);
|
|
142
179
|
}
|
|
143
180
|
result.paths[name] = {
|
|
144
181
|
path: fullPath,
|
|
145
182
|
name,
|
|
146
|
-
type:
|
|
147
|
-
...childrenResult?.paths && {
|
|
183
|
+
type: "directory",
|
|
184
|
+
...childrenResult?.paths && {
|
|
185
|
+
children: childrenResult.paths
|
|
186
|
+
}
|
|
148
187
|
};
|
|
149
|
-
}
|
|
150
|
-
|
|
188
|
+
}
|
|
189
|
+
if (node.type === "file") {
|
|
190
|
+
if (type !== "file") {
|
|
191
|
+
throw new InvalidStructure(fullPath);
|
|
192
|
+
}
|
|
151
193
|
const content = this.backend.readFile(fullPath);
|
|
152
|
-
if (node.validate
|
|
194
|
+
if (node.validate && !node.validate(content)) {
|
|
195
|
+
throw new InvalidContent(fullPath);
|
|
196
|
+
}
|
|
197
|
+
result.paths[name] = {
|
|
198
|
+
path: fullPath,
|
|
199
|
+
name,
|
|
200
|
+
type: "file"
|
|
201
|
+
};
|
|
153
202
|
}
|
|
154
203
|
}
|
|
155
204
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -44,6 +44,16 @@ interface LintBackend {
|
|
|
44
44
|
exists(path: string): boolean;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
type MapValidateSchema<T> = {
|
|
48
|
+
[K in keyof T]: T[K] extends {
|
|
49
|
+
type: "file";
|
|
50
|
+
} ? ValidateFileResult : T[K] extends {
|
|
51
|
+
type: "directory";
|
|
52
|
+
children?: infer C;
|
|
53
|
+
} ? ValidateDirectoryResult & {
|
|
54
|
+
children: C extends object ? MapValidateSchema<C> : undefined;
|
|
55
|
+
} : never;
|
|
56
|
+
};
|
|
47
57
|
interface GenerateOptions {
|
|
48
58
|
overwrite?: boolean;
|
|
49
59
|
recursive?: boolean;
|
|
@@ -64,9 +74,9 @@ interface ValidateDirectoryResult {
|
|
|
64
74
|
}
|
|
65
75
|
type ValidateNodeResult = ValidateFileResult | ValidateDirectoryResult;
|
|
66
76
|
type ValidatePathResult = Record<string, ValidateNodeResult>;
|
|
67
|
-
interface ValidateResult {
|
|
77
|
+
interface ValidateResult<TSchema> {
|
|
68
78
|
cwd: string;
|
|
69
|
-
paths:
|
|
79
|
+
paths: MapValidateSchema<TSchema>;
|
|
70
80
|
}
|
|
71
81
|
interface GenerateFileResult {
|
|
72
82
|
type: "file";
|
|
@@ -88,7 +98,7 @@ declare class DirectoryLint {
|
|
|
88
98
|
private readonly backend;
|
|
89
99
|
constructor(backend?: LintBackend);
|
|
90
100
|
generate(cwd: string, schema: GenerateSchema, options?: GenerateOptions): Promise<GenerateResult>;
|
|
91
|
-
validate(cwd: string, schema:
|
|
101
|
+
validate<TSchema extends ValidateSchema>(cwd: string, schema: TSchema, options?: ValidateOptions): Promise<ValidateResult<TSchema>>;
|
|
92
102
|
private patternToRegex;
|
|
93
103
|
}
|
|
94
104
|
|
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,16 @@ interface LintBackend {
|
|
|
44
44
|
exists(path: string): boolean;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
type MapValidateSchema<T> = {
|
|
48
|
+
[K in keyof T]: T[K] extends {
|
|
49
|
+
type: "file";
|
|
50
|
+
} ? ValidateFileResult : T[K] extends {
|
|
51
|
+
type: "directory";
|
|
52
|
+
children?: infer C;
|
|
53
|
+
} ? ValidateDirectoryResult & {
|
|
54
|
+
children: C extends object ? MapValidateSchema<C> : undefined;
|
|
55
|
+
} : never;
|
|
56
|
+
};
|
|
47
57
|
interface GenerateOptions {
|
|
48
58
|
overwrite?: boolean;
|
|
49
59
|
recursive?: boolean;
|
|
@@ -64,9 +74,9 @@ interface ValidateDirectoryResult {
|
|
|
64
74
|
}
|
|
65
75
|
type ValidateNodeResult = ValidateFileResult | ValidateDirectoryResult;
|
|
66
76
|
type ValidatePathResult = Record<string, ValidateNodeResult>;
|
|
67
|
-
interface ValidateResult {
|
|
77
|
+
interface ValidateResult<TSchema> {
|
|
68
78
|
cwd: string;
|
|
69
|
-
paths:
|
|
79
|
+
paths: MapValidateSchema<TSchema>;
|
|
70
80
|
}
|
|
71
81
|
interface GenerateFileResult {
|
|
72
82
|
type: "file";
|
|
@@ -88,7 +98,7 @@ declare class DirectoryLint {
|
|
|
88
98
|
private readonly backend;
|
|
89
99
|
constructor(backend?: LintBackend);
|
|
90
100
|
generate(cwd: string, schema: GenerateSchema, options?: GenerateOptions): Promise<GenerateResult>;
|
|
91
|
-
validate(cwd: string, schema:
|
|
101
|
+
validate<TSchema extends ValidateSchema>(cwd: string, schema: TSchema, options?: ValidateOptions): Promise<ValidateResult<TSchema>>;
|
|
92
102
|
private patternToRegex;
|
|
93
103
|
}
|
|
94
104
|
|
package/dist/index.js
CHANGED
|
@@ -51,32 +51,49 @@ var DirectoryLint = class {
|
|
|
51
51
|
cwd,
|
|
52
52
|
paths: {}
|
|
53
53
|
};
|
|
54
|
-
if (!this.backend.exists(cwd))
|
|
54
|
+
if (!this.backend.exists(cwd)) {
|
|
55
|
+
this.backend.makeDirectory(cwd, options?.recursive);
|
|
56
|
+
}
|
|
55
57
|
for (const [name, node] of Object.entries(schema)) {
|
|
56
58
|
const isRegexLiteral = name.startsWith("/") && name.endsWith("/");
|
|
57
59
|
if (isRegexLiteral) throw new RegexNotSupported(name);
|
|
58
60
|
const fullPath = join(cwd, name);
|
|
59
61
|
if (node.type === "directory") {
|
|
60
|
-
let childrenResult
|
|
62
|
+
let childrenResult;
|
|
61
63
|
if (!this.backend.exists(fullPath)) {
|
|
62
64
|
this.backend.makeDirectory(fullPath, options?.recursive);
|
|
63
65
|
}
|
|
64
66
|
if (node.children) {
|
|
65
|
-
childrenResult = await this.generate(
|
|
67
|
+
childrenResult = await this.generate(
|
|
68
|
+
fullPath,
|
|
69
|
+
node.children,
|
|
70
|
+
options
|
|
71
|
+
);
|
|
66
72
|
}
|
|
67
73
|
result.paths[name] = {
|
|
68
|
-
type:
|
|
74
|
+
type: "directory",
|
|
69
75
|
path: fullPath,
|
|
70
|
-
...childrenResult?.paths && {
|
|
76
|
+
...childrenResult?.paths && {
|
|
77
|
+
children: childrenResult.paths
|
|
78
|
+
}
|
|
71
79
|
};
|
|
72
|
-
}
|
|
80
|
+
}
|
|
81
|
+
if (node.type === "file") {
|
|
73
82
|
if (!this.backend.exists(fullPath)) {
|
|
74
|
-
this.backend.writeFile(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
this.backend.writeFile(
|
|
84
|
+
fullPath,
|
|
85
|
+
node.content ?? ""
|
|
86
|
+
);
|
|
87
|
+
} else if (options?.overwrite) {
|
|
88
|
+
this.backend.writeFile(
|
|
89
|
+
fullPath,
|
|
90
|
+
node.content ?? ""
|
|
91
|
+
);
|
|
79
92
|
}
|
|
93
|
+
result.paths[name] = {
|
|
94
|
+
type: "file",
|
|
95
|
+
path: fullPath
|
|
96
|
+
};
|
|
80
97
|
}
|
|
81
98
|
}
|
|
82
99
|
return result;
|
|
@@ -87,29 +104,61 @@ var DirectoryLint = class {
|
|
|
87
104
|
paths: {}
|
|
88
105
|
};
|
|
89
106
|
const items = this.backend.getAllItems(cwd);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
107
|
+
const processedNames = /* @__PURE__ */ new Set();
|
|
108
|
+
const sortedEntries = Object.entries(schema).sort(([a], [b]) => {
|
|
109
|
+
const aHasWildcard = String(a).includes("*");
|
|
110
|
+
const bHasWildcard = String(b).includes("*");
|
|
111
|
+
if (!aHasWildcard && bHasWildcard) return -1;
|
|
112
|
+
if (aHasWildcard && !bHasWildcard) return 1;
|
|
113
|
+
return 0;
|
|
114
|
+
});
|
|
115
|
+
for (const [pattern, node] of sortedEntries) {
|
|
116
|
+
const regex = this.patternToRegex(String(pattern));
|
|
117
|
+
const matchedItems = items.filter(
|
|
118
|
+
(item) => regex.test(item.name) && !processedNames.has(item.name)
|
|
119
|
+
);
|
|
120
|
+
const isRequired = node.required ?? true;
|
|
121
|
+
if (matchedItems.length === 0 && isRequired) {
|
|
122
|
+
throw new InvalidStructure(String(pattern));
|
|
123
|
+
}
|
|
94
124
|
for (const { name, type } of matchedItems) {
|
|
95
125
|
if (options?.ignore.includes(name)) continue;
|
|
126
|
+
processedNames.add(name);
|
|
96
127
|
const fullPath = join(cwd, name);
|
|
97
128
|
if (node.type === "directory") {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
129
|
+
if (type !== "directory") {
|
|
130
|
+
throw new InvalidStructure(fullPath);
|
|
131
|
+
}
|
|
132
|
+
let childrenResult;
|
|
133
|
+
if (node.children) {
|
|
134
|
+
childrenResult = await this.validate(
|
|
135
|
+
fullPath,
|
|
136
|
+
node.children,
|
|
137
|
+
options
|
|
138
|
+
);
|
|
102
139
|
}
|
|
103
140
|
result.paths[name] = {
|
|
104
141
|
path: fullPath,
|
|
105
142
|
name,
|
|
106
|
-
type:
|
|
107
|
-
...childrenResult?.paths && {
|
|
143
|
+
type: "directory",
|
|
144
|
+
...childrenResult?.paths && {
|
|
145
|
+
children: childrenResult.paths
|
|
146
|
+
}
|
|
108
147
|
};
|
|
109
|
-
}
|
|
110
|
-
|
|
148
|
+
}
|
|
149
|
+
if (node.type === "file") {
|
|
150
|
+
if (type !== "file") {
|
|
151
|
+
throw new InvalidStructure(fullPath);
|
|
152
|
+
}
|
|
111
153
|
const content = this.backend.readFile(fullPath);
|
|
112
|
-
if (node.validate
|
|
154
|
+
if (node.validate && !node.validate(content)) {
|
|
155
|
+
throw new InvalidContent(fullPath);
|
|
156
|
+
}
|
|
157
|
+
result.paths[name] = {
|
|
158
|
+
path: fullPath,
|
|
159
|
+
name,
|
|
160
|
+
type: "file"
|
|
161
|
+
};
|
|
113
162
|
}
|
|
114
163
|
}
|
|
115
164
|
}
|
package/package.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "directory-lint",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "Directory Lint",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Henry Vilani",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"main": "./dist/index.js",
|
|
10
|
-
"exports": {
|
|
11
|
-
".": {
|
|
12
|
-
"types": "./dist/index.d.ts",
|
|
13
|
-
"import": "./dist/index.js",
|
|
14
|
-
"require": "./dist/index.cjs"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
-
"example:basic": "ts-node examples/basic-generation.ts"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"linter",
|
|
26
|
-
"validation",
|
|
27
|
-
"filesystem",
|
|
28
|
-
"directory-structure",
|
|
29
|
-
"architecture",
|
|
30
|
-
"lint"
|
|
31
|
-
],
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@types/node": "^25.2.0",
|
|
34
|
-
"ts-node": "^10.9.2",
|
|
35
|
-
"tsup": "^8.5.1",
|
|
36
|
-
"typescript": "^5.9.3"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "directory-lint",
|
|
3
|
+
"version": "2.0.3",
|
|
4
|
+
"description": "Directory Lint",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Henry Vilani",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"example:basic": "ts-node examples/basic-generation.ts"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"linter",
|
|
26
|
+
"validation",
|
|
27
|
+
"filesystem",
|
|
28
|
+
"directory-structure",
|
|
29
|
+
"architecture",
|
|
30
|
+
"lint"
|
|
31
|
+
],
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^25.2.0",
|
|
34
|
+
"ts-node": "^10.9.2",
|
|
35
|
+
"tsup": "^8.5.1",
|
|
36
|
+
"typescript": "^5.9.3"
|
|
37
|
+
}
|
|
38
|
+
}
|