@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 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 messages.
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,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
+ {"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 messages.
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 messages = messagesQuery.getAll();
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
- });
31
- createEffect(() => {
32
- const currentMessageIds = new Set(messagesQuery.includedMessageIds());
33
- const deletedTrackedMessages = [...trackedMessages].filter((tracked) => !currentMessageIds.has(tracked[0]));
34
- if (rulesArray) {
35
- for (const messageId of currentMessageIds) {
36
- if (!trackedMessages.has(messageId)) {
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
- for (const deletedMessage of deletedTrackedMessages) {
65
- const deletedMessageId = deletedMessage[0];
66
- // call dispose to cleanup the effect
67
- const messageEffectDisposeFunction = trackedMessages.get(deletedMessageId);
68
- if (messageEffectDisposeFunction) {
69
- messageEffectDisposeFunction();
70
- trackedMessages.delete(deletedMessageId);
71
- // remove lint report result
72
- index.delete(deletedMessageId);
73
- debug(`delete lint message id: ${deletedMessageId}`);
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,EAAmB,MAAM,UAAU,CAAA;AAE9D,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;AAwB/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,CA6LpE"}
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;AAahD;;;;;;;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"}
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.5",
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/module": "1.2.11",
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/message-lint-rule": "1.4.7",
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 messages.
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 messages = messagesQuery.getAll() as Message[]
46
-
47
- const trackedMessages: Map<string, () => void> = new Map()
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
- lintSingleMessage({
79
- rules: rulesArray,
80
- settings: settingsObject(),
81
- messages: messages,
82
- message: message,
83
- }).then((report) => {
84
- lintMessageCount++
85
- throttledLogLintMessage(messageId)
86
- if (report.errors.length === 0 && index.get(messageId) !== report.data) {
87
- // console.log("lintSingleMessage", messageId, report.data.length)
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
- for (const deletedMessage of deletedTrackedMessages) {
97
- const deletedMessageId = deletedMessage[0]
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
- // call dispose to cleanup the effect
100
- const messageEffectDisposeFunction = trackedMessages.get(deletedMessageId)
101
- if (messageEffectDisposeFunction) {
102
- messageEffectDisposeFunction()
103
- trackedMessages.delete(deletedMessageId)
104
- // remove lint report result
105
- index.delete(deletedMessageId)
106
- debug(`delete lint message id: ${deletedMessageId}`)
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(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi)
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(fs, lockDirPath, messageState, messages, settingsValue, resolvedPluginApi)
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
  })
@@ -33,7 +33,6 @@ import { identifyProject } from "./telemetry/groupIdentify.js"
33
33
  import _debug from "debug"
34
34
  const debug = _debug("sdk:loadProject")
35
35
 
36
-
37
36
  const settingsCompiler = TypeCompiler.Compile(ProjectSettings)
38
37
 
39
38
  /**