kerria 0.2.0 → 0.2.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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +36 -29
- package/dist/index.js +150 -180
- package/package.json +16 -10
package/LICENSE
CHANGED
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,48 +1,55 @@
|
|
|
1
|
+
//#region src/core/useLoad.d.ts
|
|
1
2
|
interface LoadInfo extends Omit<UseLoadOptions, "defaultValue" | "beforeOutput"> {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
name: string;
|
|
4
|
+
value: any;
|
|
5
|
+
output: () => void;
|
|
5
6
|
}
|
|
6
7
|
interface UseLoadOptions {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
src?: string;
|
|
9
|
+
out: string;
|
|
10
|
+
defaultValue?: unknown;
|
|
11
|
+
onUpdate?: (newVal: any, oldVal: any) => any;
|
|
12
|
+
beforeOutput?: (val: any) => any;
|
|
12
13
|
}
|
|
13
14
|
declare function useLoad(name: string, options: UseLoadOptions): LoadInfo;
|
|
14
|
-
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/types.d.ts
|
|
15
17
|
type MaybePromise<T> = T | Promise<T>;
|
|
16
18
|
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/core/useSource.d.ts
|
|
17
21
|
interface SourceInfo extends Omit<UseSourceOptions, "folders"> {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
kind: number;
|
|
23
|
+
folders: string[];
|
|
24
|
+
patterns: string[];
|
|
25
|
+
filter: (path: string) => boolean;
|
|
26
|
+
output: (path: string, data: any) => Promise<void>;
|
|
23
27
|
}
|
|
24
28
|
interface UseSourceOptions<T = any> {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
base: string;
|
|
30
|
+
dist?: string;
|
|
31
|
+
folders?: string[];
|
|
32
|
+
ext: string;
|
|
33
|
+
deep?: boolean;
|
|
34
|
+
skip?: number;
|
|
35
|
+
parse: (path: string, info: SourceInfo) => MaybePromise<T | null | void>;
|
|
36
|
+
unlink?: (cache: T) => void;
|
|
37
|
+
onCacheHit?: (cache: T) => void;
|
|
34
38
|
}
|
|
35
39
|
declare function useSource<C extends object>(kind: number, options: UseSourceOptions<C>): SourceInfo;
|
|
36
40
|
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/core/processor.d.ts
|
|
37
43
|
interface ProcessorContext {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
sign: string;
|
|
45
|
+
loadInfos: LoadInfo[];
|
|
46
|
+
sourceInfos: SourceInfo[];
|
|
41
47
|
}
|
|
42
48
|
declare function useCurrentContext(): ProcessorContext;
|
|
43
49
|
declare function createProcessor(sign: string, setup: (ctx: ProcessorContext) => void): {
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
build: () => Promise<void>;
|
|
51
|
+
watch: () => Promise<void>;
|
|
46
52
|
};
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
//#endregion
|
|
55
|
+
export { LoadInfo, SourceInfo, UseLoadOptions, createProcessor, useCurrentContext, useLoad, useSource };
|
package/dist/index.js
CHANGED
|
@@ -1,198 +1,168 @@
|
|
|
1
|
-
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
2
|
import chokidar from "chokidar";
|
|
3
3
|
import consola from "consola";
|
|
4
|
-
import
|
|
5
|
-
import findCacheDir from "find-cache-dir";
|
|
4
|
+
import findCacheDirectory from "find-cache-directory";
|
|
6
5
|
import fs from "fs-extra";
|
|
7
|
-
import { join } from "pathe";
|
|
6
|
+
import { join, resolve } from "pathe";
|
|
8
7
|
import { glob } from "tinyglobby";
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
//#region src/utils.ts
|
|
10
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
12
11
|
function capitalize(str) {
|
|
13
|
-
|
|
12
|
+
return str[0].toUpperCase() + str.slice(1);
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/core/processor.ts
|
|
17
|
+
let currentContext = null;
|
|
18
18
|
function useCurrentContext() {
|
|
19
|
-
|
|
19
|
+
return currentContext;
|
|
20
20
|
}
|
|
21
21
|
function createProcessor(sign, setup) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return await parse(path, info);
|
|
113
|
-
}
|
|
114
|
-
function unlink(path, info) {
|
|
115
|
-
const cache = caches[path];
|
|
116
|
-
if (!cache) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
info.unlink?.(cache);
|
|
120
|
-
delete caches[path];
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
function outputLoads() {
|
|
124
|
-
fs.outputJsonSync(cachePath, caches);
|
|
125
|
-
for (const info of ctx.loadInfos) {
|
|
126
|
-
info.output();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return {
|
|
130
|
-
build,
|
|
131
|
-
watch
|
|
132
|
-
};
|
|
22
|
+
const ctx = {
|
|
23
|
+
sign,
|
|
24
|
+
loadInfos: [],
|
|
25
|
+
sourceInfos: []
|
|
26
|
+
};
|
|
27
|
+
currentContext = ctx;
|
|
28
|
+
setup(ctx);
|
|
29
|
+
currentContext = null;
|
|
30
|
+
ctx.sourceInfos.sort((a, b) => {
|
|
31
|
+
return a.kind - b.kind;
|
|
32
|
+
});
|
|
33
|
+
const cacheDir = findCacheDirectory({ name: "kerria" });
|
|
34
|
+
const cachePath = join(cacheDir, `${sign}.json`);
|
|
35
|
+
const caches = fs.existsSync(cachePath) && fs.readJsonSync(cachePath) || {};
|
|
36
|
+
async function build() {
|
|
37
|
+
for (const info of ctx.sourceInfos) {
|
|
38
|
+
const paths = await glob(info.patterns, {
|
|
39
|
+
deep: info.deep ? Infinity : 2,
|
|
40
|
+
absolute: true
|
|
41
|
+
});
|
|
42
|
+
await Promise.all(paths.map((path) => path.replaceAll("\\", "/")).filter(info.filter).sort((a, b) => a.localeCompare(b)).map((path) => parse(path, info)));
|
|
43
|
+
}
|
|
44
|
+
outputLoads();
|
|
45
|
+
consola.success(`[${sign}] Build`);
|
|
46
|
+
}
|
|
47
|
+
async function watch() {
|
|
48
|
+
for (const info of ctx.sourceInfos) chokidar.watch(info.folders, {
|
|
49
|
+
depth: info.deep ? Infinity : 0,
|
|
50
|
+
ignoreInitial: true
|
|
51
|
+
}).on("all", async (event, filename) => {
|
|
52
|
+
const path = filename.replaceAll("\\", "/");
|
|
53
|
+
if (!path.endsWith(info.ext)) return false;
|
|
54
|
+
else if (!info.filter(path)) return false;
|
|
55
|
+
else if (event === "change" && !await parse(path, info)) return false;
|
|
56
|
+
else if (event === "add" && !await add(path, info)) return false;
|
|
57
|
+
else if (event === "unlink" && !unlink(path, info)) return false;
|
|
58
|
+
outputLoads();
|
|
59
|
+
consola.success(`[${sign}] ${capitalize(event)} "${path}"`);
|
|
60
|
+
});
|
|
61
|
+
for (const info of ctx.loadInfos) {
|
|
62
|
+
if (!info.src) continue;
|
|
63
|
+
chokidar.watch(info.src, { ignoreInitial: true }).on("change", async () => {
|
|
64
|
+
const newVal = await fs.readJson(info.src);
|
|
65
|
+
info.value = info.onUpdate?.(newVal, info.value) ?? newVal;
|
|
66
|
+
info.output();
|
|
67
|
+
consola.success(`[${sign}] Change "${info.src}"`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function parse(path, info) {
|
|
72
|
+
const stats = await fs.stat(path);
|
|
73
|
+
const hash = createHash("md5").update(stats.mtimeMs.toString()).digest("hex");
|
|
74
|
+
let cache = caches[path];
|
|
75
|
+
if (isDev && cache?.hash === hash) {
|
|
76
|
+
info.onCacheHit?.(cache);
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
cache = { hash };
|
|
80
|
+
const data = await info.parse(path, info);
|
|
81
|
+
if (data !== null) {
|
|
82
|
+
cache = {
|
|
83
|
+
...cache,
|
|
84
|
+
...data ?? {}
|
|
85
|
+
};
|
|
86
|
+
info.onCacheHit?.(cache);
|
|
87
|
+
caches[path] = cache;
|
|
88
|
+
} else unlink(path, info);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
async function add(path, info) {
|
|
92
|
+
const cache = caches[path];
|
|
93
|
+
if (cache) return false;
|
|
94
|
+
return await parse(path, info);
|
|
95
|
+
}
|
|
96
|
+
function unlink(path, info) {
|
|
97
|
+
const cache = caches[path];
|
|
98
|
+
if (!cache) return false;
|
|
99
|
+
info.unlink?.(cache);
|
|
100
|
+
delete caches[path];
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
function outputLoads() {
|
|
104
|
+
if (isDev) fs.outputJsonSync(cachePath, caches);
|
|
105
|
+
else fs.removeSync(cachePath);
|
|
106
|
+
for (const info of ctx.loadInfos) info.output();
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
build,
|
|
110
|
+
watch
|
|
111
|
+
};
|
|
133
112
|
}
|
|
134
113
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
import { resolve } from "pathe";
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/core/useLoad.ts
|
|
138
116
|
function useLoad(name, options) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
};
|
|
158
|
-
ctx.loadInfos.push(info);
|
|
159
|
-
onUpdate?.(info.value, void 0);
|
|
160
|
-
return info;
|
|
117
|
+
const ctx = useCurrentContext();
|
|
118
|
+
const src = options.src ? resolve(options.src) : void 0;
|
|
119
|
+
const out = resolve(options.out);
|
|
120
|
+
const { defaultValue = {}, onUpdate, beforeOutput } = options;
|
|
121
|
+
const info = {
|
|
122
|
+
name,
|
|
123
|
+
src,
|
|
124
|
+
out,
|
|
125
|
+
value: src ? fs.readJsonSync(src) : defaultValue,
|
|
126
|
+
onUpdate,
|
|
127
|
+
output() {
|
|
128
|
+
const data = beforeOutput?.(info.value) ?? info.value;
|
|
129
|
+
fs.outputJsonSync(out, data);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
ctx.loadInfos.push(info);
|
|
133
|
+
onUpdate?.(info.value, void 0);
|
|
134
|
+
return info;
|
|
161
135
|
}
|
|
162
136
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
import { resolve as resolve2 } from "pathe";
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/core/useSource.ts
|
|
166
139
|
function useSource(kind, options) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
140
|
+
const ctx = useCurrentContext();
|
|
141
|
+
const base = resolve(options.base);
|
|
142
|
+
const dist = options.dist ? resolve(options.dist) : void 0;
|
|
143
|
+
const folders = options.folders?.map((folder) => resolve(base, folder)) ?? [base];
|
|
144
|
+
const patterns = folders.map((path) => resolve(path, `**/*${options.ext}`));
|
|
145
|
+
const info = {
|
|
146
|
+
...options,
|
|
147
|
+
kind,
|
|
148
|
+
base,
|
|
149
|
+
dist,
|
|
150
|
+
folders,
|
|
151
|
+
patterns,
|
|
152
|
+
deep: options.deep ?? true,
|
|
153
|
+
skip: options.skip ?? 0,
|
|
154
|
+
filter(path) {
|
|
155
|
+
const depth = path.split("/").length - folders[0].split("/").length;
|
|
156
|
+
return info.skip < depth;
|
|
157
|
+
},
|
|
158
|
+
async output(path, data) {
|
|
159
|
+
const outPath = path.replace(base, dist).replace(info.ext, ".json");
|
|
160
|
+
await fs.outputJson(outPath, data);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
ctx.sourceInfos.push(info);
|
|
164
|
+
return info;
|
|
192
165
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
useLoad,
|
|
197
|
-
useSource
|
|
198
|
-
};
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
export { createProcessor, useCurrentContext, useLoad, useSource };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kerria",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
5
|
-
"description": "",
|
|
4
|
+
"version": "0.2.3",
|
|
5
|
+
"description": "Composable source processor",
|
|
6
6
|
"author": "KazariEX",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": "KazariEX/kerria",
|
|
@@ -18,19 +18,25 @@
|
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"chokidar": "^4.0.3",
|
|
21
|
-
"consola": "^3.4.
|
|
22
|
-
"
|
|
23
|
-
"find-cache-dir": "^5.0.0",
|
|
21
|
+
"consola": "^3.4.2",
|
|
22
|
+
"find-cache-directory": "^6.0.0",
|
|
24
23
|
"fs-extra": "^11.3.0",
|
|
25
|
-
"pathe": "^2.0.
|
|
26
|
-
"tinyglobby": "^0.2.
|
|
24
|
+
"pathe": "^2.0.3",
|
|
25
|
+
"tinyglobby": "^0.2.13"
|
|
27
26
|
},
|
|
28
27
|
"devDependencies": {
|
|
29
|
-
"@
|
|
28
|
+
"@antfu/eslint-config": "^4.12.0",
|
|
29
|
+
"@types/fs-extra": "^11.0.4",
|
|
30
|
+
"@types/node": "^22.15.3",
|
|
31
|
+
"@zinkawaii/eslint-config": "^0.3.0",
|
|
32
|
+
"@zinkawaii/tsconfig": "^0.0.2",
|
|
33
|
+
"bumpp": "^10.1.0",
|
|
34
|
+
"eslint": "^9.25.1",
|
|
35
|
+
"tsdown": "^0.10.2"
|
|
30
36
|
},
|
|
31
37
|
"scripts": {
|
|
32
|
-
"build": "
|
|
33
|
-
"dev": "
|
|
38
|
+
"build": "tsdown",
|
|
39
|
+
"dev": "tsdown -w",
|
|
34
40
|
"release": "bumpp --no-push -c \"release: v%s\""
|
|
35
41
|
}
|
|
36
42
|
}
|