@inlang/sdk 0.34.5 → 0.34.7
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/api.d.ts +8 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/createMessageLintReportsQuery.d.ts +1 -1
- package/dist/createMessageLintReportsQuery.d.ts.map +1 -1
- package/dist/createMessageLintReportsQuery.js +43 -58
- package/dist/createMessagesQuery.d.ts.map +1 -1
- package/dist/createMessagesQuery.js +38 -9
- package/dist/loadProject.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/api.ts +9 -0
- package/src/createMessageLintReportsQuery.ts +45 -67
- package/src/createMessagesQuery.ts +60 -4
- package/src/loadProject.ts +0 -1
package/dist/api.d.ts
CHANGED
|
@@ -58,6 +58,13 @@ export type Subscribable<Value> = {
|
|
|
58
58
|
(): Value;
|
|
59
59
|
subscribe: (callback: (value: Value) => void) => void;
|
|
60
60
|
};
|
|
61
|
+
export type MessageQueryDelegate = {
|
|
62
|
+
onMessageCreate: (messageId: string, message: Message) => void;
|
|
63
|
+
onMessageUpdate: (messageId: string, message: Message) => void;
|
|
64
|
+
onMessageDelete: (messageId: string) => void;
|
|
65
|
+
onLoaded: (messages: Message[]) => void;
|
|
66
|
+
onCleanup: () => void;
|
|
67
|
+
};
|
|
61
68
|
export type MessageQueryApi = {
|
|
62
69
|
create: (args: {
|
|
63
70
|
data: Message;
|
|
@@ -95,6 +102,7 @@ export type MessageQueryApi = {
|
|
|
95
102
|
id: Message["id"];
|
|
96
103
|
};
|
|
97
104
|
}) => boolean;
|
|
105
|
+
setDelegate: (delegate: MessageQueryDelegate) => void;
|
|
98
106
|
};
|
|
99
107
|
export type MessageLintReportsQueryApi = {
|
|
100
108
|
getAll: () => Promise<MessageLintReport[]>;
|
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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"}
|
|
@@ -2,7 +2,7 @@ import type { InlangProject, InstalledMessageLintRule, MessageQueryApi } from ".
|
|
|
2
2
|
import type { ProjectSettings } from "@inlang/project-settings";
|
|
3
3
|
import type { resolveModules } from "./resolve-modules/index.js";
|
|
4
4
|
/**
|
|
5
|
-
* Creates a reactive query API for
|
|
5
|
+
* Creates a ~~reactive~~ query API for lint reports.
|
|
6
6
|
*/
|
|
7
7
|
export declare function createMessageLintReportsQuery(messagesQuery: MessageQueryApi, settings: () => ProjectSettings, installedMessageLintRules: () => Array<InstalledMessageLintRule>, resolvedModules: () => Awaited<ReturnType<typeof resolveModules>> | undefined): InlangProject["query"]["messageLintReports"];
|
|
8
8
|
//# sourceMappingURL=createMessageLintReportsQuery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMessageLintReportsQuery.d.ts","sourceRoot":"","sources":["../src/createMessageLintReportsQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,wBAAwB,EAExB,eAAe,
|
|
1
|
+
{"version":3,"file":"createMessageLintReportsQuery.d.ts","sourceRoot":"","sources":["../src/createMessageLintReportsQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,wBAAwB,EAExB,eAAe,EAEf,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAQhE;;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,CA6E9C"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { lintSingleMessage } from "./lint/index.js";
|
|
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
2
|
function sleep(ms) {
|
|
7
3
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
4
|
}
|
|
9
5
|
/**
|
|
10
|
-
* Creates a reactive query API for
|
|
6
|
+
* Creates a ~~reactive~~ query API for lint reports.
|
|
11
7
|
*/
|
|
12
8
|
export function createMessageLintReportsQuery(messagesQuery, settings, installedMessageLintRules, resolvedModules) {
|
|
13
9
|
const index = new Map();
|
|
@@ -20,61 +16,50 @@ export function createMessageLintReportsQuery(messagesQuery, settings, installed
|
|
|
20
16
|
messageLintRuleLevels,
|
|
21
17
|
};
|
|
22
18
|
};
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
createRoot((dispose) => {
|
|
38
|
-
createEffect(() => {
|
|
39
|
-
const message = messagesQuery.get({ where: { id: messageId } });
|
|
40
|
-
if (!message) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (!trackedMessages?.has(messageId)) {
|
|
44
|
-
// initial effect execution - add dispose function
|
|
45
|
-
trackedMessages?.set(messageId, dispose);
|
|
46
|
-
}
|
|
47
|
-
lintSingleMessage({
|
|
48
|
-
rules: rulesArray,
|
|
49
|
-
settings: settingsObject(),
|
|
50
|
-
messages: messages,
|
|
51
|
-
message: message,
|
|
52
|
-
}).then((report) => {
|
|
53
|
-
lintMessageCount++;
|
|
54
|
-
throttledLogLintMessage(messageId);
|
|
55
|
-
if (report.errors.length === 0 && index.get(messageId) !== report.data) {
|
|
56
|
-
// console.log("lintSingleMessage", messageId, report.data.length)
|
|
57
|
-
index.set(messageId, report.data);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
}
|
|
19
|
+
const lintMessage = (message, messages) => {
|
|
20
|
+
if (!rulesArray) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// TODO unhandled promise rejection (as before the refactor) but won't tackle this in this pr
|
|
24
|
+
lintSingleMessage({
|
|
25
|
+
rules: rulesArray,
|
|
26
|
+
settings: settingsObject(),
|
|
27
|
+
messages: messages,
|
|
28
|
+
message: message,
|
|
29
|
+
}).then((report) => {
|
|
30
|
+
if (report.errors.length === 0 && index.get(message.id) !== report.data) {
|
|
31
|
+
// console.log("lintSingleMessage", messageId, report.data.length)
|
|
32
|
+
index.set(message.id, report.data);
|
|
63
33
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const messages = messagesQuery.getAll();
|
|
37
|
+
// load report for all messages once
|
|
38
|
+
for (const message of messages) {
|
|
39
|
+
// NOTE: this potentually creates thousands of promisses we could create a promise that batches linting
|
|
40
|
+
lintMessage(message, messages);
|
|
41
|
+
}
|
|
42
|
+
const messageQueryChangeDelegate = {
|
|
43
|
+
onCleanup: () => {
|
|
44
|
+
// NOTE: we could cancel all running lint rules - but results get overritten anyway
|
|
45
|
+
index.clear();
|
|
46
|
+
},
|
|
47
|
+
onLoaded: (messages) => {
|
|
48
|
+
for (const message of messages) {
|
|
49
|
+
lintMessage(message, messages);
|
|
75
50
|
}
|
|
76
|
-
}
|
|
77
|
-
|
|
51
|
+
},
|
|
52
|
+
onMessageCreate: (messageId, message) => {
|
|
53
|
+
lintMessage(message, messages);
|
|
54
|
+
},
|
|
55
|
+
onMessageUpdate: (messageId, message) => {
|
|
56
|
+
lintMessage(message, messages);
|
|
57
|
+
},
|
|
58
|
+
onMessageDelete: (messageId) => {
|
|
59
|
+
index.delete(messageId);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
messagesQuery.setDelegate(messageQueryChangeDelegate);
|
|
78
63
|
return {
|
|
79
64
|
getAll: async () => {
|
|
80
65
|
await sleep(0); // evaluate on next tick to allow for out-of-order effects
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMessagesQuery.d.ts","sourceRoot":"","sources":["../src/createMessagesQuery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"createMessagesQuery.d.ts","sourceRoot":"","sources":["../src/createMessagesQuery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAyC,MAAM,UAAU,CAAA;AAEpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAKnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AA4B/D,KAAK,6BAA6B,GAAG;IACpC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,iBAAiB,CAAA;IAC5B,QAAQ,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IAC3C,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7E,0BAA0B,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;IACxC,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;CACxC,CAAA;AACD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EACnC,WAAW,EACX,SAAS,EACT,QAAQ,EACR,eAAe,EACf,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,GACnB,EAAE,6BAA6B,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CA+MpE"}
|
|
@@ -10,6 +10,9 @@ import { releaseLock } from "./persistence/filelock/releaseLock.js";
|
|
|
10
10
|
import { PluginLoadMessagesError, PluginSaveMessagesError } from "./errors.js";
|
|
11
11
|
import { humanIdHash } from "./storage/human-id/human-readable-id.js";
|
|
12
12
|
const debug = _debug("sdk:createMessagesQuery");
|
|
13
|
+
function sleep(ms) {
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
}
|
|
13
16
|
/**
|
|
14
17
|
* Creates a reactive query API for messages.
|
|
15
18
|
*/
|
|
@@ -18,6 +21,10 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
18
21
|
const index = new ReactiveMap();
|
|
19
22
|
// filepath for the lock folder
|
|
20
23
|
const messageLockDirPath = projectPath + "/messagelock";
|
|
24
|
+
let delegate = undefined;
|
|
25
|
+
const setDelegate = (newDelegate) => {
|
|
26
|
+
delegate = newDelegate;
|
|
27
|
+
};
|
|
21
28
|
// Map default alias to message
|
|
22
29
|
// Assumes that aliases are only created and deleted, not updated
|
|
23
30
|
// TODO #2346 - handle updates to aliases
|
|
@@ -51,6 +58,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
51
58
|
onCleanup(() => {
|
|
52
59
|
// stop listening on fs events
|
|
53
60
|
abortController.abort();
|
|
61
|
+
delegate?.onCleanup();
|
|
54
62
|
});
|
|
55
63
|
const fsWithWatcher = createNodeishFsWithWatcher({
|
|
56
64
|
nodeishFs: nodeishFs,
|
|
@@ -58,7 +66,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
58
66
|
// - the plugin loads messages -> reads the file messages.json -> start watching on messages.json -> updateMessages
|
|
59
67
|
updateMessages: () => {
|
|
60
68
|
// reload
|
|
61
|
-
loadMessagesViaPlugin(fsWithWatcher, messageLockDirPath, messageStates, index, _settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
69
|
+
loadMessagesViaPlugin(fsWithWatcher, messageLockDirPath, messageStates, index, delegate, _settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
62
70
|
resolvedPluginApi)
|
|
63
71
|
.catch((e) => {
|
|
64
72
|
onLoadMessageResult(e);
|
|
@@ -73,7 +81,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
73
81
|
onInitialMessageLoadResult(new Error("no loadMessages in resolved Modules found"));
|
|
74
82
|
return;
|
|
75
83
|
}
|
|
76
|
-
loadMessagesViaPlugin(fsWithWatcher, messageLockDirPath, messageStates, index, _settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
84
|
+
loadMessagesViaPlugin(fsWithWatcher, messageLockDirPath, messageStates, index, delegate, _settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
77
85
|
resolvedPluginApi)
|
|
78
86
|
.catch((e) => {
|
|
79
87
|
// propagate initial load error to calling laodProject function
|
|
@@ -81,6 +89,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
81
89
|
})
|
|
82
90
|
.then(() => {
|
|
83
91
|
onInitialMessageLoadResult();
|
|
92
|
+
delegate?.onLoaded([...index.values()]);
|
|
84
93
|
});
|
|
85
94
|
});
|
|
86
95
|
const get = (args) => index.get(args.where.id);
|
|
@@ -94,7 +103,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
94
103
|
const resolvedPluginApi = resolvedModules()?.resolvedPluginApi;
|
|
95
104
|
if (!resolvedPluginApi)
|
|
96
105
|
return;
|
|
97
|
-
saveMessagesViaPlugin(nodeishFs, messageLockDirPath, messageStates, index, _settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
106
|
+
saveMessagesViaPlugin(nodeishFs, messageLockDirPath, messageStates, index, delegate, _settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
98
107
|
resolvedPluginApi)
|
|
99
108
|
.catch((e) => {
|
|
100
109
|
debug.log("error during saveMessagesViaPlugin");
|
|
@@ -108,6 +117,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
108
117
|
});
|
|
109
118
|
};
|
|
110
119
|
return {
|
|
120
|
+
setDelegate,
|
|
111
121
|
create: ({ data }) => {
|
|
112
122
|
if (index.has(data.id))
|
|
113
123
|
return false;
|
|
@@ -116,6 +126,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
116
126
|
defaultAliasIndex.set(data.alias.default, data);
|
|
117
127
|
}
|
|
118
128
|
messageStates.messageDirtyFlags[data.id] = true;
|
|
129
|
+
delegate?.onMessageCreate(data.id, index.get(data.id));
|
|
119
130
|
scheduleSave();
|
|
120
131
|
return true;
|
|
121
132
|
},
|
|
@@ -137,6 +148,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
137
148
|
return false;
|
|
138
149
|
index.set(where.id, { ...message, ...data });
|
|
139
150
|
messageStates.messageDirtyFlags[where.id] = true;
|
|
151
|
+
delegate?.onMessageCreate(where.id, index.get(data.id));
|
|
140
152
|
scheduleSave();
|
|
141
153
|
return true;
|
|
142
154
|
},
|
|
@@ -147,11 +159,14 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
147
159
|
if ("default" in data.alias) {
|
|
148
160
|
defaultAliasIndex.set(data.alias.default, data);
|
|
149
161
|
}
|
|
162
|
+
messageStates.messageDirtyFlags[where.id] = true;
|
|
163
|
+
delegate?.onMessageCreate(data.id, index.get(data.id));
|
|
150
164
|
}
|
|
151
165
|
else {
|
|
152
166
|
index.set(where.id, { ...message, ...data });
|
|
167
|
+
messageStates.messageDirtyFlags[where.id] = true;
|
|
168
|
+
delegate?.onMessageUpdate(data.id, index.get(data.id));
|
|
153
169
|
}
|
|
154
|
-
messageStates.messageDirtyFlags[where.id] = true;
|
|
155
170
|
scheduleSave();
|
|
156
171
|
return true;
|
|
157
172
|
},
|
|
@@ -164,6 +179,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
164
179
|
}
|
|
165
180
|
index.delete(where.id);
|
|
166
181
|
messageStates.messageDirtyFlags[where.id] = true;
|
|
182
|
+
delegate?.onMessageDelete(where.id);
|
|
167
183
|
scheduleSave();
|
|
168
184
|
return true;
|
|
169
185
|
},
|
|
@@ -175,6 +191,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
175
191
|
// - json plugin exports into separate file per language.
|
|
176
192
|
// - saving a message in two different languages would lead to a write in de.json first
|
|
177
193
|
// - This will leads to a load of the messages and since en.json has not been saved yet the english variant in the message would get overritten with the old state again
|
|
194
|
+
const maxMessagesPerTick = 500;
|
|
178
195
|
/**
|
|
179
196
|
* Messsage that loads messages from a plugin - this method synchronizes with the saveMessage funciton.
|
|
180
197
|
* If a save is in progress loading will wait until saving is done. If another load kicks in during this load it will queue the
|
|
@@ -188,7 +205,7 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
188
205
|
* @param loadPlugin
|
|
189
206
|
* @returns void - updates the files and messages in of the project in place
|
|
190
207
|
*/
|
|
191
|
-
async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi) {
|
|
208
|
+
async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, delegate, settingsValue, resolvedPluginApi) {
|
|
192
209
|
const experimentalAliases = !!settingsValue.experimental?.aliases;
|
|
193
210
|
// loading is an asynchronous process - check if another load is in progress - queue this call if so
|
|
194
211
|
if (messageState.isLoading) {
|
|
@@ -207,6 +224,7 @@ async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
207
224
|
settings: settingsValue,
|
|
208
225
|
nodeishFs: fs,
|
|
209
226
|
}));
|
|
227
|
+
let loadedMessageCount = 0;
|
|
210
228
|
for (const loadedMessage of loadedMessages) {
|
|
211
229
|
const loadedMessageClone = structuredClone(loadedMessage);
|
|
212
230
|
const currentMessages = [...messages.values()]
|
|
@@ -240,6 +258,8 @@ async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
240
258
|
messages.set(loadedMessageClone.id, loadedMessageClone);
|
|
241
259
|
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
242
260
|
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded;
|
|
261
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone);
|
|
262
|
+
loadedMessageCount++;
|
|
243
263
|
}
|
|
244
264
|
else {
|
|
245
265
|
// message with the given alias does not exist so far
|
|
@@ -263,6 +283,15 @@ async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
263
283
|
// we don't have to check - done before hand if (messages.has(loadedMessageClone.id)) return false
|
|
264
284
|
messages.set(loadedMessageClone.id, loadedMessageClone);
|
|
265
285
|
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded;
|
|
286
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone);
|
|
287
|
+
loadedMessageCount++;
|
|
288
|
+
}
|
|
289
|
+
if (loadedMessageCount > maxMessagesPerTick) {
|
|
290
|
+
// move loading of the next messages to the next ticks to allow solid to cleanup resources
|
|
291
|
+
// solid needs some time to settle and clean up
|
|
292
|
+
// https://github.com/solidjs-community/solid-primitives/blob/9ca76a47ffa2172770e075a90695cf933da0ff48/packages/trigger/src/index.ts#L64
|
|
293
|
+
await sleep(0);
|
|
294
|
+
loadedMessageCount = 0;
|
|
266
295
|
}
|
|
267
296
|
}
|
|
268
297
|
await releaseLock(fs, lockDirPath, "loadMessage", lockTime);
|
|
@@ -282,7 +311,7 @@ async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
282
311
|
// reset sheduling to except scheduling again
|
|
283
312
|
messageState.sheduledLoadMessagesViaPlugin = undefined;
|
|
284
313
|
// recall load unawaited to allow stack to pop
|
|
285
|
-
loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi)
|
|
314
|
+
loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, delegate, settingsValue, resolvedPluginApi)
|
|
286
315
|
.then(() => {
|
|
287
316
|
// resolve the scheduled load message promise
|
|
288
317
|
executingScheduledMessages.resolve();
|
|
@@ -293,7 +322,7 @@ async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
293
322
|
});
|
|
294
323
|
}
|
|
295
324
|
}
|
|
296
|
-
async function saveMessagesViaPlugin(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi) {
|
|
325
|
+
async function saveMessagesViaPlugin(fs, lockDirPath, messageState, messages, delegate, settingsValue, resolvedPluginApi) {
|
|
297
326
|
// queue next save if we have a save ongoing
|
|
298
327
|
if (messageState.isSaving) {
|
|
299
328
|
if (!messageState.sheduledSaveMessages) {
|
|
@@ -357,7 +386,7 @@ async function saveMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
357
386
|
// if there is a queued load, allow it to take the lock before we run additional saves.
|
|
358
387
|
if (messageState.sheduledLoadMessagesViaPlugin) {
|
|
359
388
|
debug("saveMessagesViaPlugin calling queued loadMessagesViaPlugin to share lock");
|
|
360
|
-
await loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi);
|
|
389
|
+
await loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, delegate, settingsValue, resolvedPluginApi);
|
|
361
390
|
}
|
|
362
391
|
messageState.isSaving = false;
|
|
363
392
|
}
|
|
@@ -390,7 +419,7 @@ async function saveMessagesViaPlugin(fs, lockDirPath, messageState, messages, se
|
|
|
390
419
|
if (messageState.sheduledSaveMessages) {
|
|
391
420
|
const executingSheduledSaveMessages = messageState.sheduledSaveMessages;
|
|
392
421
|
messageState.sheduledSaveMessages = undefined;
|
|
393
|
-
saveMessagesViaPlugin(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi)
|
|
422
|
+
saveMessagesViaPlugin(fs, lockDirPath, messageState, messages, delegate, settingsValue, resolvedPluginApi)
|
|
394
423
|
.then(() => {
|
|
395
424
|
executingSheduledSaveMessages.resolve();
|
|
396
425
|
})
|
|
@@ -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;AAkBhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;
|
|
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;AAkBhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAYhD;;;;;;;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,CAiOzB;AA+GD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.34.
|
|
4
|
+
"version": "0.34.7",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -34,16 +34,16 @@
|
|
|
34
34
|
"solid-js": "1.6.12",
|
|
35
35
|
"throttle-debounce": "^5.0.0",
|
|
36
36
|
"@inlang/json-types": "1.1.0",
|
|
37
|
-
"@inlang/message": "2.1.0",
|
|
38
37
|
"@inlang/language-tag": "1.5.1",
|
|
39
|
-
"@inlang/
|
|
38
|
+
"@inlang/message": "2.1.0",
|
|
39
|
+
"@inlang/message-lint-rule": "1.4.7",
|
|
40
40
|
"@inlang/plugin": "2.4.11",
|
|
41
41
|
"@inlang/project-settings": "2.4.2",
|
|
42
42
|
"@inlang/result": "1.1.0",
|
|
43
|
-
"@inlang/
|
|
43
|
+
"@inlang/module": "1.2.11",
|
|
44
|
+
"@inlang/translatable": "1.3.1",
|
|
44
45
|
"@lix-js/client": "1.4.0",
|
|
45
|
-
"@lix-js/fs": "1.0.0"
|
|
46
|
-
"@inlang/translatable": "1.3.1"
|
|
46
|
+
"@lix-js/fs": "1.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/debug": "^4.1.12",
|
package/src/api.ts
CHANGED
|
@@ -81,6 +81,14 @@ export type Subscribable<Value> = {
|
|
|
81
81
|
subscribe: (callback: (value: Value) => void) => void
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
export type MessageQueryDelegate = {
|
|
85
|
+
onMessageCreate: (messageId: string, message: Message) => void
|
|
86
|
+
onMessageUpdate: (messageId: string, message: Message) => void
|
|
87
|
+
onMessageDelete: (messageId: string) => void
|
|
88
|
+
onLoaded: (messages: Message[]) => void
|
|
89
|
+
onCleanup: () => void
|
|
90
|
+
}
|
|
91
|
+
|
|
84
92
|
export type MessageQueryApi = {
|
|
85
93
|
create: (args: { data: Message }) => boolean
|
|
86
94
|
get: ((args: { where: { id: Message["id"] } }) => Readonly<Message>) & {
|
|
@@ -101,6 +109,7 @@ export type MessageQueryApi = {
|
|
|
101
109
|
update: (args: { where: { id: Message["id"] }; data: Partial<Message> }) => boolean
|
|
102
110
|
upsert: (args: { where: { id: Message["id"] }; data: Message }) => void
|
|
103
111
|
delete: (args: { where: { id: Message["id"] } }) => boolean
|
|
112
|
+
setDelegate: (delegate: MessageQueryDelegate) => void
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
export type MessageLintReportsQueryApi = {
|
|
@@ -3,23 +3,19 @@ import type {
|
|
|
3
3
|
InstalledMessageLintRule,
|
|
4
4
|
MessageLintReportsQueryApi,
|
|
5
5
|
MessageQueryApi,
|
|
6
|
+
MessageQueryDelegate,
|
|
6
7
|
} from "./api.js"
|
|
7
8
|
import type { ProjectSettings } from "@inlang/project-settings"
|
|
8
9
|
import type { resolveModules } from "./resolve-modules/index.js"
|
|
9
10
|
import type { MessageLintReport, Message } from "./versionedInterfaces.js"
|
|
10
11
|
import { lintSingleMessage } from "./lint/index.js"
|
|
11
|
-
import { createRoot, createEffect } from "./reactivity/solid.js"
|
|
12
|
-
|
|
13
|
-
import { throttle } from "throttle-debounce"
|
|
14
|
-
import _debug from "debug"
|
|
15
|
-
const debug = _debug("sdk:lintReports")
|
|
16
12
|
|
|
17
13
|
function sleep(ms: number) {
|
|
18
14
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
/**
|
|
22
|
-
* Creates a reactive query API for
|
|
18
|
+
* Creates a ~~reactive~~ query API for lint reports.
|
|
23
19
|
*/
|
|
24
20
|
export function createMessageLintReportsQuery(
|
|
25
21
|
messagesQuery: MessageQueryApi,
|
|
@@ -42,72 +38,54 @@ export function createMessageLintReportsQuery(
|
|
|
42
38
|
}
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
57
|
-
createEffect(() => {
|
|
58
|
-
const currentMessageIds = new Set(messagesQuery.includedMessageIds())
|
|
59
|
-
|
|
60
|
-
const deletedTrackedMessages = [...trackedMessages].filter(
|
|
61
|
-
(tracked) => !currentMessageIds.has(tracked[0])
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
if (rulesArray) {
|
|
65
|
-
for (const messageId of currentMessageIds) {
|
|
66
|
-
if (!trackedMessages.has(messageId)) {
|
|
67
|
-
createRoot((dispose) => {
|
|
68
|
-
createEffect(() => {
|
|
69
|
-
const message = messagesQuery.get({ where: { id: messageId } })
|
|
70
|
-
if (!message) {
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
if (!trackedMessages?.has(messageId)) {
|
|
74
|
-
// initial effect execution - add dispose function
|
|
75
|
-
trackedMessages?.set(messageId, dispose)
|
|
76
|
-
}
|
|
41
|
+
const lintMessage = (message: Message, messages: Message[]) => {
|
|
42
|
+
if (!rulesArray) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
77
45
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
index.set(messageId, report.data)
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
}
|
|
46
|
+
// TODO unhandled promise rejection (as before the refactor) but won't tackle this in this pr
|
|
47
|
+
lintSingleMessage({
|
|
48
|
+
rules: rulesArray,
|
|
49
|
+
settings: settingsObject(),
|
|
50
|
+
messages: messages,
|
|
51
|
+
message: message,
|
|
52
|
+
}).then((report) => {
|
|
53
|
+
if (report.errors.length === 0 && index.get(message.id) !== report.data) {
|
|
54
|
+
// console.log("lintSingleMessage", messageId, report.data.length)
|
|
55
|
+
index.set(message.id, report.data)
|
|
94
56
|
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
95
59
|
|
|
96
|
-
|
|
97
|
-
|
|
60
|
+
const messages = messagesQuery.getAll() as Message[]
|
|
61
|
+
// load report for all messages once
|
|
62
|
+
for (const message of messages) {
|
|
63
|
+
// NOTE: this potentually creates thousands of promisses we could create a promise that batches linting
|
|
64
|
+
lintMessage(message, messages)
|
|
65
|
+
}
|
|
98
66
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
67
|
+
const messageQueryChangeDelegate: MessageQueryDelegate = {
|
|
68
|
+
onCleanup: () => {
|
|
69
|
+
// NOTE: we could cancel all running lint rules - but results get overritten anyway
|
|
70
|
+
index.clear()
|
|
71
|
+
},
|
|
72
|
+
onLoaded: (messages: Message[]) => {
|
|
73
|
+
for (const message of messages) {
|
|
74
|
+
lintMessage(message, messages)
|
|
108
75
|
}
|
|
109
|
-
}
|
|
110
|
-
|
|
76
|
+
},
|
|
77
|
+
onMessageCreate: (messageId: string, message: Message) => {
|
|
78
|
+
lintMessage(message, messages)
|
|
79
|
+
},
|
|
80
|
+
onMessageUpdate: (messageId: string, message: Message) => {
|
|
81
|
+
lintMessage(message, messages)
|
|
82
|
+
},
|
|
83
|
+
onMessageDelete: (messageId: string) => {
|
|
84
|
+
index.delete(messageId)
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
messagesQuery.setDelegate(messageQueryChangeDelegate)
|
|
111
89
|
|
|
112
90
|
return {
|
|
113
91
|
getAll: async () => {
|
|
@@ -2,7 +2,7 @@ import type { Message } from "@inlang/message"
|
|
|
2
2
|
import { ReactiveMap } from "./reactivity/map.js"
|
|
3
3
|
import { createEffect } from "./reactivity/solid.js"
|
|
4
4
|
import { createSubscribable } from "./loadProject.js"
|
|
5
|
-
import type { InlangProject, MessageQueryApi } from "./api.js"
|
|
5
|
+
import type { InlangProject, MessageQueryApi, MessageQueryDelegate } from "./api.js"
|
|
6
6
|
import type { ResolvedPluginApi } from "./resolve-modules/plugins/types.js"
|
|
7
7
|
import type { resolveModules } from "./resolve-modules/resolveModules.js"
|
|
8
8
|
import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js"
|
|
@@ -17,6 +17,10 @@ import { PluginLoadMessagesError, PluginSaveMessagesError } from "./errors.js"
|
|
|
17
17
|
import { humanIdHash } from "./storage/human-id/human-readable-id.js"
|
|
18
18
|
const debug = _debug("sdk:createMessagesQuery")
|
|
19
19
|
|
|
20
|
+
function sleep(ms: number) {
|
|
21
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
type MessageState = {
|
|
21
25
|
messageDirtyFlags: {
|
|
22
26
|
[messageId: string]: boolean
|
|
@@ -62,6 +66,12 @@ export function createMessagesQuery({
|
|
|
62
66
|
// filepath for the lock folder
|
|
63
67
|
const messageLockDirPath = projectPath + "/messagelock"
|
|
64
68
|
|
|
69
|
+
let delegate: MessageQueryDelegate | undefined = undefined
|
|
70
|
+
|
|
71
|
+
const setDelegate = (newDelegate: MessageQueryDelegate) => {
|
|
72
|
+
delegate = newDelegate
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
// Map default alias to message
|
|
66
76
|
// Assumes that aliases are only created and deleted, not updated
|
|
67
77
|
// TODO #2346 - handle updates to aliases
|
|
@@ -98,6 +108,7 @@ export function createMessagesQuery({
|
|
|
98
108
|
onCleanup(() => {
|
|
99
109
|
// stop listening on fs events
|
|
100
110
|
abortController.abort()
|
|
111
|
+
delegate?.onCleanup()
|
|
101
112
|
})
|
|
102
113
|
|
|
103
114
|
const fsWithWatcher = createNodeishFsWithWatcher({
|
|
@@ -111,6 +122,7 @@ export function createMessagesQuery({
|
|
|
111
122
|
messageLockDirPath,
|
|
112
123
|
messageStates,
|
|
113
124
|
index,
|
|
125
|
+
delegate,
|
|
114
126
|
_settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
115
127
|
resolvedPluginApi
|
|
116
128
|
)
|
|
@@ -133,6 +145,7 @@ export function createMessagesQuery({
|
|
|
133
145
|
messageLockDirPath,
|
|
134
146
|
messageStates,
|
|
135
147
|
index,
|
|
148
|
+
delegate,
|
|
136
149
|
_settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
137
150
|
resolvedPluginApi
|
|
138
151
|
)
|
|
@@ -142,6 +155,7 @@ export function createMessagesQuery({
|
|
|
142
155
|
})
|
|
143
156
|
.then(() => {
|
|
144
157
|
onInitialMessageLoadResult()
|
|
158
|
+
delegate?.onLoaded([...index.values()])
|
|
145
159
|
})
|
|
146
160
|
})
|
|
147
161
|
|
|
@@ -165,6 +179,7 @@ export function createMessagesQuery({
|
|
|
165
179
|
messageLockDirPath,
|
|
166
180
|
messageStates,
|
|
167
181
|
index,
|
|
182
|
+
delegate,
|
|
168
183
|
_settings, // NOTE we bang here - we don't expect the settings to become null during the livetime of a project
|
|
169
184
|
resolvedPluginApi
|
|
170
185
|
)
|
|
@@ -181,6 +196,7 @@ export function createMessagesQuery({
|
|
|
181
196
|
}
|
|
182
197
|
|
|
183
198
|
return {
|
|
199
|
+
setDelegate,
|
|
184
200
|
create: ({ data }): boolean => {
|
|
185
201
|
if (index.has(data.id)) return false
|
|
186
202
|
index.set(data.id, data)
|
|
@@ -189,6 +205,7 @@ export function createMessagesQuery({
|
|
|
189
205
|
}
|
|
190
206
|
|
|
191
207
|
messageStates.messageDirtyFlags[data.id] = true
|
|
208
|
+
delegate?.onMessageCreate(data.id, index.get(data.id))
|
|
192
209
|
scheduleSave()
|
|
193
210
|
return true
|
|
194
211
|
},
|
|
@@ -215,6 +232,7 @@ export function createMessagesQuery({
|
|
|
215
232
|
if (message === undefined) return false
|
|
216
233
|
index.set(where.id, { ...message, ...data })
|
|
217
234
|
messageStates.messageDirtyFlags[where.id] = true
|
|
235
|
+
delegate?.onMessageCreate(where.id, index.get(data.id))
|
|
218
236
|
scheduleSave()
|
|
219
237
|
return true
|
|
220
238
|
},
|
|
@@ -225,10 +243,13 @@ export function createMessagesQuery({
|
|
|
225
243
|
if ("default" in data.alias) {
|
|
226
244
|
defaultAliasIndex.set(data.alias.default, data)
|
|
227
245
|
}
|
|
246
|
+
messageStates.messageDirtyFlags[where.id] = true
|
|
247
|
+
delegate?.onMessageCreate(data.id, index.get(data.id))
|
|
228
248
|
} else {
|
|
229
249
|
index.set(where.id, { ...message, ...data })
|
|
250
|
+
messageStates.messageDirtyFlags[where.id] = true
|
|
251
|
+
delegate?.onMessageUpdate(data.id, index.get(data.id))
|
|
230
252
|
}
|
|
231
|
-
messageStates.messageDirtyFlags[where.id] = true
|
|
232
253
|
scheduleSave()
|
|
233
254
|
return true
|
|
234
255
|
},
|
|
@@ -240,6 +261,7 @@ export function createMessagesQuery({
|
|
|
240
261
|
}
|
|
241
262
|
index.delete(where.id)
|
|
242
263
|
messageStates.messageDirtyFlags[where.id] = true
|
|
264
|
+
delegate?.onMessageDelete(where.id)
|
|
243
265
|
scheduleSave()
|
|
244
266
|
return true
|
|
245
267
|
},
|
|
@@ -253,6 +275,8 @@ export function createMessagesQuery({
|
|
|
253
275
|
// - saving a message in two different languages would lead to a write in de.json first
|
|
254
276
|
// - This will leads to a load of the messages and since en.json has not been saved yet the english variant in the message would get overritten with the old state again
|
|
255
277
|
|
|
278
|
+
const maxMessagesPerTick = 500
|
|
279
|
+
|
|
256
280
|
/**
|
|
257
281
|
* Messsage that loads messages from a plugin - this method synchronizes with the saveMessage funciton.
|
|
258
282
|
* If a save is in progress loading will wait until saving is done. If another load kicks in during this load it will queue the
|
|
@@ -271,6 +295,7 @@ async function loadMessagesViaPlugin(
|
|
|
271
295
|
lockDirPath: string,
|
|
272
296
|
messageState: MessageState,
|
|
273
297
|
messages: Map<string, Message>,
|
|
298
|
+
delegate: MessageQueryDelegate | undefined,
|
|
274
299
|
settingsValue: ProjectSettings,
|
|
275
300
|
resolvedPluginApi: ResolvedPluginApi
|
|
276
301
|
) {
|
|
@@ -298,6 +323,8 @@ async function loadMessagesViaPlugin(
|
|
|
298
323
|
})
|
|
299
324
|
)
|
|
300
325
|
|
|
326
|
+
let loadedMessageCount = 0
|
|
327
|
+
|
|
301
328
|
for (const loadedMessage of loadedMessages) {
|
|
302
329
|
const loadedMessageClone = structuredClone(loadedMessage)
|
|
303
330
|
|
|
@@ -339,6 +366,8 @@ async function loadMessagesViaPlugin(
|
|
|
339
366
|
messages.set(loadedMessageClone.id, loadedMessageClone)
|
|
340
367
|
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
341
368
|
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded
|
|
369
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone)
|
|
370
|
+
loadedMessageCount++
|
|
342
371
|
} else {
|
|
343
372
|
// message with the given alias does not exist so far
|
|
344
373
|
loadedMessageClone.alias = {} as any
|
|
@@ -365,6 +394,15 @@ async function loadMessagesViaPlugin(
|
|
|
365
394
|
// we don't have to check - done before hand if (messages.has(loadedMessageClone.id)) return false
|
|
366
395
|
messages.set(loadedMessageClone.id, loadedMessageClone)
|
|
367
396
|
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded
|
|
397
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone)
|
|
398
|
+
loadedMessageCount++
|
|
399
|
+
}
|
|
400
|
+
if (loadedMessageCount > maxMessagesPerTick) {
|
|
401
|
+
// move loading of the next messages to the next ticks to allow solid to cleanup resources
|
|
402
|
+
// solid needs some time to settle and clean up
|
|
403
|
+
// https://github.com/solidjs-community/solid-primitives/blob/9ca76a47ffa2172770e075a90695cf933da0ff48/packages/trigger/src/index.ts#L64
|
|
404
|
+
await sleep(0)
|
|
405
|
+
loadedMessageCount = 0
|
|
368
406
|
}
|
|
369
407
|
}
|
|
370
408
|
await releaseLock(fs as NodeishFilesystem, lockDirPath, "loadMessage", lockTime)
|
|
@@ -388,7 +426,15 @@ async function loadMessagesViaPlugin(
|
|
|
388
426
|
messageState.sheduledLoadMessagesViaPlugin = undefined
|
|
389
427
|
|
|
390
428
|
// recall load unawaited to allow stack to pop
|
|
391
|
-
loadMessagesViaPlugin(
|
|
429
|
+
loadMessagesViaPlugin(
|
|
430
|
+
fs,
|
|
431
|
+
lockDirPath,
|
|
432
|
+
messageState,
|
|
433
|
+
messages,
|
|
434
|
+
delegate,
|
|
435
|
+
settingsValue,
|
|
436
|
+
resolvedPluginApi
|
|
437
|
+
)
|
|
392
438
|
.then(() => {
|
|
393
439
|
// resolve the scheduled load message promise
|
|
394
440
|
executingScheduledMessages.resolve()
|
|
@@ -405,6 +451,7 @@ async function saveMessagesViaPlugin(
|
|
|
405
451
|
lockDirPath: string,
|
|
406
452
|
messageState: MessageState,
|
|
407
453
|
messages: Map<string, Message>,
|
|
454
|
+
delegate: MessageQueryDelegate | undefined,
|
|
408
455
|
settingsValue: ProjectSettings,
|
|
409
456
|
resolvedPluginApi: ResolvedPluginApi
|
|
410
457
|
): Promise<void> {
|
|
@@ -491,6 +538,7 @@ async function saveMessagesViaPlugin(
|
|
|
491
538
|
lockDirPath,
|
|
492
539
|
messageState,
|
|
493
540
|
messages,
|
|
541
|
+
delegate,
|
|
494
542
|
settingsValue,
|
|
495
543
|
resolvedPluginApi
|
|
496
544
|
)
|
|
@@ -530,7 +578,15 @@ async function saveMessagesViaPlugin(
|
|
|
530
578
|
const executingSheduledSaveMessages = messageState.sheduledSaveMessages
|
|
531
579
|
messageState.sheduledSaveMessages = undefined
|
|
532
580
|
|
|
533
|
-
saveMessagesViaPlugin(
|
|
581
|
+
saveMessagesViaPlugin(
|
|
582
|
+
fs,
|
|
583
|
+
lockDirPath,
|
|
584
|
+
messageState,
|
|
585
|
+
messages,
|
|
586
|
+
delegate,
|
|
587
|
+
settingsValue,
|
|
588
|
+
resolvedPluginApi
|
|
589
|
+
)
|
|
534
590
|
.then(() => {
|
|
535
591
|
executingSheduledSaveMessages.resolve()
|
|
536
592
|
})
|