@delta-comic/model 2.2.0 → 3.0.0-next.5

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.mjs ADDED
@@ -0,0 +1,379 @@
1
+ import { isString } from "es-toolkit";
2
+ import { shallowReactive } from "vue";
3
+ import { logger } from "@delta-comic/logger";
4
+ import { isEmpty, isString as isString$1 } from "es-toolkit/compat";
5
+ //#region lib/struct/store.ts
6
+ /**
7
+ * 比如有很多需要注明来自哪个插件的值都可以用
8
+ */
9
+ var SourcedValue = class {
10
+ separator;
11
+ toJSON(value) {
12
+ if (isString(value)) return this.parse(value);
13
+ return value;
14
+ }
15
+ parse(value) {
16
+ const splited = value.split(this.separator);
17
+ return [splited[0], splited.slice(1).join(this.separator)];
18
+ }
19
+ toString(value) {
20
+ if (isString(value)) return value;
21
+ return this.stringify(value);
22
+ }
23
+ stringify(value) {
24
+ return value.join(this.separator);
25
+ }
26
+ constructor(separator = ":") {
27
+ this.separator = separator;
28
+ }
29
+ };
30
+ /**
31
+ * 相比较于普通的Map,这个元素的key操作可以是`TKey | string`
32
+ * _但内部保存仍使用`SourcedValue.key.toString`作为key_
33
+ */
34
+ var SourcedKeyMap = class {
35
+ getOrInsert(key, value) {
36
+ const storeKey = this.key.toString(key);
37
+ if (this.store.has(storeKey)) return this.store.get(storeKey);
38
+ this.store.set(storeKey, value);
39
+ return value;
40
+ }
41
+ getOrInsertComputed(key, compute) {
42
+ const storeKey = this.key.toString(key);
43
+ if (this.store.has(storeKey)) return this.store.get(storeKey);
44
+ const value = compute(storeKey);
45
+ this.store.set(storeKey, value);
46
+ return value;
47
+ }
48
+ static createReactive(separator = ":") {
49
+ return shallowReactive(new this(separator));
50
+ }
51
+ constructor(separator = ":") {
52
+ this.key = new SourcedValue(separator);
53
+ }
54
+ key;
55
+ store = shallowReactive(/* @__PURE__ */ new Map());
56
+ get size() {
57
+ return this.store.size;
58
+ }
59
+ [Symbol.toStringTag] = "SourcedKeyMap";
60
+ clear() {
61
+ this.store.clear();
62
+ }
63
+ delete(key) {
64
+ return this.store.delete(this.key.toString(key));
65
+ }
66
+ forEach(callbackfn, thisArg) {
67
+ this.store.forEach((v, k) => {
68
+ callbackfn.call(thisArg, v, k, this);
69
+ });
70
+ }
71
+ get(key) {
72
+ return this.store.get(this.key.toString(key));
73
+ }
74
+ has(key) {
75
+ return this.store.has(this.key.toString(key));
76
+ }
77
+ set(key, value) {
78
+ this.store.set(this.key.toString(key), value);
79
+ return this;
80
+ }
81
+ entries() {
82
+ return this.store.entries();
83
+ }
84
+ keys() {
85
+ return this.store.keys();
86
+ }
87
+ values() {
88
+ return this.store.values();
89
+ }
90
+ [Symbol.iterator]() {
91
+ return this.entries();
92
+ }
93
+ };
94
+ //#endregion
95
+ //#region lib/struct/struct.ts
96
+ /**
97
+ * 可以结构化的数据,调用`toJSON`获取纯粹的json(没有get/set或method)
98
+ */
99
+ var Struct = class Struct {
100
+ $$raw;
101
+ toJSON() {
102
+ return JSON.parse(JSON.stringify(this.$$raw));
103
+ }
104
+ /**
105
+ * @param $$raw 一个纯粹json对象,不可以是高级对象
106
+ */
107
+ constructor($$raw) {
108
+ this.$$raw = $$raw;
109
+ }
110
+ static toRaw(item) {
111
+ if (item instanceof Struct) return item.toJSON();
112
+ return item;
113
+ }
114
+ };
115
+ //#endregion
116
+ //#region lib/struct/meta.ts
117
+ var StreamQuery = class {
118
+ query;
119
+ initPage;
120
+ constructor(query, initPage) {
121
+ this.query = query;
122
+ this.initPage = initPage;
123
+ }
124
+ };
125
+ //#endregion
126
+ //#region lib/model/comment.ts
127
+ var UniComment = class extends Struct {
128
+ static commentRow = SourcedKeyMap.createReactive();
129
+ constructor(v) {
130
+ super(v);
131
+ this.content = v.content;
132
+ this.time = v.time;
133
+ this.id = v.id;
134
+ this.childrenCount = v.childrenCount;
135
+ this.likeCount = v.likeCount;
136
+ this.isLiked = v.isLiked;
137
+ this.reported = v.reported;
138
+ this.$$plugin = v.$$plugin;
139
+ this.$$meta = v.$$meta;
140
+ this.isTop = v.isTop;
141
+ }
142
+ content;
143
+ time;
144
+ id;
145
+ childrenCount;
146
+ likeCount;
147
+ isTop;
148
+ isLiked;
149
+ reported;
150
+ $$plugin;
151
+ $$meta;
152
+ };
153
+ //#endregion
154
+ //#region lib/model/ep.ts
155
+ var UniEp = class extends Struct {
156
+ name;
157
+ id;
158
+ $$plugin;
159
+ $$meta;
160
+ constructor(v) {
161
+ super(v);
162
+ this.name = v.name;
163
+ this.id = v.id;
164
+ this.$$plugin = v.$$plugin;
165
+ this.$$meta = v.$$meta;
166
+ }
167
+ };
168
+ //#endregion
169
+ //#region lib/model/resource.ts
170
+ const resourceLogger = logger.scoped("model:resource");
171
+ var UniResource = class UniResource extends Struct {
172
+ static processInstances = SourcedKeyMap.createReactive();
173
+ static fork = SourcedKeyMap.createReactive();
174
+ static precedenceFork = SourcedKeyMap.createReactive();
175
+ static is(value) {
176
+ return value instanceof this;
177
+ }
178
+ static create(v) {
179
+ return new this(v);
180
+ }
181
+ constructor(v) {
182
+ super(v);
183
+ this.$$plugin = v.$$plugin;
184
+ this.$$meta = v.$$meta;
185
+ this.pathname = v.pathname;
186
+ this.type = v.type;
187
+ this.processSteps = (v.processSteps ?? []).map((v) => isString$1(v) ? {
188
+ referenceName: v,
189
+ ignoreExit: false
190
+ } : v);
191
+ }
192
+ type;
193
+ pathname;
194
+ processSteps;
195
+ $$meta;
196
+ $$plugin;
197
+ async getUrl() {
198
+ let resultPath = this.pathname;
199
+ for (const option of this.processSteps) {
200
+ const instance = UniResource.processInstances.get([this.$$plugin, option.referenceName]);
201
+ if (!instance) {
202
+ resourceLogger.warn("resource process not found", {
203
+ plugin: this.$$plugin,
204
+ referenceName: option.referenceName
205
+ });
206
+ continue;
207
+ }
208
+ const result = await instance(resultPath, this);
209
+ resultPath = result[0];
210
+ if (option.ignoreExit || !result[1]) continue;
211
+ break;
212
+ }
213
+ if (!URL.canParse(resultPath)) return `${this.getThisFork()}/${resultPath}`;
214
+ return resultPath;
215
+ }
216
+ omittedForks = shallowReactive(/* @__PURE__ */ new Set());
217
+ getThisFork() {
218
+ const all = new Set(UniResource.fork.get([this.$$plugin, this.type])?.urls ?? []);
219
+ let fork;
220
+ if (isEmpty(this.omittedForks)) fork = UniResource.precedenceFork.get([this.$$plugin, this.type]);
221
+ else fork = Array.from(all.difference(this.omittedForks).values())[0];
222
+ if (!fork) throw new Error(`[UniResource.getThisFork] fork not found, type: [${this.$$plugin}, ${this.type}]`);
223
+ return fork;
224
+ }
225
+ localChangeFork() {
226
+ const all = new Set(UniResource.fork.get([this.$$plugin, this.type])?.urls ?? []);
227
+ this.omittedForks.add(this.getThisFork());
228
+ const isChangedFail = isEmpty(all.difference(this.omittedForks));
229
+ if (isChangedFail) this.omittedForks.clear();
230
+ return isChangedFail;
231
+ }
232
+ };
233
+ //#endregion
234
+ //#region lib/model/image.ts
235
+ var UniImage = class extends UniResource {
236
+ static is(value) {
237
+ return value instanceof this;
238
+ }
239
+ static create(v, aspect) {
240
+ return new this(v, aspect);
241
+ }
242
+ constructor(v, aspect) {
243
+ if ("forkNamespace" in v) super({
244
+ $$plugin: v.$$plugin,
245
+ $$meta: {
246
+ ...v.$$meta,
247
+ aspect
248
+ },
249
+ pathname: v.path,
250
+ type: v.forkNamespace,
251
+ processSteps: v.processSteps
252
+ });
253
+ else super(v);
254
+ }
255
+ get aspect() {
256
+ return this.$$meta.aspect;
257
+ }
258
+ set aspect(v) {
259
+ if (!v) return;
260
+ this.$$meta ??= {};
261
+ this.$$meta.aspect ??= {};
262
+ this.$$meta.aspect.width = v.width;
263
+ this.$$meta.aspect.height = v.height;
264
+ }
265
+ };
266
+ //#endregion
267
+ //#region lib/model/item.ts
268
+ var UniItem = class extends Struct {
269
+ static itemTranslator = SourcedKeyMap.createReactive();
270
+ static create(raw) {
271
+ const translator = this.itemTranslator.get(raw.contentType);
272
+ if (!translator) throw new Error(`can not found itemTranslator contentType:"${UniContentPage.contentPages.key.toString(raw.contentType)}"`);
273
+ return translator(raw);
274
+ }
275
+ static authorIcon = SourcedKeyMap.createReactive();
276
+ static itemCards = SourcedKeyMap.createReactive();
277
+ static is(value) {
278
+ return value instanceof this;
279
+ }
280
+ cover;
281
+ get $cover() {
282
+ return UniImage.create(this.cover);
283
+ }
284
+ title;
285
+ id;
286
+ categories;
287
+ author;
288
+ viewNumber;
289
+ likeNumber;
290
+ commentNumber;
291
+ isLiked;
292
+ description;
293
+ updateTime;
294
+ contentType;
295
+ length;
296
+ epLength;
297
+ $$plugin;
298
+ $$meta;
299
+ thisEp;
300
+ customIsSafe;
301
+ get $thisEp() {
302
+ return new UniEp(this.thisEp);
303
+ }
304
+ constructor(v) {
305
+ super(v);
306
+ this.$$plugin = v.$$plugin;
307
+ this.$$meta = v.$$meta;
308
+ this.thisEp = v.thisEp;
309
+ this.updateTime = v.updateTime;
310
+ this.cover = v.cover;
311
+ this.title = v.title;
312
+ this.id = v.id;
313
+ this.categories = v.categories;
314
+ this.author = v.author;
315
+ this.viewNumber = v.viewNumber;
316
+ this.likeNumber = v.likeNumber;
317
+ this.commentNumber = v.commentNumber;
318
+ this.isLiked = v.isLiked;
319
+ this.customIsAI = v.customIsAI;
320
+ this.contentType = UniContentPage.contentPages.key.toJSON(v.contentType);
321
+ this.length = v.length;
322
+ this.epLength = v.epLength;
323
+ this.description = v.description;
324
+ this.commentSendable = v.commentSendable;
325
+ this.customIsSafe = v.customIsSafe;
326
+ }
327
+ commentSendable;
328
+ customIsAI;
329
+ get $isAi() {
330
+ const check = (str) => /(^|[(([\s【])ai[】))\]\s]?/gi.test(str);
331
+ return this.customIsAI || check(this.title) || this.author.some((author) => check(`${author.label}\u1145${author.description}`));
332
+ }
333
+ };
334
+ //#endregion
335
+ //#region lib/model/content.ts
336
+ var UniContentPage = class {
337
+ preload;
338
+ id;
339
+ ep;
340
+ static layouts = SourcedKeyMap.createReactive();
341
+ static contentPages = SourcedKeyMap.createReactive();
342
+ static downloadProviders = SourcedKeyMap.createReactive();
343
+ constructor(preload, id, ep) {
344
+ this.preload = preload;
345
+ this.id = id;
346
+ this.ep = ep;
347
+ }
348
+ };
349
+ //#endregion
350
+ //#region lib/model/download.ts
351
+ /**
352
+ * Legacy imperative download controller.
353
+ *
354
+ * @deprecated Register a {@link UniContentDownloadProvider} for the content type and let the native
355
+ * downloader own task state, persistence, and lifecycle controls. This class remains unchanged so
356
+ * existing plugins can migrate without an immediate breaking change.
357
+ */
358
+ var UniDownloader = class {};
359
+ //#endregion
360
+ //#region lib/model/user.ts
361
+ var UniUser = class {
362
+ static userBase = shallowReactive(/* @__PURE__ */ new Map());
363
+ static userEditorBase = shallowReactive(/* @__PURE__ */ new Map());
364
+ static userCards = shallowReactive(/* @__PURE__ */ new Map());
365
+ constructor(v) {
366
+ if (v.avatar) this.avatar = UniImage.create(v.avatar);
367
+ this.name = v.name;
368
+ this.id = v.id;
369
+ this.$$plugin = v.$$plugin;
370
+ this.$$meta = v.$$meta;
371
+ }
372
+ avatar;
373
+ name;
374
+ id;
375
+ $$plugin;
376
+ $$meta;
377
+ };
378
+ //#endregion
379
+ export { SourcedKeyMap, SourcedValue, StreamQuery, Struct, UniComment, UniContentPage, UniDownloader, UniEp, UniImage, UniItem, UniResource, UniUser };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delta-comic/model",
3
- "version": "2.2.0",
3
+ "version": "3.0.0-next.5",
4
4
  "description": "空阙虱楼",
