kerria 0.2.1 → 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 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
@@ -14,4 +14,4 @@ pnpm i kerria
14
14
 
15
15
  ## 使用方式
16
16
 
17
- 请参考[示例文件](playground/kerria.config.ts)。
17
+ 请参考[示例文件](playground/kerria.config.ts)。
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
- name: string;
3
- value: any;
4
- output: () => void;
3
+ name: string;
4
+ value: any;
5
+ output: () => void;
5
6
  }
6
7
  interface UseLoadOptions {
7
- src?: string;
8
- out: string;
9
- defaultValue?: unknown;
10
- onUpdate?: (newVal: any, oldVal: any) => any;
11
- beforeOutput?: (val: any) => any;
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
- kind: number;
19
- folders: string[];
20
- patterns: string[];
21
- filter: (path: string) => boolean;
22
- output: (path: string, data: any) => Promise<void>;
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
- base: string;
26
- dist?: string;
27
- folders?: string[];
28
- ext: string;
29
- deep?: boolean;
30
- skip?: number;
31
- parse: (path: string, info: SourceInfo) => MaybePromise<T | null | void>;
32
- unlink?: (cache: T) => void;
33
- onCacheHit?: (cache: T) => void;
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
- sign: string;
39
- loadInfos: LoadInfo[];
40
- sourceInfos: SourceInfo[];
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
- build: () => Promise<void>;
45
- watch: () => Promise<void>;
50
+ build: () => Promise<void>;
51
+ watch: () => Promise<void>;
46
52
  };
47
53
 
48
- export { type LoadInfo, type SourceInfo, type UseLoadOptions, createProcessor, useCurrentContext, useLoad, useSource };
54
+ //#endregion
55
+ export { LoadInfo, SourceInfo, UseLoadOptions, createProcessor, useCurrentContext, useLoad, useSource };
package/dist/index.js CHANGED
@@ -1,200 +1,168 @@
1
- // src/core/processor.ts
1
+ import { createHash } from "node:crypto";
2
2
  import chokidar from "chokidar";
3
3
  import consola from "consola";
4
- import CryptoES from "crypto-es";
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
- // src/utils.ts
11
- var isDev = process.env.NODE_ENV === "development";
9
+ //#region src/utils.ts
10
+ const isDev = process.env.NODE_ENV === "development";
12
11
  function capitalize(str) {
13
- return str[0].toUpperCase() + str.slice(1);
12
+ return str[0].toUpperCase() + str.slice(1);
14
13
  }
15
14
 
16
- // src/core/processor.ts
17
- var currentContext = null;
15
+ //#endregion
16
+ //#region src/core/processor.ts
17
+ let currentContext = null;
18
18
  function useCurrentContext() {
19
- return currentContext;
19
+ return currentContext;
20
20
  }
21
21
  function createProcessor(sign, setup) {
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 = findCacheDir({ 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(
43
- paths.map((path) => path.replaceAll("\\", "/")).filter(info.filter).sort((a, b) => a.localeCompare(b)).map((path) => parse(path, info))
44
- );
45
- }
46
- outputLoads();
47
- consola.success(`[${sign}] Build`);
48
- }
49
- async function watch() {
50
- for (const info of ctx.sourceInfos) {
51
- chokidar.watch(info.folders, {
52
- depth: info.deep ? Infinity : 0,
53
- ignoreInitial: true
54
- }).on("all", async (event, filename) => {
55
- const path = filename.replaceAll("\\", "/");
56
- if (!path.endsWith(info.ext)) {
57
- return false;
58
- } else if (!info.filter(path)) {
59
- return false;
60
- } else if (event === "change" && !await parse(path, info)) {
61
- return false;
62
- } else if (event === "add" && !await add(path, info)) {
63
- return false;
64
- } else if (event === "unlink" && !unlink(path, info)) {
65
- return false;
66
- }
67
- outputLoads();
68
- consola.success(`[${sign}] ${capitalize(event)} "${path}"`);
69
- });
70
- }
71
- for (const info of ctx.loadInfos) {
72
- if (!info.src) {
73
- continue;
74
- }
75
- chokidar.watch(info.src, {
76
- ignoreInitial: true
77
- }).on("change", async () => {
78
- const newVal = await fs.readJson(info.src);
79
- info.value = info.onUpdate?.(newVal, info.value) ?? newVal;
80
- info.output();
81
- consola.success(`[${sign}] Change "${info.src}"`);
82
- });
83
- }
84
- }
85
- async function parse(path, info) {
86
- const stats = await fs.stat(path);
87
- const hash = CryptoES.MD5(stats.size.toString()).toString();
88
- let cache = caches[path];
89
- if (isDev && cache?.hash === hash) {
90
- info.onCacheHit?.(cache);
91
- return false;
92
- }
93
- cache = { hash };
94
- const data = await info.parse(path, info);
95
- if (data !== null) {
96
- cache = {
97
- ...cache,
98
- ...data ?? {}
99
- };
100
- info.onCacheHit?.(cache);
101
- caches[path] = cache;
102
- } else {
103
- unlink(path, info);
104
- }
105
- return true;
106
- }
107
- async function add(path, info) {
108
- const cache = caches[path];
109
- if (cache) {
110
- return false;
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
- if (isDev) {
125
- fs.outputJsonSync(cachePath, caches);
126
- }
127
- for (const info of ctx.loadInfos) {
128
- info.output();
129
- }
130
- }
131
- return {
132
- build,
133
- watch
134
- };
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
+ };
135
112
  }
