directory-lint 2.0.2 → 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 +52 -24
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +52 -24
- package/package.json +38 -38
package/dist/index.cjs
CHANGED
|
@@ -91,35 +91,48 @@ 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
|
}
|
|
120
133
|
result.paths[name] = {
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
type: "file",
|
|
135
|
+
path: fullPath
|
|
123
136
|
};
|
|
124
137
|
}
|
|
125
138
|
}
|
|
@@ -133,39 +146,54 @@ var DirectoryLint = class {
|
|
|
133
146
|
const items = this.backend.getAllItems(cwd);
|
|
134
147
|
const processedNames = /* @__PURE__ */ new Set();
|
|
135
148
|
const sortedEntries = Object.entries(schema).sort(([a], [b]) => {
|
|
136
|
-
const aHasWildcard = a.includes("*");
|
|
137
|
-
const bHasWildcard = b.includes("*");
|
|
149
|
+
const aHasWildcard = String(a).includes("*");
|
|
150
|
+
const bHasWildcard = String(b).includes("*");
|
|
138
151
|
if (!aHasWildcard && bHasWildcard) return -1;
|
|
139
152
|
if (aHasWildcard && !bHasWildcard) return 1;
|
|
140
153
|
return 0;
|
|
141
154
|
});
|
|
142
155
|
for (const [pattern, node] of sortedEntries) {
|
|
143
|
-
const regex = this.patternToRegex(pattern);
|
|
156
|
+
const regex = this.patternToRegex(String(pattern));
|
|
144
157
|
const matchedItems = items.filter(
|
|
145
158
|
(item) => regex.test(item.name) && !processedNames.has(item.name)
|
|
146
159
|
);
|
|
147
160
|
const isRequired = node.required ?? true;
|
|
148
|
-
if (matchedItems.length === 0 && isRequired)
|
|
161
|
+
if (matchedItems.length === 0 && isRequired) {
|
|
162
|
+
throw new InvalidStructure(String(pattern));
|
|
163
|
+
}
|
|
149
164
|
for (const { name, type } of matchedItems) {
|
|
150
165
|
if (options?.ignore.includes(name)) continue;
|
|
151
166
|
processedNames.add(name);
|
|
152
167
|
const fullPath = (0, import_path.join)(cwd, name);
|
|
153
168
|
if (node.type === "directory") {
|
|
154
|
-
if (type !== "directory")
|
|
155
|
-
|
|
169
|
+
if (type !== "directory") {
|
|
170
|
+
throw new InvalidStructure(fullPath);
|
|
171
|
+
}
|
|
172
|
+
let childrenResult;
|
|
156
173
|
if (node.children) {
|
|
157
|
-
childrenResult = await this.validate(
|
|
174
|
+
childrenResult = await this.validate(
|
|
175
|
+
fullPath,
|
|
176
|
+
node.children,
|
|
177
|
+
options
|
|
178
|
+
);
|
|
158
179
|
}
|
|
159
180
|
result.paths[name] = {
|
|
160
181
|
path: fullPath,
|
|
161
182
|
name,
|
|
162
183
|
type: "directory",
|
|
163
|
-
...childrenResult?.paths && {
|
|
184
|
+
...childrenResult?.paths && {
|
|
185
|
+
children: childrenResult.paths
|
|
186
|
+
}
|
|
164
187
|
};
|
|
165
|
-
}
|
|
166
|
-
|
|
188
|
+
}
|
|
189
|
+
if (node.type === "file") {
|
|
190
|
+
if (type !== "file") {
|
|
191
|
+
throw new InvalidStructure(fullPath);
|
|
192
|
+
}
|
|
167
193
|
const content = this.backend.readFile(fullPath);
|
|
168
|
-
if (node.validate
|
|
194
|
+
if (node.validate && !node.validate(content)) {
|
|
195
|
+
throw new InvalidContent(fullPath);
|
|
196
|
+
}
|
|
169
197
|
result.paths[name] = {
|
|
170
198
|
path: fullPath,
|
|
171
199
|
name,
|
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,35 +51,48 @@ 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
|
}
|
|
80
93
|
result.paths[name] = {
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
type: "file",
|
|
95
|
+
path: fullPath
|
|
83
96
|
};
|
|
84
97
|
}
|
|
85
98
|
}
|
|
@@ -93,39 +106,54 @@ var DirectoryLint = class {
|
|
|
93
106
|
const items = this.backend.getAllItems(cwd);
|
|
94
107
|
const processedNames = /* @__PURE__ */ new Set();
|
|
95
108
|
const sortedEntries = Object.entries(schema).sort(([a], [b]) => {
|
|
96
|
-
const aHasWildcard = a.includes("*");
|
|
97
|
-
const bHasWildcard = b.includes("*");
|
|
109
|
+
const aHasWildcard = String(a).includes("*");
|
|
110
|
+
const bHasWildcard = String(b).includes("*");
|
|
98
111
|
if (!aHasWildcard && bHasWildcard) return -1;
|
|
99
112
|
if (aHasWildcard && !bHasWildcard) return 1;
|
|
100
113
|
return 0;
|
|
101
114
|
});
|
|
102
115
|
for (const [pattern, node] of sortedEntries) {
|
|
103
|
-
const regex = this.patternToRegex(pattern);
|
|
116
|
+
const regex = this.patternToRegex(String(pattern));
|
|
104
117
|
const matchedItems = items.filter(
|
|
105
118
|
(item) => regex.test(item.name) && !processedNames.has(item.name)
|
|
106
119
|
);
|
|
107
120
|
const isRequired = node.required ?? true;
|
|
108
|
-
if (matchedItems.length === 0 && isRequired)
|
|
121
|
+
if (matchedItems.length === 0 && isRequired) {
|
|
122
|
+
throw new InvalidStructure(String(pattern));
|
|
123
|
+
}
|
|
109
124
|
for (const { name, type } of matchedItems) {
|
|
110
125
|
if (options?.ignore.includes(name)) continue;
|
|
111
126
|
processedNames.add(name);
|
|
112
127
|
const fullPath = join(cwd, name);
|
|
113
128
|
if (node.type === "directory") {
|
|
114
|
-
if (type !== "directory")
|
|
115
|
-
|
|
129
|
+
if (type !== "directory") {
|
|
130
|
+
throw new InvalidStructure(fullPath);
|
|
131
|
+
}
|
|
132
|
+
let childrenResult;
|
|
116
133
|
if (node.children) {
|
|
117
|
-
childrenResult = await this.validate(
|
|
134
|
+
childrenResult = await this.validate(
|
|
135
|
+
fullPath,
|
|
136
|
+
node.children,
|
|
137
|
+
options
|
|
138
|
+
);
|
|
118
139
|
}
|
|
119
140
|
result.paths[name] = {
|
|
120
141
|
path: fullPath,
|
|
121
142
|
name,
|
|
122
143
|
type: "directory",
|
|
123
|
-
...childrenResult?.paths && {
|
|
144
|
+
...childrenResult?.paths && {
|
|
145
|
+
children: childrenResult.paths
|
|
146
|
+
}
|
|
124
147
|
};
|
|
125
|
-
}
|
|
126
|
-
|
|
148
|
+
}
|
|
149
|
+
if (node.type === "file") {
|
|
150
|
+
if (type !== "file") {
|
|
151
|
+
throw new InvalidStructure(fullPath);
|
|
152
|
+
}
|
|
127
153
|
const content = this.backend.readFile(fullPath);
|
|
128
|
-
if (node.validate
|
|
154
|
+
if (node.validate && !node.validate(content)) {
|
|
155
|
+
throw new InvalidContent(fullPath);
|
|
156
|
+
}
|
|
129
157
|
result.paths[name] = {
|
|
130
158
|
path: fullPath,
|
|
131
159
|
name,
|
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
|
+
}
|