@inlang/sdk 0.22.0 → 0.24.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.
Files changed (46) hide show
  1. package/README.md +2 -2
  2. package/dist/adapter/solidAdapter.test.js +13 -6
  3. package/dist/createNodeishFsWithWatcher.js +1 -1
  4. package/dist/env-variables/index.d.ts +4 -0
  5. package/dist/env-variables/index.d.ts.map +1 -0
  6. package/dist/env-variables/index.js +3 -0
  7. package/dist/listProjects.d.ts.map +1 -1
  8. package/dist/listProjects.js +15 -9
  9. package/dist/listProjects.test.js +14 -1
  10. package/dist/loadProject.d.ts +28 -9
  11. package/dist/loadProject.d.ts.map +1 -1
  12. package/dist/loadProject.js +49 -50
  13. package/dist/loadProject.test.js +70 -33
  14. package/dist/migrations/maybeCreateFirstProjectId.d.ts +16 -0
  15. package/dist/migrations/maybeCreateFirstProjectId.d.ts.map +1 -0
  16. package/dist/migrations/maybeCreateFirstProjectId.js +37 -0
  17. package/dist/migrations/maybeCreateFirstProjectId.test.d.ts +2 -0
  18. package/dist/migrations/maybeCreateFirstProjectId.test.d.ts.map +1 -0
  19. package/dist/migrations/maybeCreateFirstProjectId.test.js +27 -0
  20. package/dist/migrations/migrateToDirectory.d.ts +1 -1
  21. package/dist/migrations/migrateToDirectory.js +3 -3
  22. package/dist/telemetry/capture.d.ts +21 -0
  23. package/dist/telemetry/capture.d.ts.map +1 -0
  24. package/dist/telemetry/capture.js +39 -0
  25. package/package.json +13 -12
  26. package/src/adapter/solidAdapter.test.ts +13 -6
  27. package/src/createNodeishFsWithWatcher.ts +1 -1
  28. package/src/env-variables/.prettierignore +1 -0
  29. package/src/env-variables/createIndexFile.js +28 -0
  30. package/src/env-variables/index.d.ts +13 -0
  31. package/src/listProjects.test.ts +21 -2
  32. package/src/listProjects.ts +14 -7
  33. package/src/loadProject.test.ts +73 -33
  34. package/src/loadProject.ts +91 -48
  35. package/src/migrations/maybeCreateFirstProjectId.test.ts +34 -0
  36. package/src/migrations/maybeCreateFirstProjectId.ts +43 -0
  37. package/src/migrations/migrateToDirectory.ts +3 -3
  38. package/src/telemetry/capture.ts +49 -0
  39. package/dist/generateProjectId.d.ts +0 -3
  40. package/dist/generateProjectId.d.ts.map +0 -1
  41. package/dist/generateProjectId.js +0 -11
  42. package/dist/generateProjectId.test.d.ts +0 -2
  43. package/dist/generateProjectId.test.d.ts.map +0 -1
  44. package/dist/generateProjectId.test.js +0 -18
  45. package/src/generateProjectId.test.ts +0 -22
  46. package/src/generateProjectId.ts +0 -14
package/README.md CHANGED
@@ -2,12 +2,12 @@ Developer-first localization infrastructure that is built on git. Your git repos
2
2
 
3
3
  <div>
4
4
  <p align="center">
5
- <img width="300" src="https://cdn.jsdelivr.net/gh/inlang/monorepo/inlang/assets/logo-white-background.png"/>
5
+ <img width="300" src="https://cdn.jsdelivr.net/gh/opral/monorepo/inlang/assets/logo-white-background.png"/>
6
6
  </p>
7
7
  <h4 align="center">
8
8
  <!-- <a href="https://inlang.com/documentation" target="_blank">Get Started</a>
9
9
  · -->
10
- <a href="https://github.com/inlang/monorepo/discussions" target="_blank">Discussions</a> · <a href="https://twitter.com/inlangHQ" target="_blank">Twitter</a>
10
+ <a href="https://github.com/opral/monorepo/discussions" target="_blank">Discussions</a> · <a href="https://twitter.com/inlangHQ" target="_blank">Twitter</a>
11
11
  </h4>
12
12
  </div>
13
13
 
@@ -4,6 +4,7 @@ import { createEffect, from, createRoot } from "../reactivity/solid.js";
4
4
  import { solidAdapter } from "./solidAdapter.js";
5
5
  import { loadProject } from "../loadProject.js";