136
113
 
137
- // src/core/useLoad.ts
138
- import fs2 from "fs-extra";
139
- import { resolve } from "pathe";
114
+ //#endregion
115
+ //#region src/core/useLoad.ts
140
116
  function useLoad(name, options) {
141
- const ctx = useCurrentContext();
142
- const src = options.src ? resolve(options.src) : void 0;
143
- const out = resolve(options.out);
144
- const {
145
- defaultValue = {},
146
- onUpdate,
147
- beforeOutput
148
- } = options;
149
- const info = {
150
- name,
151
- src,
152
- out,
153
- value: src ? fs2.readJsonSync(src) : defaultValue,
154
- onUpdate,
155
- output() {
156
- const data = beforeOutput?.(info.value) ?? info.value;
157
- fs2.outputJsonSync(out, data);
158
- }
159
- };
160
- ctx.loadInfos.push(info);
161
- onUpdate?.(info.value, void 0);
162
- 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;
163
135
  }
164
136
 
165
- // src/core/useSource.ts
166
- import fs3 from "fs-extra";
167
- import { resolve as resolve2 } from "pathe";
137
+ //#endregion
138
+ //#region src/core/useSource.ts
168
139
  function useSource(kind, options) {
169
- const ctx = useCurrentContext();
170
- const base = resolve2(options.base);
171
- const dist = options.dist ? resolve2(options.dist) : void 0;
172
- const folders = options.folders?.map((folder) => resolve2(base, folder)) ?? [base];
173
- const patterns = folders.map((path) => resolve2(path, `**/*${options.ext}`));
174
- const info = {
175
- ...options,
176
- kind,
177
- base,
178
- dist,
179
- folders,
180
- patterns,
181
- deep: options.deep ?? true,
182
- skip: options.skip ?? 0,
183
- filter(path) {
184
- const depth = path.split("/").length - folders[0].split("/").length;
185
- return info.skip < depth;
186
- },
187
- async output(path, data) {
188
- const outPath = path.replace(base, dist).replace(info.ext, ".json");
189
- await fs3.outputJson(outPath, data);
190
- }
191
- };
192
- ctx.sourceInfos.push(info);
193
- return info;
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;
194
165
  }
195
- export {
196
- createProcessor,
197
- useCurrentContext,
198
- useLoad,
199
- useSource
200
- };
166
+
167
+ //#endregion
168
+ export { createProcessor, useCurrentContext, useLoad, useSource };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kerria",
3
3
  "type": "module",
4
- "version": "0.2.1",
4
+ "version": "0.2.3",
5
5
  "description": "Composable source processor",
6
6
  "author": "KazariEX",
7
7
  "license": "MIT",
@@ -19,18 +19,24 @@
19
19
  "dependencies": {
20
20
  "chokidar": "^4.0.3",
21
21
  "consola": "^3.4.2",
22
- "crypto-es": "^2.1.0",
23
- "find-cache-dir": "^5.0.0",
22
+ "find-cache-directory": "^6.0.0",
24
23
  "fs-extra": "^11.3.0",
25
24
  "pathe": "^2.0.3",
26
- "tinyglobby": "^0.2.12"
25
+ "tinyglobby": "^0.2.13"
27
26
  },
28
27
  "devDependencies": {
29
- "@types/fs-extra": "^11.0.4"
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": "tsup-node",
33
- "dev": "tsup-node --watch",
38
+ "build": "tsdown",
39
+ "dev": "tsdown -w",
34
40
  "release": "bumpp --no-push -c \"release: v%s\""
35
41
  }
36
42
  }