@inlang/sdk 0.28.3 → 0.30.0
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/adapter/solidAdapter.js +1 -1
- package/dist/adapter/solidAdapter.test.js +23 -37
- package/dist/api.d.ts +3 -9
- package/dist/api.d.ts.map +1 -1
- package/dist/createMessageLintReportsQuery.d.ts.map +1 -1
- package/dist/createMessageLintReportsQuery.js +24 -12
- package/dist/loadProject.d.ts.map +1 -1
- package/dist/loadProject.js +5 -6
- package/dist/loadProject.test.js +7 -5
- package/dist/reactivity/solid.d.ts +2 -1
- package/dist/reactivity/solid.d.ts.map +1 -1
- package/dist/reactivity/solid.js +3 -2
- package/dist/reactivity/solid.test.js +47 -1
- package/package.json +4 -4
- package/src/adapter/solidAdapter.test.ts +34 -48
- package/src/adapter/solidAdapter.ts +1 -1
- package/src/api.ts +3 -8
- package/src/createMessageLintReportsQuery.ts +28 -16
- package/src/loadProject.test.ts +7 -5
- package/src/loadProject.ts +5 -7
- package/src/reactivity/solid.test.ts +57 -1
- package/src/reactivity/solid.ts +3 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
2
|
import { describe, it, expect } from "vitest";
|
|
3
|
-
import { createEffect, from, createRoot } from "../reactivity/solid.js";
|
|
3
|
+
import { createResource, createSignal, createEffect, from, createRoot, } from "../reactivity/solid.js";
|
|
4
4
|
import { solidAdapter } from "./solidAdapter.js";
|
|
5
5
|
import { loadProject } from "../loadProject.js";
|
|
6
6
|
import { mockRepo } from "@lix-js/client";
|
|
7
|
+
function sleep(ms) {
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9
|
+
}
|
|
7
10
|
// ------------------------------------------------------------------------------------------------
|
|
8
11
|
const config = {
|
|
9
12
|
sourceLanguageTag: "en",
|
|
@@ -265,50 +268,32 @@ describe("messages", () => {
|
|
|
265
268
|
});
|
|
266
269
|
});
|
|
267
270
|
describe("lint", () => {
|
|
268
|
-
it.todo("should react to changes in config", async () => {
|
|
269
|
-
await createRoot(async () => {
|
|
270
|
-
const repo = await mockRepo();
|
|
271
|
-
const fs = repo.nodeishFs;
|
|
272
|
-
await fs.mkdir("./project.inlang", { recursive: true });
|
|
273
|
-
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(config));
|
|
274
|
-
const project = solidAdapter(await loadProject({
|
|
275
|
-
projectPath: "./project.inlang",
|
|
276
|
-
repo,
|
|
277
|
-
_import: $import,
|
|
278
|
-
}), { from });
|
|
279
|
-
let counter = 0;
|
|
280
|
-
createEffect(() => {
|
|
281
|
-
project.query.messageLintReports.getAll();
|
|
282
|
-
counter += 1;
|
|
283
|
-
});
|
|
284
|
-
const newConfig = { ...project.settings(), languageTags: ["en", "de"] };
|
|
285
|
-
project.setSettings(newConfig);
|
|
286
|
-
expect(counter).toBe(1);
|
|
287
|
-
expect(project.query.messageLintReports.getAll()).toEqual([]);
|
|
288
|
-
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
289
|
-
const newConfig2 = { ...project.settings(), languageTags: ["en", "de", "fr"] };
|
|
290
|
-
project.setSettings(newConfig2);
|
|
291
|
-
expect(counter).toBe(9);
|
|
292
|
-
expect(project.query.messageLintReports.getAll()).toEqual([]);
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
271
|
it.todo("should react to changes to packages");
|
|
296
272
|
it.todo("should react to changes to modules");
|
|
297
|
-
it
|
|
273
|
+
it("should react to changes to messages", async () => {
|
|
298
274
|
await createRoot(async () => {
|
|
299
275
|
const repo = await mockRepo();
|
|
300
276
|
const fs = repo.nodeishFs;
|
|
301
|
-
await fs.
|
|
277
|
+
await fs.mkdir("/user/project.inlang", { recursive: true });
|
|
278
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config));
|
|
302
279
|
const project = solidAdapter(await loadProject({
|
|
303
|
-
projectPath: "
|
|
280
|
+
projectPath: "/user/project.inlang",
|
|
304
281
|
repo,
|
|
305
282
|
_import: $import,
|
|
306
283
|
}), { from });
|
|
284
|
+
const [messages, setMessages] = createSignal();
|
|
307
285
|
let counter = 0;
|
|
308
286
|
createEffect(() => {
|
|
309
|
-
project.query.
|
|
287
|
+
setMessages(project.query.messages.getAll());
|
|
288
|
+
});
|
|
289
|
+
const [lintReports] = createResource(messages, async () => {
|
|
290
|
+
const reports = await project.query.messageLintReports.getAll();
|
|
310
291
|
counter += 1;
|
|
292
|
+
return reports;
|
|
311
293
|
});
|
|
294
|
+
await sleep(10);
|
|
295
|
+
expect(counter).toBe(1);
|
|
296
|
+
expect(lintReports()).toStrictEqual([]);
|
|
312
297
|
project.query.messages.update({
|
|
313
298
|
where: { id: "a" },
|
|
314
299
|
data: {
|
|
@@ -316,9 +301,9 @@ describe("lint", () => {
|
|
|
316
301
|
variants: [{ languageTag: "en", match: [], pattern: [{ type: "Text", value: "new" }] }],
|
|
317
302
|
},
|
|
318
303
|
});
|
|
319
|
-
|
|
320
|
-
expect(
|
|
321
|
-
|
|
304
|
+
await sleep(10);
|
|
305
|
+
expect(counter).toBe(2);
|
|
306
|
+
expect(lintReports()).toStrictEqual([]);
|
|
322
307
|
project.query.messages.update({
|
|
323
308
|
where: { id: "a" },
|
|
324
309
|
data: {
|
|
@@ -326,8 +311,9 @@ describe("lint", () => {
|
|
|
326
311
|
variants: [{ languageTag: "en", match: [], pattern: [{ type: "Text", value: "new" }] }],
|
|
327
312
|
},
|
|
328
313
|
});
|
|
329
|
-
|
|
330
|
-
expect(
|
|
314
|
+
await sleep(10);
|
|
315
|
+
expect(counter).toBe(3);
|
|
316
|
+
expect(lintReports()).toStrictEqual([]);
|
|
331
317
|
});
|
|
332
318
|
});
|
|
333
319
|
});
|
package/dist/api.d.ts
CHANGED
|
@@ -85,17 +85,11 @@ export type MessageQueryApi = {
|
|
|
85
85
|
}) => boolean;
|
|
86
86
|
};
|
|
87
87
|
export type MessageLintReportsQueryApi = {
|
|
88
|
-
getAll:
|
|
89
|
-
get: (
|
|
88
|
+
getAll: () => Promise<MessageLintReport[]>;
|
|
89
|
+
get: (args: {
|
|
90
90
|
where: {
|
|
91
91
|
messageId: MessageLintReport["messageId"];
|
|
92
92
|
};
|
|
93
|
-
}) => Readonly<MessageLintReport[]
|
|
94
|
-
subscribe: (args: {
|
|
95
|
-
where: {
|
|
96
|
-
messageId: MessageLintReport["messageId"];
|
|
97
|
-
};
|
|
98
|
-
}, callback: (MessageLintRules: Readonly<MessageLintReport[]>) => void) => void;
|
|
99
|
-
};
|
|
93
|
+
}) => Promise<Readonly<MessageLintReport[]>>;
|
|
100
94
|
};
|
|
101
95
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMessageLintReportsQuery.d.ts","sourceRoot":"","sources":["../src/createMessageLintReportsQuery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createMessageLintReportsQuery.d.ts","sourceRoot":"","sources":["../src/createMessageLintReportsQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,wBAAwB,EAExB,eAAe,EACf,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAahE;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,aAAa,EAAE,eAAe,EAC9B,QAAQ,EAAE,MAAM,eAAe,EAC/B,yBAAyB,EAAE,MAAM,KAAK,CAAC,wBAAwB,CAAC,EAChE,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAAG,SAAS,GAC3E,aAAa,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CA+F9C"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { createSubscribable } from "./loadProject.js";
|
|
2
1
|
import { lintSingleMessage } from "./lint/index.js";
|
|
3
|
-
import { ReactiveMap } from "./reactivity/map.js";
|
|
4
2
|
import { createRoot, createEffect } from "./reactivity/solid.js";
|
|
3
|
+
import { throttle } from "throttle-debounce";
|
|
4
|
+
import _debug from "debug";
|
|
5
|
+
const debug = _debug("sdk:lintReports");
|
|
6
|
+
function sleep(ms) {
|
|
7
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
|
+
}
|
|
5
9
|
/**
|
|
6
10
|
* Creates a reactive query API for messages.
|
|
7
11
|
*/
|
|
8
12
|
export function createMessageLintReportsQuery(messagesQuery, settings, installedMessageLintRules, resolvedModules) {
|
|
9
|
-
|
|
10
|
-
const index = new ReactiveMap();
|
|
13
|
+
const index = new Map();
|
|
11
14
|
const modules = resolvedModules();
|
|
12
15
|
const rulesArray = modules?.messageLintRules;
|
|
13
16
|
const messageLintRuleLevels = Object.fromEntries(installedMessageLintRules().map((rule) => [rule.id, rule.level]));
|
|
@@ -19,6 +22,12 @@ export function createMessageLintReportsQuery(messagesQuery, settings, installed
|
|
|
19
22
|
};
|
|
20
23
|
const messages = messagesQuery.getAll();
|
|
21
24
|
const trackedMessages = new Map();
|
|
25
|
+
debug(`createMessageLintReportsQuery ${rulesArray?.length} rules, ${messages.length} messages`);
|
|
26
|
+
// TODO: don't throttle when no debug
|
|
27
|
+
let lintMessageCount = 0;
|
|
28
|
+
const throttledLogLintMessage = throttle(2000, (messageId) => {
|
|
29
|
+
debug(`lintSingleMessage: ${lintMessageCount} id: ${messageId}`);
|
|
30
|
+
});
|
|
22
31
|
createEffect(() => {
|
|
23
32
|
const currentMessageIds = new Set(messagesQuery.includedMessageIds());
|
|
24
33
|
const deletedTrackedMessages = [...trackedMessages].filter((tracked) => !currentMessageIds.has(tracked[0]));
|
|
@@ -41,7 +50,10 @@ export function createMessageLintReportsQuery(messagesQuery, settings, installed
|
|
|
41
50
|
messages: messages,
|
|
42
51
|
message: message,
|
|
43
52
|
}).then((report) => {
|
|
53
|
+
lintMessageCount++;
|
|
54
|
+
throttledLogLintMessage(messageId);
|
|
44
55
|
if (report.errors.length === 0 && index.get(messageId) !== report.data) {
|
|
56
|
+
// console.log("lintSingleMessage", messageId, report.data.length)
|
|
45
57
|
index.set(messageId, report.data);
|
|
46
58
|
}
|
|
47
59
|
});
|
|
@@ -58,19 +70,19 @@ export function createMessageLintReportsQuery(messagesQuery, settings, installed
|
|
|
58
70
|
trackedMessages.delete(deletedMessageId);
|
|
59
71
|
// remove lint report result
|
|
60
72
|
index.delete(deletedMessageId);
|
|
73
|
+
debug(`delete lint message id: ${deletedMessageId}`);
|
|
61
74
|
}
|
|
62
75
|
}
|
|
63
76
|
}
|
|
64
77
|
});
|
|
65
|
-
const get = (args) => {
|
|
66
|
-
return structuredClone(index.get(args.where.messageId));
|
|
67
|
-
};
|
|
68
78
|
return {
|
|
69
|
-
getAll:
|
|
79
|
+
getAll: async () => {
|
|
80
|
+
await sleep(0); // evaluate on next tick to allow for out-of-order effects
|
|
70
81
|
return structuredClone([...index.values()].flat().length === 0 ? [] : [...index.values()].flat());
|
|
71
|
-
}
|
|
72
|
-
get:
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
},
|
|
83
|
+
get: async (args) => {
|
|
84
|
+
await sleep(0); // evaluate on next tick to allow for out-of-order effects
|
|
85
|
+
return structuredClone(index.get(args.where.messageId) ?? []);
|
|
86
|
+
},
|
|
75
87
|
};
|
|
76
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadProject.d.ts","sourceRoot":"","sources":["../src/loadProject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EAGb,YAAY,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,4BAA4B,CAAA;AAyBhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAgChD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,cAAc,CAAA;CACxB,GAAG,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"loadProject.d.ts","sourceRoot":"","sources":["../src/loadProject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EAGb,YAAY,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,4BAA4B,CAAA;AAyBhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAgChD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,cAAc,CAAA;CACxB,GAAG,OAAO,CAAC,aAAa,CAAC,CAqYzB;AAsHD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
|
package/dist/loadProject.js
CHANGED
|
@@ -49,20 +49,19 @@ export async function loadProject(args) {
|
|
|
49
49
|
else if (/[^\\/]+\.inlang$/.test(projectPath) === false) {
|
|
50
50
|
throw new LoadProjectInvalidArgument(`Expected a path ending in "{name}.inlang" but received "${projectPath}".\n\nValid examples: \n- "/path/to/micky-mouse.inlang"\n- "/path/to/green-elephant.inlang\n`, { argument: "projectPath" });
|
|
51
51
|
}
|
|
52
|
-
const fs = args.repo.nodeishFs;
|
|
53
52
|
const nodeishFs = createNodeishFsWithAbsolutePaths({
|
|
54
53
|
projectPath,
|
|
55
|
-
nodeishFs:
|
|
54
|
+
nodeishFs: args.repo.nodeishFs,
|
|
56
55
|
});
|
|
57
56
|
// -- migratations ------------------------------------------------
|
|
58
|
-
await maybeMigrateToDirectory({ nodeishFs
|
|
57
|
+
await maybeMigrateToDirectory({ nodeishFs, projectPath });
|
|
59
58
|
await maybeCreateFirstProjectId({ projectPath, repo: args.repo });
|
|
60
59
|
// -- load project ------------------------------------------------------
|
|
61
60
|
return await createRoot(async () => {
|
|
62
61
|
// TODO remove tryCatch after https://github.com/opral/monorepo/issues/2013
|
|
63
62
|
// - a repo will always be present
|
|
64
63
|
// - if a repo is present, the project id will always be present
|
|
65
|
-
const { data: projectId } = await tryCatch(() =>
|
|
64
|
+
const { data: projectId } = await tryCatch(() => nodeishFs.readFile(args.projectPath + "/project_id", { encoding: "utf-8" }));
|
|
66
65
|
const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable();
|
|
67
66
|
// -- settings ------------------------------------------------------------
|
|
68
67
|
const [settings, _setSettings] = createSignal();
|
|
@@ -219,7 +218,7 @@ export async function loadProject(args) {
|
|
|
219
218
|
// don't trigger saves or set dirty flags during initial setup
|
|
220
219
|
if (!initialSetup) {
|
|
221
220
|
messageStates.messageDirtyFlags[message.id] = true;
|
|
222
|
-
saveMessagesViaPlugin(
|
|
221
|
+
saveMessagesViaPlugin(nodeishFs, messageLockDirPath, messageStates, messagesQuery, settings(), saveMessagesPlugin, loadMessagesPlugin)
|
|
223
222
|
.catch((e) => setSaveMessagesViaPluginError(new PluginSaveMessagesError({ cause: e })))
|
|
224
223
|
.then(() => {
|
|
225
224
|
if (saveMessagesViaPluginError() !== undefined) {
|
|
@@ -628,7 +627,7 @@ async function saveMessagesViaPlugin(fs, lockDirPath, messageState, messagesQuer
|
|
|
628
627
|
});
|
|
629
628
|
}
|
|
630
629
|
}
|
|
631
|
-
const maxRetries =
|
|
630
|
+
const maxRetries = 10;
|
|
632
631
|
const nProbes = 50;
|
|
633
632
|
const probeInterval = 100;
|
|
634
633
|
async function acquireFileLock(fs, lockDirPath, lockOrigin, tryCount = 0) {
|
package/dist/loadProject.test.js
CHANGED
|
@@ -515,8 +515,8 @@ describe("functionality", () => {
|
|
|
515
515
|
_import,
|
|
516
516
|
});
|
|
517
517
|
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
518
|
-
expect(project.query.messageLintReports.getAll()).toHaveLength(1);
|
|
519
|
-
expect(project.query.messageLintReports.getAll()?.[0]?.ruleId).toBe(_mockLintRule.id);
|
|
518
|
+
expect(await project.query.messageLintReports.getAll()).toHaveLength(1);
|
|
519
|
+
expect((await project.query.messageLintReports.getAll())?.[0]?.ruleId).toBe(_mockLintRule.id);
|
|
520
520
|
expect(project.installed.messageLintRules()).toHaveLength(1);
|
|
521
521
|
});
|
|
522
522
|
it("should return lint reports for a single message", async () => {
|
|
@@ -558,7 +558,7 @@ describe("functionality", () => {
|
|
|
558
558
|
_import,
|
|
559
559
|
});
|
|
560
560
|
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
561
|
-
expect(project.query.messageLintReports.get({ where: { messageId: "some-message" } })).toHaveLength(1);
|
|
561
|
+
expect(await project.query.messageLintReports.get({ where: { messageId: "some-message" } })).toHaveLength(1);
|
|
562
562
|
});
|
|
563
563
|
});
|
|
564
564
|
describe("errors", () => {
|
|
@@ -852,7 +852,8 @@ describe("functionality", () => {
|
|
|
852
852
|
});
|
|
853
853
|
// TODO: test with real lint rules
|
|
854
854
|
try {
|
|
855
|
-
project.query.messageLintReports.getAll
|
|
855
|
+
const r = await project.query.messageLintReports.getAll();
|
|
856
|
+
expect(r).toEqual(undefined);
|
|
856
857
|
throw new Error("Should not reach this");
|
|
857
858
|
}
|
|
858
859
|
catch (e) {
|
|
@@ -877,7 +878,8 @@ describe("functionality", () => {
|
|
|
877
878
|
}),
|
|
878
879
|
});
|
|
879
880
|
// TODO: test with real lint rules
|
|
880
|
-
project.query.messageLintReports.getAll
|
|
881
|
+
const r = await project.query.messageLintReports.getAll();
|
|
882
|
+
expect(r).toEqual([]);
|
|
881
883
|
});
|
|
882
884
|
});
|
|
883
885
|
describe("watcher", () => {
|
|
@@ -3,10 +3,11 @@ declare const createSignal: typeof import("solid-js").createSignal;
|
|
|
3
3
|
declare const createMemo: typeof import("solid-js").createMemo;
|
|
4
4
|
declare const createRoot: typeof import("solid-js").createRoot;
|
|
5
5
|
declare const createEffect: typeof import("solid-js").createEffect;
|
|
6
|
+
declare const createResource: typeof import("solid-js").createResource;
|
|
6
7
|
declare const observable: typeof import("solid-js").observable;
|
|
7
8
|
declare const from: typeof import("solid-js").from;
|
|
8
9
|
declare const batch: typeof import("solid-js").batch;
|
|
9
10
|
declare const getListener: typeof import("solid-js").getListener;
|
|
10
11
|
declare const onCleanup: typeof import("solid-js").onCleanup;
|
|
11
|
-
export { createSignal, createMemo, createRoot, createEffect, observable, from, batch, getListener, onCleanup, DEV, };
|
|
12
|
+
export { createSignal, createMemo, createRoot, createEffect, createResource, observable, from, batch, getListener, onCleanup, DEV, };
|
|
12
13
|
//# sourceMappingURL=solid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../../src/reactivity/solid.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../../src/reactivity/solid.ts"],"names":[],"mappings":"AAAA,OAAO,EAWN,GAAG,EAEH,MAAM,wBAAwB,CAAA;AAE/B,QAAA,MAAM,YAAY,wCAA6D,CAAA;AAC/E,QAAA,MAAM,UAAU,sCAAyD,CAAA;AACzE,QAAA,MAAM,UAAU,sCAAyD,CAAA;AACzE,QAAA,MAAM,YAAY,wCAA6D,CAAA;AAC/E,QAAA,MAAM,cAAc,0CAAiE,CAAA;AACrF,QAAA,MAAM,UAAU,sCAAyD,CAAA;AACzE,QAAA,MAAM,IAAI,gCAA6C,CAAA;AACvD,QAAA,MAAM,KAAK,iCAA+C,CAAA;AAC1D,QAAA,MAAM,WAAW,uCAA2D,CAAA;AAC5E,QAAA,MAAM,SAAS,qCAAuD,CAAA;AAEtE,OAAO,EACN,YAAY,EACZ,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,UAAU,EACV,IAAI,EACJ,KAAK,EACL,WAAW,EACX,SAAS,EACT,GAAG,GACH,CAAA"}
|
package/dist/reactivity/solid.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { createSignal as _createSignal, createMemo as _createMemo, createRoot as _createRoot, createEffect as _createEffect, observable as _observable, batch as _batch, from as _from, getListener as _getListener, onCleanup as _onCleanup, DEV,
|
|
1
|
+
import { createSignal as _createSignal, createMemo as _createMemo, createRoot as _createRoot, createEffect as _createEffect, createResource as _createResource, observable as _observable, batch as _batch, from as _from, getListener as _getListener, onCleanup as _onCleanup, DEV,
|
|
2
2
|
// @ts-ignore
|
|
3
3
|
} from "solid-js/dist/solid.js";
|
|
4
4
|
const createSignal = _createSignal;
|
|
5
5
|
const createMemo = _createMemo;
|
|
6
6
|
const createRoot = _createRoot;
|
|
7
7
|
const createEffect = _createEffect;
|
|
8
|
+
const createResource = _createResource;
|
|
8
9
|
const observable = _observable;
|
|
9
10
|
const from = _from;
|
|
10
11
|
const batch = _batch;
|
|
11
12
|
const getListener = _getListener;
|
|
12
13
|
const onCleanup = _onCleanup;
|
|
13
|
-
export { createSignal, createMemo, createRoot, createEffect, observable, from, batch, getListener, onCleanup, DEV, };
|
|
14
|
+
export { createSignal, createMemo, createRoot, createEffect, createResource, observable, from, batch, getListener, onCleanup, DEV, };
|
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { createSignal, createEffect, createMemo } from "./solid.js";
|
|
2
|
+
import { createRoot, createSignal, createEffect, createMemo, createResource } from "./solid.js";
|
|
3
3
|
function sleep(ms) {
|
|
4
4
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
5
|
}
|
|
6
|
+
function delay(v, ms) {
|
|
7
|
+
return new Promise((resolve) => setTimeout(() => resolve(v), ms));
|
|
8
|
+
}
|
|
9
|
+
describe("vitest", () => {
|
|
10
|
+
it("waits for the result of an async function", async () => {
|
|
11
|
+
const rval = await delay(42, 1);
|
|
12
|
+
expect(rval).toBe(42);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
6
15
|
describe("solid", () => {
|
|
16
|
+
it("await createRoot returns the result the async function", async () => {
|
|
17
|
+
let count = 0;
|
|
18
|
+
await sleep(0);
|
|
19
|
+
const rval = await createRoot(async () => {
|
|
20
|
+
await sleep(0);
|
|
21
|
+
count++;
|
|
22
|
+
return await delay(42, 1);
|
|
23
|
+
});
|
|
24
|
+
expect(rval).toBe(42);
|
|
25
|
+
expect(count).toBe(1);
|
|
26
|
+
});
|
|
7
27
|
it("sets and gets", () => {
|
|
8
28
|
const [get, set] = createSignal(0);
|
|
9
29
|
expect(get()).toBe(0);
|
|
@@ -84,6 +104,32 @@ describe("solid", () => {
|
|
|
84
104
|
set(1);
|
|
85
105
|
expect(count).toBe(2);
|
|
86
106
|
});
|
|
107
|
+
it("Resource async fetch is triggered by signals, and works in effects", async () => {
|
|
108
|
+
const [get, set] = createSignal(0);
|
|
109
|
+
const [resource] = createResource(get, async (v) => {
|
|
110
|
+
return (await delay(v, 10));
|
|
111
|
+
});
|
|
112
|
+
let count = 0;
|
|
113
|
+
createEffect(() => {
|
|
114
|
+
count++;
|
|
115
|
+
resource();
|
|
116
|
+
});
|
|
117
|
+
expect(resource.loading).toBe(true);
|
|
118
|
+
expect(resource()).toBe(undefined);
|
|
119
|
+
expect(count).toBe(1);
|
|
120
|
+
await sleep(20);
|
|
121
|
+
expect(resource.loading).toBe(false);
|
|
122
|
+
expect(resource()).toBe(0);
|
|
123
|
+
expect(count).toBe(2);
|
|
124
|
+
set(42);
|
|
125
|
+
expect(resource.loading).toBe(true);
|
|
126
|
+
expect(resource()).toBe(0);
|
|
127
|
+
expect(count).toBe(2);
|
|
128
|
+
await sleep(20);
|
|
129
|
+
expect(resource.loading).toBe(false);
|
|
130
|
+
expect(resource()).toBe(42);
|
|
131
|
+
expect(count).toBe(3);
|
|
132
|
+
});
|
|
87
133
|
it("memoizes values and updates them when signals change", () => {
|
|
88
134
|
const [get, set] = createSignal(0);
|
|
89
135
|
let count = 0;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.30.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
"solid-js": "1.6.12",
|
|
34
34
|
"throttle-debounce": "^5.0.0",
|
|
35
35
|
"@inlang/json-types": "1.1.0",
|
|
36
|
+
"@inlang/language-tag": "1.5.1",
|
|
36
37
|
"@inlang/message": "2.1.0",
|
|
37
38
|
"@inlang/message-lint-rule": "1.4.5",
|
|
38
|
-
"@inlang/language-tag": "1.5.1",
|
|
39
39
|
"@inlang/module": "1.2.9",
|
|
40
|
-
"@inlang/plugin": "2.4.9",
|
|
41
40
|
"@inlang/project-settings": "2.4.0",
|
|
42
|
-
"@inlang/
|
|
41
|
+
"@inlang/plugin": "2.4.9",
|
|
43
42
|
"@inlang/translatable": "1.3.1",
|
|
43
|
+
"@inlang/result": "1.1.0",
|
|
44
44
|
"@lix-js/client": "1.2.0",
|
|
45
45
|
"@lix-js/fs": "1.0.0"
|
|
46
46
|
},
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
2
|
import { describe, it, expect } from "vitest"
|
|
3
3
|
import type { ImportFunction } from "../resolve-modules/index.js"
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createResource,
|
|
6
|
+
createSignal,
|
|
7
|
+
createEffect,
|
|
8
|
+
from,
|
|
9
|
+
createRoot,
|
|
10
|
+
} from "../reactivity/solid.js"
|
|
5
11
|
import { solidAdapter } from "./solidAdapter.js"
|
|
6
12
|
import { loadProject } from "../loadProject.js"
|
|
7
13
|
import { mockRepo } from "@lix-js/client"
|
|
@@ -13,6 +19,10 @@ import type {
|
|
|
13
19
|
Text,
|
|
14
20
|
} from "../versionedInterfaces.js"
|
|
15
21
|
|
|
22
|
+
function sleep(ms: number) {
|
|
23
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
// ------------------------------------------------------------------------------------------------
|
|
17
27
|
|
|
18
28
|
const config: ProjectSettings = {
|
|
@@ -353,66 +363,42 @@ describe("messages", () => {
|
|
|
353
363
|
})
|
|
354
364
|
|
|
355
365
|
describe("lint", () => {
|
|
356
|
-
it.todo("should react to changes in config", async () => {
|
|
357
|
-
await createRoot(async () => {
|
|
358
|
-
const repo = await mockRepo()
|
|
359
|
-
const fs = repo.nodeishFs
|
|
360
|
-
await fs.mkdir("./project.inlang", { recursive: true })
|
|
361
|
-
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(config))
|
|
362
|
-
const project = solidAdapter(
|
|
363
|
-
await loadProject({
|
|
364
|
-
projectPath: "./project.inlang",
|
|
365
|
-
repo,
|
|
366
|
-
_import: $import,
|
|
367
|
-
}),
|
|
368
|
-
{ from }
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
let counter = 0
|
|
372
|
-
createEffect(() => {
|
|
373
|
-
project.query.messageLintReports.getAll()
|
|
374
|
-
counter += 1
|
|
375
|
-
})
|
|
376
|
-
|
|
377
|
-
const newConfig = { ...project.settings()!, languageTags: ["en", "de"] }
|
|
378
|
-
project.setSettings(newConfig)
|
|
379
|
-
|
|
380
|
-
expect(counter).toBe(1)
|
|
381
|
-
expect(project.query.messageLintReports.getAll()).toEqual([])
|
|
382
|
-
|
|
383
|
-
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
384
|
-
|
|
385
|
-
const newConfig2 = { ...project.settings()!, languageTags: ["en", "de", "fr"] }
|
|
386
|
-
project.setSettings(newConfig2)
|
|
387
|
-
|
|
388
|
-
expect(counter).toBe(9)
|
|
389
|
-
expect(project.query.messageLintReports.getAll()).toEqual([])
|
|
390
|
-
})
|
|
391
|
-
})
|
|
392
|
-
|
|
393
366
|
it.todo("should react to changes to packages")
|
|
394
367
|
it.todo("should react to changes to modules")
|
|
395
368
|
|
|
396
|
-
it
|
|
369
|
+
it("should react to changes to messages", async () => {
|
|
397
370
|
await createRoot(async () => {
|
|
398
371
|
const repo = await mockRepo()
|
|
399
372
|
const fs = repo.nodeishFs
|
|
400
|
-
await fs.
|
|
373
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
374
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config))
|
|
401
375
|
const project = solidAdapter(
|
|
402
376
|
await loadProject({
|
|
403
|
-
projectPath: "
|
|
377
|
+
projectPath: "/user/project.inlang",
|
|
404
378
|
repo,
|
|
405
379
|
_import: $import,
|
|
406
380
|
}),
|
|
407
381
|
{ from }
|
|
408
382
|
)
|
|
409
383
|
|
|
384
|
+
const [messages, setMessages] = createSignal<readonly Message[]>()
|
|
385
|
+
|
|
410
386
|
let counter = 0
|
|
387
|
+
|
|
411
388
|
createEffect(() => {
|
|
412
|
-
project.query.
|
|
389
|
+
setMessages(project.query.messages.getAll())
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
const [lintReports] = createResource(messages, async () => {
|
|
393
|
+
const reports = await project.query.messageLintReports.getAll()
|
|
413
394
|
counter += 1
|
|
395
|
+
return reports
|
|
414
396
|
})
|
|
415
397
|
|
|
398
|
+
await sleep(10)
|
|
399
|
+
expect(counter).toBe(1)
|
|
400
|
+
expect(lintReports()).toStrictEqual([])
|
|
401
|
+
|
|
416
402
|
project.query.messages.update({
|
|
417
403
|
where: { id: "a" },
|
|
418
404
|
data: {
|
|
@@ -421,10 +407,9 @@ describe("lint", () => {
|
|
|
421
407
|
},
|
|
422
408
|
})
|
|
423
409
|
|
|
424
|
-
|
|
425
|
-
expect(
|
|
426
|
-
|
|
427
|
-
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
410
|
+
await sleep(10)
|
|
411
|
+
expect(counter).toBe(2)
|
|
412
|
+
expect(lintReports()).toStrictEqual([])
|
|
428
413
|
|
|
429
414
|
project.query.messages.update({
|
|
430
415
|
where: { id: "a" },
|
|
@@ -434,8 +419,9 @@ describe("lint", () => {
|
|
|
434
419
|
},
|
|
435
420
|
})
|
|
436
421
|
|
|
437
|
-
|
|
438
|
-
expect(
|
|
422
|
+
await sleep(10)
|
|
423
|
+
expect(counter).toBe(3)
|
|
424
|
+
expect(lintReports()).toStrictEqual([])
|
|
439
425
|
})
|
|
440
426
|
})
|
|
441
427
|
})
|
|
@@ -39,7 +39,7 @@ export const solidAdapter = (
|
|
|
39
39
|
},
|
|
40
40
|
messageLintReports: {
|
|
41
41
|
get: project.query.messageLintReports.get,
|
|
42
|
-
getAll:
|
|
42
|
+
getAll: project.query.messageLintReports.getAll,
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
45
|
} satisfies InlangProjectWithSolidAdapter
|
package/src/api.ts
CHANGED
|
@@ -89,13 +89,8 @@ export type MessageQueryApi = {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
export type MessageLintReportsQueryApi = {
|
|
92
|
-
getAll:
|
|
93
|
-
get: (
|
|
92
|
+
getAll: () => Promise<MessageLintReport[]>
|
|
93
|
+
get: (args: {
|
|
94
94
|
where: { messageId: MessageLintReport["messageId"] }
|
|
95
|
-
}) => Readonly<MessageLintReport[]
|
|
96
|
-
subscribe: (
|
|
97
|
-
args: { where: { messageId: MessageLintReport["messageId"] } },
|
|
98
|
-
callback: (MessageLintRules: Readonly<MessageLintReport[]>) => void
|
|
99
|
-
) => void
|
|
100
|
-
}
|
|
95
|
+
}) => Promise<Readonly<MessageLintReport[]>>
|
|
101
96
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createSubscribable } from "./loadProject.js"
|
|
2
1
|
import type {
|
|
3
2
|
InlangProject,
|
|
4
3
|
InstalledMessageLintRule,
|
|
@@ -9,9 +8,16 @@ import type { ProjectSettings } from "@inlang/project-settings"
|
|
|
9
8
|
import type { resolveModules } from "./resolve-modules/index.js"
|
|
10
9
|
import type { MessageLintReport, Message } from "./versionedInterfaces.js"
|
|
11
10
|
import { lintSingleMessage } from "./lint/index.js"
|
|
12
|
-
import { ReactiveMap } from "./reactivity/map.js"
|
|
13
11
|
import { createRoot, createEffect } from "./reactivity/solid.js"
|
|
14
12
|
|
|
13
|
+
import { throttle } from "throttle-debounce"
|
|
14
|
+
import _debug from "debug"
|
|
15
|
+
const debug = _debug("sdk:lintReports")
|
|
16
|
+
|
|
17
|
+
function sleep(ms: number) {
|
|
18
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
/**
|
|
16
22
|
* Creates a reactive query API for messages.
|
|
17
23
|
*/
|
|
@@ -21,8 +27,7 @@ export function createMessageLintReportsQuery(
|
|
|
21
27
|
installedMessageLintRules: () => Array<InstalledMessageLintRule>,
|
|
22
28
|
resolvedModules: () => Awaited<ReturnType<typeof resolveModules>> | undefined
|
|
23
29
|
): InlangProject["query"]["messageLintReports"] {
|
|
24
|
-
|
|
25
|
-
const index = new ReactiveMap<MessageLintReport["messageId"], MessageLintReport[]>()
|
|
30
|
+
const index = new Map<MessageLintReport["messageId"], MessageLintReport[]>()
|
|
26
31
|
|
|
27
32
|
const modules = resolvedModules()
|
|
28
33
|
|
|
@@ -41,6 +46,14 @@ export function createMessageLintReportsQuery(
|
|
|
41
46
|
|
|
42
47
|
const trackedMessages: Map<string, () => void> = new Map()
|
|
43
48
|
|
|
49
|
+
debug(`createMessageLintReportsQuery ${rulesArray?.length} rules, ${messages.length} messages`)
|
|
50
|
+
|
|
51
|
+
// TODO: don't throttle when no debug
|
|
52
|
+
let lintMessageCount = 0
|
|
53
|
+
const throttledLogLintMessage = throttle(2000, (messageId) => {
|
|
54
|
+
debug(`lintSingleMessage: ${lintMessageCount} id: ${messageId}`)
|
|
55
|
+
})
|
|
56
|
+
|
|
44
57
|
createEffect(() => {
|
|
45
58
|
const currentMessageIds = new Set(messagesQuery.includedMessageIds())
|
|
46
59
|
|
|
@@ -68,7 +81,10 @@ export function createMessageLintReportsQuery(
|
|
|
68
81
|
messages: messages,
|
|
69
82
|
message: message,
|
|
70
83
|
}).then((report) => {
|
|
84
|
+
lintMessageCount++
|
|
85
|
+
throttledLogLintMessage(messageId)
|
|
71
86
|
if (report.errors.length === 0 && index.get(messageId) !== report.data) {
|
|
87
|
+
// console.log("lintSingleMessage", messageId, report.data.length)
|
|
72
88
|
index.set(messageId, report.data)
|
|
73
89
|
}
|
|
74
90
|
})
|
|
@@ -87,26 +103,22 @@ export function createMessageLintReportsQuery(
|
|
|
87
103
|
trackedMessages.delete(deletedMessageId)
|
|
88
104
|
// remove lint report result
|
|
89
105
|
index.delete(deletedMessageId)
|
|
106
|
+
debug(`delete lint message id: ${deletedMessageId}`)
|
|
90
107
|
}
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
})
|
|
94
111
|
|
|
95
|
-
const get = (args: Parameters<MessageLintReportsQueryApi["get"]>[0]) => {
|
|
96
|
-
return structuredClone(index.get(args.where.messageId))
|
|
97
|
-
}
|
|
98
|
-
|
|
99
112
|
return {
|
|
100
|
-
getAll:
|
|
113
|
+
getAll: async () => {
|
|
114
|
+
await sleep(0) // evaluate on next tick to allow for out-of-order effects
|
|
101
115
|
return structuredClone(
|
|
102
116
|
[...index.values()].flat().length === 0 ? [] : [...index.values()].flat()
|
|
103
117
|
)
|
|
104
|
-
}
|
|
105
|
-
get:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
) => createSubscribable(() => get(args)).subscribe(callback),
|
|
110
|
-
}) as any,
|
|
118
|
+
},
|
|
119
|
+
get: async (args: Parameters<MessageLintReportsQueryApi["get"]>[0]) => {
|
|
120
|
+
await sleep(0) // evaluate on next tick to allow for out-of-order effects
|
|
121
|
+
return structuredClone(index.get(args.where.messageId) ?? [])
|
|
122
|
+
},
|
|
111
123
|
}
|
|
112
124
|
}
|
package/src/loadProject.test.ts
CHANGED
|
@@ -634,8 +634,8 @@ describe("functionality", () => {
|
|
|
634
634
|
|
|
635
635
|
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
636
636
|
|
|
637
|
-
expect(project.query.messageLintReports.getAll()).toHaveLength(1)
|
|
638
|
-
expect(project.query.messageLintReports.getAll()?.[0]?.ruleId).toBe(_mockLintRule.id)
|
|
637
|
+
expect(await project.query.messageLintReports.getAll()).toHaveLength(1)
|
|
638
|
+
expect((await project.query.messageLintReports.getAll())?.[0]?.ruleId).toBe(_mockLintRule.id)
|
|
639
639
|
expect(project.installed.messageLintRules()).toHaveLength(1)
|
|
640
640
|
})
|
|
641
641
|
|
|
@@ -687,7 +687,7 @@ describe("functionality", () => {
|
|
|
687
687
|
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
688
688
|
|
|
689
689
|
expect(
|
|
690
|
-
project.query.messageLintReports.get({ where: { messageId: "some-message" } })
|
|
690
|
+
await project.query.messageLintReports.get({ where: { messageId: "some-message" } })
|
|
691
691
|
).toHaveLength(1)
|
|
692
692
|
})
|
|
693
693
|
})
|
|
@@ -1025,7 +1025,8 @@ describe("functionality", () => {
|
|
|
1025
1025
|
})
|
|
1026
1026
|
// TODO: test with real lint rules
|
|
1027
1027
|
try {
|
|
1028
|
-
project.query.messageLintReports.getAll
|
|
1028
|
+
const r = await project.query.messageLintReports.getAll()
|
|
1029
|
+
expect(r).toEqual(undefined)
|
|
1029
1030
|
throw new Error("Should not reach this")
|
|
1030
1031
|
} catch (e) {
|
|
1031
1032
|
expect((e as Error).message).toBe("lint not initialized yet")
|
|
@@ -1049,7 +1050,8 @@ describe("functionality", () => {
|
|
|
1049
1050
|
}),
|
|
1050
1051
|
})
|
|
1051
1052
|
// TODO: test with real lint rules
|
|
1052
|
-
project.query.messageLintReports.getAll
|
|
1053
|
+
const r = await project.query.messageLintReports.getAll()
|
|
1054
|
+
expect(r).toEqual([])
|
|
1053
1055
|
})
|
|
1054
1056
|
})
|
|
1055
1057
|
|
package/src/loadProject.ts
CHANGED
|
@@ -105,16 +105,14 @@ export async function loadProject(args: {
|
|
|
105
105
|
)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const fs = args.repo.nodeishFs
|
|
109
|
-
|
|
110
108
|
const nodeishFs = createNodeishFsWithAbsolutePaths({
|
|
111
109
|
projectPath,
|
|
112
|
-
nodeishFs:
|
|
110
|
+
nodeishFs: args.repo.nodeishFs,
|
|
113
111
|
})
|
|
114
112
|
|
|
115
113
|
// -- migratations ------------------------------------------------
|
|
116
114
|
|
|
117
|
-
await maybeMigrateToDirectory({ nodeishFs
|
|
115
|
+
await maybeMigrateToDirectory({ nodeishFs, projectPath })
|
|
118
116
|
await maybeCreateFirstProjectId({ projectPath, repo: args.repo })
|
|
119
117
|
|
|
120
118
|
// -- load project ------------------------------------------------------
|
|
@@ -124,7 +122,7 @@ export async function loadProject(args: {
|
|
|
124
122
|
// - a repo will always be present
|
|
125
123
|
// - if a repo is present, the project id will always be present
|
|
126
124
|
const { data: projectId } = await tryCatch(() =>
|
|
127
|
-
|
|
125
|
+
nodeishFs.readFile(args.projectPath + "/project_id", { encoding: "utf-8" })
|
|
128
126
|
)
|
|
129
127
|
|
|
130
128
|
const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable()
|
|
@@ -348,7 +346,7 @@ export async function loadProject(args: {
|
|
|
348
346
|
if (!initialSetup) {
|
|
349
347
|
messageStates.messageDirtyFlags[message.id] = true
|
|
350
348
|
saveMessagesViaPlugin(
|
|
351
|
-
|
|
349
|
+
nodeishFs,
|
|
352
350
|
messageLockDirPath,
|
|
353
351
|
messageStates,
|
|
354
352
|
messagesQuery,
|
|
@@ -901,7 +899,7 @@ async function saveMessagesViaPlugin(
|
|
|
901
899
|
}
|
|
902
900
|
}
|
|
903
901
|
|
|
904
|
-
const maxRetries =
|
|
902
|
+
const maxRetries = 10
|
|
905
903
|
const nProbes = 50
|
|
906
904
|
const probeInterval = 100
|
|
907
905
|
async function acquireFileLock(
|
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest"
|
|
2
|
-
import { createSignal, createEffect, createMemo } from "./solid.js"
|
|
2
|
+
import { createRoot, createSignal, createEffect, createMemo, createResource } from "./solid.js"
|
|
3
3
|
|
|
4
4
|
function sleep(ms: number) {
|
|
5
5
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
function delay(v: unknown, ms: number) {
|
|
9
|
+
return new Promise((resolve) => setTimeout(() => resolve(v), ms))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe("vitest", () => {
|
|
13
|
+
it("waits for the result of an async function", async () => {
|
|
14
|
+
const rval = await delay(42, 1)
|
|
15
|
+
expect(rval).toBe(42)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
8
19
|
describe("solid", () => {
|
|
20
|
+
it("await createRoot returns the result the async function", async () => {
|
|
21
|
+
let count = 0
|
|
22
|
+
await sleep(0)
|
|
23
|
+
const rval = await createRoot(async () => {
|
|
24
|
+
await sleep(0)
|
|
25
|
+
count++
|
|
26
|
+
return await delay(42, 1)
|
|
27
|
+
})
|
|
28
|
+
expect(rval).toBe(42)
|
|
29
|
+
expect(count).toBe(1)
|
|
30
|
+
})
|
|
31
|
+
|
|
9
32
|
it("sets and gets", () => {
|
|
10
33
|
const [get, set] = createSignal(0)
|
|
11
34
|
|
|
@@ -93,6 +116,39 @@ describe("solid", () => {
|
|
|
93
116
|
expect(count).toBe(2)
|
|
94
117
|
})
|
|
95
118
|
|
|
119
|
+
it("Resource async fetch is triggered by signals, and works in effects", async () => {
|
|
120
|
+
const [get, set] = createSignal<number>(0)
|
|
121
|
+
|
|
122
|
+
const [resource] = createResource(get, async (v) => {
|
|
123
|
+
return (await delay(v, 10)) as number
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
let count = 0
|
|
127
|
+
createEffect(() => {
|
|
128
|
+
count++
|
|
129
|
+
resource()
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
expect(resource.loading).toBe(true)
|
|
133
|
+
expect(resource()).toBe(undefined)
|
|
134
|
+
expect(count).toBe(1)
|
|
135
|
+
|
|
136
|
+
await sleep(20)
|
|
137
|
+
expect(resource.loading).toBe(false)
|
|
138
|
+
expect(resource()).toBe(0)
|
|
139
|
+
expect(count).toBe(2)
|
|
140
|
+
|
|
141
|
+
set(42)
|
|
142
|
+
expect(resource.loading).toBe(true)
|
|
143
|
+
expect(resource()).toBe(0)
|
|
144
|
+
expect(count).toBe(2)
|
|
145
|
+
|
|
146
|
+
await sleep(20)
|
|
147
|
+
expect(resource.loading).toBe(false)
|
|
148
|
+
expect(resource()).toBe(42)
|
|
149
|
+
expect(count).toBe(3)
|
|
150
|
+
})
|
|
151
|
+
|
|
96
152
|
it("memoizes values and updates them when signals change", () => {
|
|
97
153
|
const [get, set] = createSignal(0)
|
|
98
154
|
let count = 0
|
package/src/reactivity/solid.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
createMemo as _createMemo,
|
|
4
4
|
createRoot as _createRoot,
|
|
5
5
|
createEffect as _createEffect,
|
|
6
|
+
createResource as _createResource,
|
|
6
7
|
observable as _observable,
|
|
7
8
|
batch as _batch,
|
|
8
9
|
from as _from,
|
|
@@ -16,6 +17,7 @@ const createSignal = _createSignal as typeof import("solid-js")["createSignal"]
|
|
|
16
17
|
const createMemo = _createMemo as typeof import("solid-js")["createMemo"]
|
|
17
18
|
const createRoot = _createRoot as typeof import("solid-js")["createRoot"]
|
|
18
19
|
const createEffect = _createEffect as typeof import("solid-js")["createEffect"]
|
|
20
|
+
const createResource = _createResource as typeof import("solid-js")["createResource"]
|
|
19
21
|
const observable = _observable as typeof import("solid-js")["observable"]
|
|
20
22
|
const from = _from as typeof import("solid-js")["from"]
|
|
21
23
|
const batch = _batch as typeof import("solid-js")["batch"]
|
|
@@ -27,6 +29,7 @@ export {
|
|
|
27
29
|
createMemo,
|
|
28
30
|
createRoot,
|
|
29
31
|
createEffect,
|
|
32
|
+
createResource,
|
|
30
33
|
observable,
|
|
31
34
|
from,
|
|
32
35
|
batch,
|