6
6
  import { createNodeishMemoryFs } from "@lix-js/fs";
7
+ import { openRepository } from "@lix-js/client";
7
8
  // ------------------------------------------------------------------------------------------------
8
9
  const config = {
9
10
  sourceLanguageTag: "en",
@@ -74,9 +75,10 @@ describe("config", () => {
74
75
  const fs = createNodeishMemoryFs();
75
76
  await fs.mkdir("/user/project.inlang", { recursive: true });
76
77
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config));
78
+ const repo = await openRepository("file://", { nodeishFs: fs });
77
79
  const project = solidAdapter(await loadProject({
78
80
  projectPath: "/user/project.inlang",
79
- nodeishFs: fs,
81
+ repo,
80
82
  _import: $import,
81
83
  }), { from });
82
84
  let counter = 0;
@@ -98,9 +100,10 @@ describe("installed", () => {
98
100
  const fs = createNodeishMemoryFs();
99
101
  await fs.mkdir("/user/project.inlang", { recursive: true });
100
102
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config));
103
+ const repo = await openRepository("file://", { nodeishFs: fs });
101
104
  const project = solidAdapter(await loadProject({
102
105
  projectPath: "/user/project.inlang",
103
- nodeishFs: fs,
106
+ repo,
104
107
  _import: $import,
105
108
  }), { from });
106
109
  let counterPlugins = 0;
@@ -151,9 +154,10 @@ describe("messages", () => {
151
154
  const mockImport = async () => ({ default: mockPlugin });
152
155
  await fs.mkdir("/user/project.inlang.inlang", { recursive: true });
153
156
  await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(mockConfig));
157
+ const repo = await openRepository("file://", { nodeishFs: fs });
154
158
  const project = solidAdapter(await loadProject({
155
159
  projectPath: "/user/project.inlang.inlang",
156
- nodeishFs: fs,
160
+ repo,
157
161
  _import: mockImport,
158
162
  }), { from });
159
163
  let counter = 0;
@@ -172,9 +176,10 @@ describe("messages", () => {
172
176
  const fs = createNodeishMemoryFs();
173
177
  await fs.mkdir("/user/project.inlang.inlang", { recursive: true });
174
178
  await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(config));
179
+ const repo = await openRepository("file://", { nodeishFs: fs });
175
180
  const project = solidAdapter(await loadProject({
176
181
  projectPath: "/user/project.inlang.inlang",
177
- nodeishFs: fs,
182
+ repo,
178
183
  _import: $import,
179
184
  }), { from });
180
185
  let counter = 0;
@@ -218,9 +223,10 @@ describe("lint", () => {
218
223
  const fs = createNodeishMemoryFs();
219
224
  await fs.mkdir("./project.inlang", { recursive: true });
220
225
  await fs.writeFile("./project.inlang/settings.json", JSON.stringify(config));
226
+ const repo = await openRepository("file://", { nodeishFs: fs });
221
227
  const project = solidAdapter(await loadProject({
222
228
  projectPath: "./project.inlang",
223
- nodeishFs: fs,
229
+ repo,
224
230
  _import: $import,
225
231
  }), { from });
226
232
  let counter = 0;
@@ -245,9 +251,10 @@ describe("lint", () => {
245
251
  await createRoot(async () => {
246
252
  const fs = createNodeishMemoryFs();
247
253
  await fs.writeFile("./project.config.json", JSON.stringify(config));
254
+ const repo = await openRepository("file://", { nodeishFs: fs });
248
255
  const project = solidAdapter(await loadProject({
249
256
  projectPath: "./project.config.json",
250
- nodeishFs: fs,
257
+ repo,
251
258
  _import: $import,
252
259
  }), { from });
253
260
  let counter = 0;
@@ -24,7 +24,7 @@ export const createNodeishFsWithWatcher = (args) => {
24
24
  catch (err) {
25
25
  if (err.name === "AbortError")
26
26
  return;
27
- // https://github.com/inlang/monorepo/issues/1647
27
+ // https://github.com/opral/monorepo/issues/1647
28
28
  // the file does not exist (yet)
29
29
  // this is not testable beacause the fs.watch api differs
30
30
  // from node and lix. lenghty
@@ -0,0 +1,4 @@
1
+ export declare const ENV_VARIABLES: {
2
+ PUBLIC_POSTHOG_TOKEN: string;
3
+ };
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/env-variables/index.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa;;CAEzB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const ENV_VARIABLES = {
2
+ PUBLIC_POSTHOG_TOKEN: "phc_m5yJZCxjOGxF8CJvP5sQ3H0d76xpnLrsmiZHduT4jDz",
3
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"listProjects.d.ts","sourceRoot":"","sources":["../src/listProjects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,eAAO,MAAM,YAAY,cACb,iBAAiB,QACtB,MAAM,KACV,QAAQ,MAAM;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCxC,CAAA"}
1
+ {"version":3,"file":"listProjects.d.ts","sourceRoot":"","sources":["../src/listProjects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,eAAO,MAAM,YAAY,cACb,iBAAiB,QACtB,MAAM,KACV,QAAQ,MAAM;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAwCxC,CAAA"}
@@ -9,17 +9,23 @@ export const listProjects = async (nodeishFs, from) => {
9
9
  const files = await nodeishFs.readdir(path);
10
10
  for (const file of files) {
11
11
  const filePath = `${path}/${file}`;
12
- const stats = await nodeishFs.stat(filePath);
13
- if (stats.isDirectory()) {
14
- if (file === "node_modules")
15
- continue;
16
- if (file.endsWith(".inlang")) {
17
- projects.push({ projectPath: filePath });
18
- }
19
- else {
20
- await searchDir(filePath, depth + 1);
12
+ try {
13
+ const stats = await nodeishFs.stat(filePath);
14
+ if (stats.isDirectory()) {
15
+ if (file === "node_modules") {
16
+ continue;
17
+ }
18
+ if (file.endsWith(".inlang")) {
19
+ projects.push({ projectPath: filePath });
20
+ }
21
+ else {
22
+ await searchDir(filePath, depth + 1);
23
+ }
21
24
  }
22
25
  }
26
+ catch {
27
+ continue;
28
+ }
23
29
  }
24
30
  }
25
31
  await searchDir(from, 0);
@@ -1,6 +1,9 @@
1
- import { assert, describe, it } from "vitest";
1
+ import { assert, describe, it, expect } from "vitest";
2
2
  import { listProjects } from "./listProjects.js";
3
3
  import { createNodeishMemoryFs } from "@lix-js/fs";
4
+ import { mockRepo } from "@lix-js/client";
5
+ // eslint-disable-next-line no-restricted-imports -- test
6
+ import { readFileSync } from "node:fs";
4
7
  const settings = {
5
8
  sourceLanguageTag: "en",
6
9
  languageTags: ["en"],
@@ -43,6 +46,16 @@ describe("listProjects", () => {
43
46
  assert(projects.length === 0);
44
47
  });
45
48
  });
49
+ it("should not crash on broken symlinks as cal.com has", async () => {
50
+ const ciTestRepo = JSON.parse(readFileSync("./mocks/ci-test-repo-no-shallow.json", { encoding: "utf-8" }));
51
+ const repo = await mockRepo({ fromSnapshot: ciTestRepo });
52
+ repo.checkout({ branch: "test-symlink" });
53
+ const link = await repo.nodeishFs.readlink("test-symlink-not-existing-target");
54
+ expect(link).toBe("/test-symlink-not-existing-target//.././no-exist");
55
+ await listProjects(repo.nodeishFs, "/").then((projects) => {
56
+ assert(projects.length === 1);
57
+ });
58
+ });
46
59
  it("should also find files inside of a dir that ends with *.inlang", async () => {
47
60
  const fs = createNodeishMemoryFs();
48
61
  await fs.mkdir("/user/dir1/go.inlang", { recursive: true });
@@ -1,23 +1,42 @@
1
1
  import type { InlangProject, Subscribable } from "./api.js";
2
2
  import { type ImportFunction } from "./resolve-modules/index.js";
3
- import { type NodeishFilesystem } from "@lix-js/fs";
4
3
  import type { Repository } from "@lix-js/client";
5
4
  /**
6
5
  * Creates an inlang instance.
7
6
  *
8
7
  * @param projectPath - Absolute path to the inlang settings file.
9
- * @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
8
+ * @param @deprecated nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
10
9
  * @param _import - Use `_import` to pass a custom import function for testing,
11
10
  * and supporting legacy resolvedModules such as CJS.
12
- * @param _capture - Use `_capture` to capture events for analytics.
13
11
  *
14
12
  */
15
- export declare const loadProject: (args: {
13
+ export declare function loadProject(args: {
16
14
  projectPath: string;
17
- repo?: Repository | undefined;
18
- nodeishFs: NodeishFilesystem;
19
- _import?: ImportFunction | undefined;
20
- _capture?: ((id: string, props: Record<string, unknown>) => void) | undefined;
21
- }) => Promise<InlangProject>;
15
+ nodeishFs: Repository["nodeishFs"];
16
+ /**
17
+ * The app id is used to identify the app that is using the SDK.
18
+ *
19
+ * We use the app id to group events in telemetry to answer questions
20
+ * like "Which apps causes these errors?" or "Which apps are used more than others?".
21
+ *
22
+ * @example
23
+ * appId: "app.inlang.badge"
24
+ */
25
+ appId?: string;
26
+ _import?: ImportFunction;
27
+ }): Promise<InlangProject>;
28
+ /**
29
+ * @param projectPath - Absolute path to the inlang settings file.
30
+ * @param repo - An instance of a lix repo as returned by `openRepository`.
31
+ * @param _import - Use `_import` to pass a custom import function for testing,
32
+ * and supporting legacy resolvedModules such as CJS.
33
+ *
34
+ */
35
+ export declare function loadProject(args: {
36
+ projectPath: string;
37
+ repo: Repository;
38
+ appId?: string;
39
+ _import?: ImportFunction;
40
+ }): Promise<InlangProject>;
22
41
  export declare function createSubscribable<T>(signal: () => T): Subscribable<T>;
23
42
  //# sourceMappingURL=loadProject.d.ts.map
@@ -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,EAAiB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAIlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAKhD;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW;iBACV,MAAM;;eAER,iBAAiB;;qBAEZ,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;MAC5D,QAAQ,aAAa,CAkQxB,CAAA;AAwHD,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;AAuBhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAKhD;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IAClC;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,cAAc,CAAA;CACxB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;AAE1B;;;;;;GAMG;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,CAAA;AA+Y1B,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
@@ -13,22 +13,11 @@ import { normalizePath } from "@lix-js/fs";
13
13
  import { isAbsolutePath } from "./isAbsolutePath.js";
14
14
  import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js";
15
15
  import { maybeMigrateToDirectory } from "./migrations/migrateToDirectory.js";
16
- import { generateProjectId } from "./generateProjectId.js";
16
+ import { maybeCreateFirstProjectId } from "./migrations/maybeCreateFirstProjectId.js";
17
+ import { capture } from "./telemetry/capture.js";
17
18
  const settingsCompiler = TypeCompiler.Compile(ProjectSettings);
18
- /**
19
- * Creates an inlang instance.
20
- *
21
- * @param projectPath - Absolute path to the inlang settings file.
22
- * @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
23
- * @param _import - Use `_import` to pass a custom import function for testing,
24
- * and supporting legacy resolvedModules such as CJS.
25
- * @param _capture - Use `_capture` to capture events for analytics.
26
- *
27
- */
28
- export const loadProject = async (args) => {
19
+ export async function loadProject(args) {
29
20
  const projectPath = normalizePath(args.projectPath);
30
- // -- migrate if outdated ------------------------------------------------
31
- await maybeMigrateToDirectory({ nodeishFs: args.nodeishFs, projectPath });
32
21
  // -- validation --------------------------------------------------------
33
22
  // the only place where throwing is acceptable because the project
34
23
  // won't even be loaded. do not throw anywhere else. otherwise, apps
@@ -39,34 +28,31 @@ export const loadProject = async (args) => {
39
28
  else if (/[^\\/]+\.inlang$/.test(projectPath) === false) {
40
29
  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" });
41
30
  }
31
+ let fs;
32
+ if (args.nodeishFs) {
33
+ // TODO: deprecate
34
+ fs = args.nodeishFs;
35
+ }
36
+ else if (args.repo) {
37
+ fs = args.repo.nodeishFs;
38
+ }
39
+ else {
40
+ throw new LoadProjectInvalidArgument(`Repo missing from arguments.`, { argument: "repo" });
41
+ }
42
+ const nodeishFs = createNodeishFsWithAbsolutePaths({
43
+ projectPath,
44
+ nodeishFs: fs,
45
+ });
46
+ // -- migratations ------------------------------------------------
47
+ await maybeMigrateToDirectory({ nodeishFs: fs, projectPath });
48
+ await maybeCreateFirstProjectId({ projectPath, repo: args.repo });
42
49
  // -- load project ------------------------------------------------------
43
- let idError;
44
50
  return await createRoot(async () => {
51
+ // TODO remove tryCatch after https://github.com/opral/monorepo/issues/2013
52
+ // - a repo will always be present
53
+ // - if a repo is present, the project id will always be present
54
+ const { data: projectId } = await tryCatch(() => fs.readFile(args.projectPath + "/project_id", { encoding: "utf-8" }));
45
55
  const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable();
46
- const nodeishFs = createNodeishFsWithAbsolutePaths({
47
- projectPath,
48
- nodeishFs: args.nodeishFs,
49
- });
50
- let projectId;
51
- try {
52
- projectId = await nodeishFs.readFile(projectPath + "/project_id", {
53
- encoding: "utf-8",
54
- });
55
- }
56
- catch (error) {
57
- // @ts-ignore
58
- if (error.code === "ENOENT") {
59
- if (args.repo) {
60
- projectId = await generateProjectId(args.repo, projectPath);
61
- if (projectId) {
62
- await nodeishFs.writeFile(projectPath + "/project_id", projectId);
63
- }
64
- }
65
- }
66
- else {
67
- idError = error;
68
- }
69
- }
70
56
  // -- settings ------------------------------------------------------------
71
57
  const [settings, _setSettings] = createSignal();
72
58
  createEffect(() => {
@@ -77,12 +63,7 @@ export const loadProject = async (args) => {
77
63
  // })
78
64
  // }
79
65
  loadSettings({ settingsFilePath: projectPath + "/settings.json", nodeishFs })
80
- .then((settings) => {
81
- setSettings(settings);
82
- // rename settings to get a convenient access to the data in Posthog
83
- const project_settings = settings;
84
- args._capture?.("SDK used settings", { project_settings, group: projectId });
85
- })
66
+ .then((settings) => setSettings(settings))
86
67
  .catch((err) => {
87
68
  markInitAsFailed(err);
88
69
  });
@@ -158,7 +139,7 @@ export const loadProject = async (args) => {
158
139
  description: rule.description,
159
140
  module: resolvedModules()?.meta.find((m) => m.id.includes(rule.id))?.module ??
160
141
  "Unknown module. You stumbled on a bug in inlang's source code. Please open an issue.",
161
- // default to warning, see https://github.com/inlang/monorepo/issues/1254
142
+ // default to warning, see https://github.com/opral/monorepo/issues/1254
162
143
  level: settingsValue["messageLintRuleLevels"]?.[rule.id] ?? "warning",
163
144
  }));
164
145
  };
@@ -203,6 +184,27 @@ export const loadProject = async (args) => {
203
184
  createEffect(() => {
204
185
  debouncedSave(messagesQuery.getAll());
205
186
  });
187
+ /**
188
+ * Utility to escape reactive tracking and avoid multiple calls to
189
+ * the capture event.
190
+ *
191
+ * Should be addressed with https://github.com/opral/monorepo/issues/1772
192
+ */
193
+ let projectLoadedCapturedAlready = false;
194
+ if (projectId && projectLoadedCapturedAlready === false) {
195
+ projectLoadedCapturedAlready = true;
196
+ // TODO ensure that capture is "awaited" without blocking the the app from starting
197
+ await capture("SDK loaded project", {
198
+ projectId,
199
+ properties: {
200
+ appId: args.appId,
201
+ settings: settings(),
202
+ installedPluginIds: installedPlugins().map((p) => p.id),
203
+ installedMessageLintRuleIds: installedMessageLintRules().map((r) => r.id),
204
+ numberOfMessages: messagesQuery.includedMessageIds().length,
205
+ },
206
+ });
207
+ }
206
208
  return {
207
209
  installed: {
208
210
  plugins: createSubscribable(() => installedPlugins()),
@@ -210,10 +212,7 @@ export const loadProject = async (args) => {
210
212
  },
211
213
  errors: createSubscribable(() => [
212
214
  ...(initializeError ? [initializeError] : []),
213
- ...(idError ? [idError] : []),
214
215
  ...(resolvedModules() ? resolvedModules().errors : []),
215
- // have a query error exposed
216
- //...(lintErrors() ?? []),
217
216
  ]),
218
217
  settings: createSubscribable(() => settings()),
219
218
  setSettings,
@@ -224,7 +223,7 @@ export const loadProject = async (args) => {
224
223
  },
225
224
  };
226
225
  });
227
- };
226
+ }
228
227
  //const x = {} as InlangProject
229
228
  // ------------------------------------------------------------------------------------------------
230
229
  const loadSettings = async (args) => {