@likec4/language-services 1.50.0 → 1.52.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.
@@ -0,0 +1,19 @@
1
+ import { configureLanguageServerLogger } from "@likec4/language-server";
2
+ import { isColorSupported } from "std-env";
3
+ function configureLogger(options) {
4
+ const opt = options?.configureLogger ?? "console";
5
+ if (opt === false) return;
6
+ if (opt === "stderr" || options?.mcp === "stdio") {
7
+ configureLanguageServerLogger({
8
+ useStdErr: true,
9
+ colors: false,
10
+ logLevel: options?.logLevel
11
+ });
12
+ return;
13
+ }
14
+ configureLanguageServerLogger({
15
+ colors: isColorSupported,
16
+ logLevel: options?.logLevel
17
+ });
18
+ }
19
+ export { configureLogger as t };
@@ -1,5 +1,4 @@
1
1
  import { loggable, rootLogger } from "@likec4/log";
2
- import defu from "defu";
3
2
  import { extname } from "pathe";
4
3
  import k from "tinyrainbow";
5
4
  import { LikeC4ProjectConfigOps, isLikeC4JsonConfig } from "@likec4/config";
@@ -147,6 +146,23 @@ Please specify a project folder`);
147
146
  sib.dispose();
148
147
  };
149
148
  }
149
+ /**
150
+ * Formats documents and returns a map of document URI → formatted source text.
151
+ *
152
+ * Target selection uses union semantics:
153
+ * - Omit both `projects` and `documentUris` to format **all** documents.
154
+ * - Provide `projects` to include all documents from those projects.
155
+ * - Provide `documentUris` to include specific documents.
156
+ * - Provide both to format the **union** (deduplicated).
157
+ */
158
+ async format(options) {
159
+ const { projects, ...rest } = options ?? {};
160
+ const formatOptions = {
161
+ ...rest,
162
+ ...projects && { projectIds: projects.map((p) => this.projectsManager.ensureProjectId(p)) }
163
+ };
164
+ return await this.languageServices.format(formatOptions);
165
+ }
150
166
  async dispose() {
151
167
  await this.languageServices.dispose();
152
168
  }
@@ -154,18 +170,22 @@ Please specify a project folder`);
154
170
  await this.dispose();
155
171
  }
156
172
  };
173
+ const DefaultInitOptions = {
174
+ printErrors: true,
175
+ throwIfInvalid: false,
176
+ graphviz: "wasm",
177
+ mcp: false,
178
+ configureLogger: false,
179
+ logLevel: void 0
180
+ };
157
181
  const validationErrorsToError = (likec4) => /* @__PURE__ */ new Error(`Invalid model:\n${likec4.getErrors().map((e) => ` ${e.sourceFsPath}:${e.line} ${e.message.slice(0, 200)}`).join("\n")}`);
158
182
  async function handleInitOptions(langium, logger = rootLogger, options) {
159
183
  const likec4 = new LikeC4(langium, logger);
160
- const opts = defu(options, {
161
- printErrors: true,
162
- throwIfInvalid: false
163
- });
164
- if (opts.throwIfInvalid === true && likec4.hasErrors()) {
184
+ if ((options?.throwIfInvalid ?? DefaultInitOptions.throwIfInvalid) === true && likec4.hasErrors()) {
165
185
  await likec4.dispose();
166
186
  return Promise.reject(validationErrorsToError(likec4));
167
187
  }
168
- if (opts.printErrors !== false && likec4.hasErrors()) likec4.printErrors();
188
+ if ((options?.printErrors ?? DefaultInitOptions.printErrors) && likec4.hasErrors()) likec4.printErrors();
169
189
  return likec4;
170
190
  }
171
191
  /**
@@ -209,4 +229,4 @@ async function createFromSources(langium, logger, sources, initOptions) {
209
229
  await langium.shared.workspace.DocumentBuilder.build(docs, { validation: true });
210
230
  return handleInitOptions(langium, logger, initOptions);
211
231
  }
212
- export { handleInitOptions as n, LikeC4 as r, createFromSources as t };
232
+ export { LikeC4 as i, handleInitOptions as n, DefaultInitOptions as r, createFromSources as t };
@@ -1,7 +1,7 @@
1
1
  import { Logger } from "@likec4/log";
2
+ import { LikeC4LanguageServices, LikeC4ModelBuilder, LikeC4Services, LikeC4SharedServices, LikeC4Views, ProjectsManager } from "@likec4/language-server";
2
3
  import { LikeC4Model } from "@likec4/core/model";
3
4
  import { LayoutedView, NonEmptyArray, ProjectId } from "@likec4/core/types";
4
- import { LikeC4LanguageServices, LikeC4ModelBuilder, LikeC4Services, LikeC4SharedServices, LikeC4Views, ProjectsManager } from "@likec4/language-server";
5
5
 
6
6
  //#region src/common/LikeC4.d.ts
7
7
  interface LikeC4Langium {
@@ -81,12 +81,43 @@ declare class LikeC4 {
81
81
  * @returns a function to dispose the listener
82
82
  */
83
83
  onModelUpdate(listener: () => void): () => void;
84
+ /**
85
+ * Formats documents and returns a map of document URI → formatted source text.
86
+ *
87
+ * Target selection uses union semantics:
88
+ * - Omit both `projects` and `documentUris` to format **all** documents.
89
+ * - Provide `projects` to include all documents from those projects.
90
+ * - Provide `documentUris` to include specific documents.
91
+ * - Provide both to format the **union** (deduplicated).
92
+ */
93
+ format(options?: LikeC4FormatOptions): Promise<Map<string, string>>;
84
94
  dispose(): Promise<void>;
85
95
  [Symbol.asyncDispose](): Promise<void>;
86
96
  }