5
5
  "homepage": "https://github.com/delta-comic/delta-comic",
6
6
  "license": "AGPL-3.0-only",
@@ -16,41 +16,32 @@
16
16
  "dist"
17
17
  ],
18
18
  "type": "module",
19
- "main": "./dist/index.js",
20
- "module": "./dist/index.js",
21
- "types": "./dist/lib/index.d.ts",
19
+ "main": "./dist/index.mjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/lib/index.d.mts",
22
22
  "exports": {
23
23
  ".": {
24
- "types": "./dist/lib/index.d.ts",
25
- "import": "./dist/index.js"
24
+ "types": "./dist/lib/index.d.mts",
25
+ "import": "./dist/index.mjs"
26
26
  }
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@pinia/colada": "^1.1.0",
33
- "@vueuse/core": "^14.2.1",
34
- "dayjs": "^1.11.20",
35
- "mitt": "^3.0.1"
32
+ "es-toolkit": "^1.47.0",
33
+ "@delta-comic/logger": "3.0.0-next.5"
36
34
  },
37
35
  "devDependencies": {
38
- "vite": "npm:@voidzero-dev/vite-plus-core@^0.1.16",
39
- "vite-plus": "^0.1.16"
36
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
37
+ "vite-plus": "^0.2.4",
38
+ "vitest": "4.1.10"
40
39
  },
41
40
  "peerDependencies": {
42
- "vue": "^3.5",
43
- "@delta-comic/utils": "2.2.0",
44
- "@delta-comic/request": "2.2.0"
41
+ "vue": "^3.5.40"
45
42
  },
46
- "release": {
47
- "tagFormat": "model-${version}"
48
- },
49
- "dist": {
50
- "tarball": "./dist/pack.tgz"
51
- },
52
- "readme": "./README.md",
53
43
  "scripts": {
54
- "build": "vp build && pnpm pack --out ./dist/pack.tgz"
44
+ "build": "vp pack",
45
+ "typecheck": "tsgo -p tsconfig.app.json --noEmit && tsgo -p tsconfig.node.json --noEmit"
55
46
  }
56
47
  }
package/README.md DELETED
@@ -1,42 +0,0 @@
1
- ```python
2
- r"""
3
- ___________________________
4
- / ______\ | __ | | ____|
5
- | | _____ | |__| | | |__
6
- | | / _ \| __ \ | __|
7
- | |___| |_| || | \ \| |____
8
- \__________/|_| \________|
9
- ==============================
10
- 空阙虱楼 Copyright © Wenxig
11
- """
12
- ```
13
-
14
- [![GitHub](https://img.shields.io/github/license/delta-comic/delta-comic-core)](https://raw.githubusercontent.com/delta-comic/delta-comic-core/main/LICENSE)
15
- [![NPM Downloads](https://img.shields.io/npm/dm/delta-comic-core)](https://www.npmjs.com/package/delta-comic-core)
16
-
17
- - 工具库
18
-
19
- ## 功能
20
-
21
- - 辅助编写插件
22
- - 提供通用数据结构与默认样式
23
-
24
- ## 如何使用
25
-
26
- ```sh
27
- pnpm add delta-comic-core
28
- ```
29
-
30
- ## 为谁编写插件?
31
-
32
- [![Readme Card](https://wenxig-grs.vercel.app/api/pin/?username=delta-comic&repo=delta-comic&user&theme=transparent)](https://github.com/delta-comic/delta-comic)
33
-
34
- ## 辅助的插件
35
-
36
- ### Layout
37
-
38
- [![Readme Card](https://wenxig-grs.vercel.app/api/pin/?username=delta-comic&repo=delta-comic-plugin-layout&user&theme=transparent)](https://github.com/delta-comic/delta-comic-plugin-bika)
39
-
40
- ## Star History
41
-
42
- [![Star History Chart](https://api.star-history.com/svg?repos=delta-comic/delta-comic-core&type=Date)](https://www.star-history.com/#delta-comic/delta-comic-core&Date)