97
+ /**
98
+ * Options for {@link LikeC4.format}.
99
+ *
100
+ * Same as {@link FormatOptions} but uses project name strings instead of {@link ProjectId}.
101
+ */
102
+ interface LikeC4FormatOptions {
103
+ /** Include all documents from these projects (by name). */
104
+ projects?: ReadonlyArray<string>;
105
+ /** Include these specific documents (by URI string). */
106
+ documentUris?: ReadonlyArray<string>;
107
+ /** Size of a tab in spaces (default: 2). */
108
+ tabSize?: number;
109
+ /** Prefer spaces over tabs (default: true). */
110
+ insertSpaces?: boolean;
111
+ /** Trim trailing whitespace on a line. */
112
+ trimTrailingWhitespace?: boolean;
113
+ /** Insert a newline character at the end of the file if one does not exist. */
114
+ insertFinalNewline?: boolean;
115
+ /** Trim all newlines after the final newline at the end of the file. */
116
+ trimFinalNewlines?: boolean;
117
+ }
87
118
  //#endregion
88
119
  //#region src/common/options.d.ts
89
- type InitOptions = {
120
+ interface InitOptions {
90
121
  /**
91
122
  * By default, if LikeC4 model is invalid, errors are printed to the console.
92
123
  * Disable this behavior by setting this option to false.
@@ -115,7 +146,22 @@ type InitOptions = {
115
146
  mcp?: false | 'stdio' | {
116
147
  port: number;
117
148
  };
118
- };
149
+ /**
150
+ * Whether to configure the logger.
151
+ *
152
+ * - `false` - don't configure the logger
153
+ * - `'console'` - configure the logger with console sink
154
+ * - `'stderr'` - configure the logger with stderr (for LSP or MCP)
155
+ *
156
+ * @default false
157
+ */
158
+ configureLogger?: false | 'console' | 'stderr';
159
+ /**
160
+ * The log level to use.
161
+ * Applied if {@link configureLogger} is not `false`
162
+ */
163
+ logLevel?: 'trace' | 'debug' | 'info' | 'warning' | 'error' | undefined;
164
+ }
119
165
  type FromWorkspaceOptions = InitOptions & {
120
166
  /**
121
167
  * Whether to read and use manual layouts from the workspace.
@@ -1,14 +1,16 @@
1
- import { n as handleInitOptions, r as LikeC4, t as createFromSources } from "../_chunks/createFromSources.mjs";
1
+ import { i as LikeC4, n as handleInitOptions, r as DefaultInitOptions, t as createFromSources } from "../_chunks/createFromSources.mjs";
2
+ import { t as configureLogger$1 } from "../_chunks/configureLogger.mjs";
2
3
  import { memoizeProp } from "@likec4/core";
3
- import { configureLogger, getConsoleStderrSink, loggable, rootLogger } from "@likec4/log";
4
+ import { loggable, rootLogger } from "@likec4/log";
4
5
  import defu from "defu";
5
6
  import { basename, resolve } from "pathe";
6
7
  import k from "tinyrainbow";
8
+ import { withTrailingSlash } from "ufo";
7
9
  import { pathToFileURL } from "url";
8
10
  import { WithFileSystem, WithLikeC4ManualLayouts } from "@likec4/language-server/filesystem";
9
11
  import { WithMCPServer } from "@likec4/language-server/mcp";
10
- import { NoFileSystem, NoLikeC4ManualLayouts, createLanguageServices } from "@likec4/language-server/module";
11
- import { GraphvizWasmAdapter, QueueGraphvizLayoter } from "@likec4/layouts";
12
+ import { NoFileSystem, NoLikeC4ManualLayouts, WithGraphviz, createLanguageServices } from "@likec4/language-server/module";
13
+ import { GraphvizWasmAdapter } from "@likec4/layouts";
12
14
  import { GraphvizBinaryAdapter } from "@likec4/layouts/graphviz/binary";
13
15
  function createLanguageServices$1(opts) {
14
16
  const logger = rootLogger.getChild("lang");
@@ -19,15 +21,6 @@ function createLanguageServices$1(opts) {
19
21
  graphviz: "wasm",
20
22
  mcp: false
21
23
  });
22
- if (options.mcp === "stdio") configureLogger({
23
- reset: true,
24
- sinks: { console: getConsoleStderrSink() },
25
- loggers: [{
26
- category: "likec4",
27
- sinks: ["console"],
28
- lowestLevel: "warning"
29
- }]
30
- });
31
24
  const useDotBin = options.graphviz === "binary";
32
25
  logger.info(`${k.dim("layout")} ${useDotBin ? "binary" : "wasm"}`);
33
26
  const langium = createLanguageServices({
@@ -38,8 +31,9 @@ function createLanguageServices$1(opts) {
38
31
  ...NoFileSystem,
39
32
  ...NoLikeC4ManualLayouts
40
33
  },
41
- ...options.mcp ? WithMCPServer(options.mcp === "stdio" ? "stdio" : options.mcp) : {}
42
- }, { likec4: { Layouter: () => new QueueGraphvizLayoter({ graphviz: useDotBin ? new GraphvizBinaryAdapter() : new GraphvizWasmAdapter() }) } });
34
+ ...options.mcp ? WithMCPServer(options.mcp === "stdio" ? "stdio" : options.mcp) : {},
35
+ ...WithGraphviz(useDotBin ? new GraphvizBinaryAdapter() : new GraphvizWasmAdapter())
36
+ });
43
37
  if (typeof options.mcp === "object" && options.mcp.port) langium.likec4.mcp.Server.start(options.mcp.port).catch((e) => {
44
38
  logger.error(loggable(e));
45
39
  });
@@ -57,12 +51,13 @@ function createLanguageServices$1(opts) {
57
51
  * @returns A Promise that resolves to a LikeC4 instance
58
52
  */
59
53
  async function fromWorkspace(path, options) {
54
+ configureLogger$1(options);
60
55
  const workspacePath = resolve(path);
61
- const folderUri = pathToFileURL(workspacePath).toString();
62
- const workspaceUri = folderUri.endsWith("/") ? folderUri : folderUri + "/";
56
+ const workspaceUri = withTrailingSlash(pathToFileURL(workspacePath).toString());
63
57
  return memoizeProp(globalThis, "likec4:" + workspacePath, async () => {
64
58
  const logger = rootLogger.getChild("lang");
65
59
  const langium = createLanguageServices$1(defu(options, {
60
+ ...DefaultInitOptions,
66
61
  useFileSystem: true,
67
62
  manualLayouts: true,
68
63
  watch: false,
@@ -115,8 +110,10 @@ async function fromWorkdir(options) {
115
110
  * @returns A Promise that resolves to a LikeC4 instance
116
111
  */
117
112
  async function fromSources(sources, options) {
113
+ configureLogger$1(options);
118
114
  const logger = rootLogger.getChild("lang");
119
115
  return await createFromSources(createLanguageServices$1(defu(options, {
116
+ ...DefaultInitOptions,
120
117
  useFileSystem: false,
121
118
  watch: false,
122
119
  manualLayouts: false,
@@ -1,4 +1,5 @@
1
- import { n as handleInitOptions, r as LikeC4, t as createFromSources } from "../../_chunks/createFromSources.mjs";
1
+ import { i as LikeC4, n as handleInitOptions, t as createFromSources } from "../../_chunks/createFromSources.mjs";
2
+ import { t as configureLogger$1 } from "../../_chunks/configureLogger.mjs";
2
3
  import { memoizeProp } from "@likec4/core";
3
4
  import { rootLogger } from "@likec4/log";
4
5
  import defu from "defu";
@@ -6,8 +7,8 @@ import { basename, resolve } from "pathe";
6
7
  import k from "tinyrainbow";
7
8
  import { pathToFileURL } from "url";
8
9
  import { WithFileSystem, WithLikeC4ManualLayouts } from "@likec4/language-server/filesystem";
9
- import { NoFileSystem, NoLikeC4ManualLayouts, createLanguageServices } from "@likec4/language-server/module";
10
- import { GraphvizWasmAdapter, QueueGraphvizLayoter } from "@likec4/layouts";
10
+ import { NoFileSystem, NoLikeC4ManualLayouts, WithGraphviz, createLanguageServices } from "@likec4/language-server/module";
11
+ import { GraphvizWasmAdapter } from "@likec4/layouts";
11
12
  import { GraphvizBinaryAdapter } from "@likec4/layouts/graphviz/binary";
12
13
  function createLanguageServices$1(opts) {
13
14
  const logger = rootLogger.getChild("lang");
@@ -19,13 +20,16 @@ function createLanguageServices$1(opts) {
19
20
  });
20
21
  const useDotBin = options.graphviz === "binary";
21
22
  logger.info(`${k.dim("layout")} ${useDotBin ? "binary" : "wasm"}`);
22
- return createLanguageServices({ ...options.useFileSystem ? {
23
- ...WithFileSystem(options.watch),
24
- ...options.manualLayouts ? WithLikeC4ManualLayouts : NoLikeC4ManualLayouts
25
- } : {
26
- ...NoFileSystem,
27
- ...NoLikeC4ManualLayouts
28
- } }, { likec4: { Layouter: () => new QueueGraphvizLayoter({ graphviz: useDotBin ? new GraphvizBinaryAdapter() : new GraphvizWasmAdapter() }) } });
23
+ return createLanguageServices({
24
+ ...options.useFileSystem ? {
25
+ ...WithFileSystem(options.watch),
26
+ ...options.manualLayouts ? WithLikeC4ManualLayouts : NoLikeC4ManualLayouts
27
+ } : {
28
+ ...NoFileSystem,
29
+ ...NoLikeC4ManualLayouts
30
+ },
31
+ ...WithGraphviz(useDotBin ? new GraphvizBinaryAdapter() : new GraphvizWasmAdapter())
32
+ });
29
33
  }
30
34
  /**
31
35
  * Create a LikeC4 instance from a workspace directory
@@ -36,6 +40,7 @@ function createLanguageServices$1(opts) {
36
40
  * @returns A Promise that resolves to a LikeC4 instance
37
41
  */
38
42
  async function fromWorkspace(path, options) {
43
+ configureLogger$1(options);
39
44
  const workspacePath = resolve(path);
40
45
  const folderUri = pathToFileURL(workspacePath).toString();
41
46
  const workspaceUri = folderUri.endsWith("/") ? folderUri : folderUri + "/";
@@ -95,6 +100,7 @@ async function fromWorkdir(options) {
95
100
  * @returns A Promise that resolves to a LikeC4 instance
96
101
  */
97
102
  async function fromSources(sources, options) {
103
+ configureLogger$1(options);
98
104
  const logger = rootLogger.getChild("lang");
99
105
  return await createFromSources(createLanguageServices$1(defu(options, {
100
106
  useFileSystem: false,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likec4/language-services",
3
3
  "description": "LikeC4 Language Services",
4
- "version": "1.50.0",
4
+ "version": "1.52.0",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -70,31 +70,32 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "defu": "^6.1.4",
73
- "remeda": "^2.33.5",
73
+ "remeda": "^2.33.6",
74
74
  "langium": "3.5.0",
75
- "tinyrainbow": "^2.0.0",
75
+ "tinyrainbow": "^3.0.3",
76
76
  "pathe": "^2.0.3",
77
+ "ufo": "1.6.3",
77
78
  "std-env": "^3.10.0",
78
79
  "type-fest": "^4.41.0",
79
80
  "vscode-languageserver-types": "3.17.5",
80
- "@likec4/config": "1.50.0",
81
- "@likec4/core": "1.50.0",
82
- "@likec4/generators": "1.50.0",
81
+ "@likec4/config": "1.52.0",
82
+ "@likec4/core": "1.52.0",
83
+ "@likec4/generators": "1.52.0",
83
84
  "@likec4/icons": "1.46.4",
84
- "@likec4/language-server": "1.50.0",
85
- "@likec4/log": "1.50.0",
86
- "@likec4/layouts": "1.50.0"
85
+ "@likec4/language-server": "1.52.0",
86
+ "@likec4/layouts": "1.52.0",
87
+ "@likec4/log": "1.52.0"
87
88
  },
88
89
  "devDependencies": {
89
90
  "@types/node": "~22.19.11",
90
91
  "obuild": "^0.4.31",
91
92
  "oxlint": "1.43.0",
92
93
  "tsx": "4.21.0",
93
- "turbo": "2.8.10",
94
+ "turbo": "2.8.13",
94
95
  "typescript": "5.9.3",
95
96
  "vitest": "4.0.18",
96
97
  "@likec4/devops": "1.42.0",
97
- "@likec4/tsconfig": "1.50.0"
98
+ "@likec4/tsconfig": "1.52.0"
98
99
  },
99
100
  "scripts": {
100
101
  "typecheck": "tsc -b --verbose",