arc-lang 0.5.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,327 @@
1
+ // Arc Language Semantic Analyzer
2
+ // Performs: name resolution, scope validation, mutability checking, arity checking, match exhaustiveness warnings
3
+ class Scope {
4
+ parent;
5
+ symbols = new Map();
6
+ constructor(parent) {
7
+ this.parent = parent;
8
+ }
9
+ define(name, info) {
10
+ // Allow redefinition in same scope (shadowing)
11
+ this.symbols.set(name, info);
12
+ return true;
13
+ }
14
+ lookup(name) {
15
+ const s = this.symbols.get(name);
16
+ if (s)
17
+ return s;
18
+ if (this.parent)
19
+ return this.parent.lookup(name);
20
+ return undefined;
21
+ }
22
+ lookupLocal(name) {
23
+ return this.symbols.get(name);
24
+ }
25
+ }
26
+ // Built-in names that are always available
27
+ const BUILTINS = new Set([
28
+ "print", "println", "len", "push", "pop", "map", "filter", "reduce",
29
+ "range", "keys", "values", "entries", "type", "str", "int", "float",
30
+ "sort", "reverse", "join", "split", "trim", "contains", "starts_with",
31
+ "ends_with", "replace", "to_upper", "to_lower", "slice", "flat",
32
+ "flat_map", "zip", "enumerate", "sum", "min", "max", "abs",
33
+ "head", "tail", "take", "drop", "find", "any", "all", "count",
34
+ "unique", "group_by", "sort_by", "chunk", "window", "scan",
35
+ "assert", "assert_eq", "Some", "None", "Ok", "Err",
36
+ "Math", "String", "List", "Map", "JSON", "Error",
37
+ "true", "false", "nil",
38
+ "is_nil", "is_some", "unwrap", "unwrap_or",
39
+ "typeof", "chars", "char_at", "index_of", "last_index_of",
40
+ "parse_int", "parse_float", "to_string", "format",
41
+ "now", "sleep", "random", "floor", "ceil", "round", "sqrt", "pow", "log",
42
+ "read_file", "write_file", "http_get", "http_post",
43
+ "append", "prepend", "concat", "flatten", "each", "fold",
44
+ "first", "last", "rest", "init", "is_empty", "size",
45
+ "repeat", "pad_left", "pad_right", "upper", "lower",
46
+ "every", "some", "none", "includes",
47
+ ]);
48
+ export function analyze(program) {
49
+ const diagnostics = [];
50
+ const globalScope = new Scope();
51
+ function error(loc, message) {
52
+ diagnostics.push({ level: "error", message, loc });
53
+ }
54
+ function warning(loc, message) {
55
+ diagnostics.push({ level: "warning", message, loc });
56
+ }
57
+ function analyzeExpr(expr, scope) {
58
+ switch (expr.kind) {
59
+ case "IntLiteral":
60
+ case "FloatLiteral":
61
+ case "BoolLiteral":
62
+ case "NilLiteral":
63
+ case "StringLiteral":
64
+ break;
65
+ case "StringInterp":
66
+ for (const part of expr.parts) {
67
+ if (typeof part !== "string") {
68
+ analyzeExpr(part, scope);
69
+ }
70
+ }
71
+ break;
72
+ case "Identifier": {
73
+ const sym = scope.lookup(expr.name);
74
+ if (!sym && !BUILTINS.has(expr.name)) {
75
+ error(expr.loc, `Undefined variable: '${expr.name}'`);
76
+ }
77
+ break;
78
+ }
79
+ case "BinaryExpr":
80
+ analyzeExpr(expr.left, scope);
81
+ analyzeExpr(expr.right, scope);
82
+ break;
83
+ case "UnaryExpr":
84
+ analyzeExpr(expr.operand, scope);
85
+ break;
86
+ case "CallExpr": {
87
+ analyzeExpr(expr.callee, scope);
88
+ for (const arg of expr.args) {
89
+ analyzeExpr(arg, scope);
90
+ }
91
+ // Arity check for known functions
92
+ if (expr.callee.kind === "Identifier") {
93
+ const sym = scope.lookup(expr.callee.name);
94
+ if (sym && sym.kind === "function" && sym.arity !== undefined) {
95
+ if (expr.args.length !== sym.arity) {
96
+ error(expr.loc, `Function '${expr.callee.name}' expects ${sym.arity} argument(s), but got ${expr.args.length}`);
97
+ }
98
+ }
99
+ }
100
+ break;
101
+ }
102
+ case "MemberExpr":
103
+ analyzeExpr(expr.object, scope);
104
+ break;
105
+ case "IndexExpr":
106
+ analyzeExpr(expr.object, scope);
107
+ analyzeExpr(expr.index, scope);
108
+ break;
109
+ case "PipelineExpr":
110
+ analyzeExpr(expr.left, scope);
111
+ analyzeExpr(expr.right, scope);
112
+ break;
113
+ case "IfExpr":
114
+ analyzeExpr(expr.condition, scope);
115
+ analyzeExpr(expr.then, scope);
116
+ if (expr.else_)
117
+ analyzeExpr(expr.else_, scope);
118
+ break;
119
+ case "MatchExpr":
120
+ analyzeExpr(expr.subject, scope);
121
+ analyzeMatchExhaustiveness(expr, scope);
122
+ for (const arm of expr.arms) {
123
+ const armScope = new Scope(scope);
124
+ analyzePattern(arm.pattern, armScope);
125
+ if (arm.guard)
126
+ analyzeExpr(arm.guard, armScope);
127
+ analyzeExpr(arm.body, armScope);
128
+ }
129
+ break;
130
+ case "LambdaExpr": {
131
+ const lambdaScope = new Scope(scope);
132
+ for (const p of expr.params) {
133
+ lambdaScope.define(p, { mutable: false, kind: "parameter" });
134
+ }
135
+ analyzeExpr(expr.body, lambdaScope);
136
+ break;
137
+ }
138
+ case "ListLiteral":
139
+ for (const el of expr.elements)
140
+ analyzeExpr(el, scope);
141
+ break;
142
+ case "MapLiteral":
143
+ for (const entry of expr.entries) {
144
+ if (typeof entry.key !== "string")
145
+ analyzeExpr(entry.key, scope);
146
+ analyzeExpr(entry.value, scope);
147
+ }
148
+ break;
149
+ case "ListComprehension": {
150
+ analyzeExpr(expr.iterable, scope);
151
+ const compScope = new Scope(scope);
152
+ compScope.define(expr.variable, { mutable: false, kind: "loop-var" });
153
+ analyzeExpr(expr.expr, compScope);
154
+ if (expr.filter)
155
+ analyzeExpr(expr.filter, compScope);
156
+ break;
157
+ }
158
+ case "ToolCallExpr":
159
+ analyzeExpr(expr.arg, scope);
160
+ if (expr.body)
161
+ analyzeExpr(expr.body, scope);
162
+ break;
163
+ case "RangeExpr":
164
+ analyzeExpr(expr.start, scope);
165
+ analyzeExpr(expr.end, scope);
166
+ break;
167
+ case "BlockExpr": {
168
+ const blockScope = new Scope(scope);
169
+ analyzeStmts(expr.stmts, blockScope);
170
+ break;
171
+ }
172
+ case "AsyncExpr":
173
+ analyzeExpr(expr.body, scope);
174
+ break;
175
+ case "AwaitExpr":
176
+ analyzeExpr(expr.expr, scope);
177
+ break;
178
+ case "FetchExpr":
179
+ for (const t of expr.targets)
180
+ analyzeExpr(t, scope);
181
+ break;
182
+ }
183
+ }
184
+ function analyzePattern(pattern, scope) {
185
+ switch (pattern.kind) {
186
+ case "WildcardPattern":
187
+ break;
188
+ case "LiteralPattern":
189
+ break;
190
+ case "BindingPattern":
191
+ scope.define(pattern.name, { mutable: false, kind: "variable" });
192
+ break;
193
+ case "ArrayPattern":
194
+ for (const el of pattern.elements)
195
+ analyzePattern(el, scope);
196
+ break;
197
+ case "OrPattern":
198
+ for (const p of pattern.patterns)
199
+ analyzePattern(p, scope);
200
+ break;
201
+ }
202
+ }
203
+ function analyzeMatchExhaustiveness(expr, _scope) {
204
+ const arms = expr.arms;
205
+ if (arms.length === 0) {
206
+ warning(expr.loc, "Match expression has no arms");
207
+ return;
208
+ }
209
+ // Check if there's a wildcard or binding (catch-all) pattern without a guard
210
+ const hasCatchAll = arms.some(arm => !arm.guard && isCatchAllPattern(arm.pattern));
211
+ if (!hasCatchAll) {
212
+ warning(expr.loc, "Match expression may not be exhaustive — consider adding a wildcard '_' arm");
213
+ }
214
+ // Check for unreachable arms (arms after a catch-all without guard)
215
+ for (let i = 0; i < arms.length - 1; i++) {
216
+ if (!arms[i].guard && isCatchAllPattern(arms[i].pattern)) {
217
+ warning(arms[i + 1].body.loc, "Unreachable match arm — previous arm catches all patterns");
218
+ break;
219
+ }
220
+ }
221
+ }
222
+ function isCatchAllPattern(pattern) {
223
+ return pattern.kind === "WildcardPattern" || pattern.kind === "BindingPattern";
224
+ }
225
+ function analyzeStmts(stmts, scope) {
226
+ // First pass: register all function declarations (hoisting)
227
+ for (const stmt of stmts) {
228
+ if (stmt.kind === "FnStmt") {
229
+ scope.define(stmt.name, {
230
+ mutable: false,
231
+ kind: "function",
232
+ arity: stmt.params.length,
233
+ });
234
+ }
235
+ }
236
+ for (const stmt of stmts) {
237
+ analyzeStmt(stmt, scope);
238
+ }
239
+ }
240
+ function analyzeStmt(stmt, scope) {
241
+ switch (stmt.kind) {
242
+ case "LetStmt": {
243
+ analyzeExpr(stmt.value, scope);
244
+ if (typeof stmt.name === "string") {
245
+ scope.define(stmt.name, {
246
+ mutable: stmt.mutable,
247
+ kind: "variable",
248
+ });
249
+ }
250
+ else {
251
+ // DestructureTarget
252
+ for (const n of stmt.name.names) {
253
+ scope.define(n, {
254
+ mutable: stmt.mutable,
255
+ kind: "destructured",
256
+ });
257
+ }
258
+ }
259
+ break;
260
+ }
261
+ case "FnStmt": {
262
+ // Already registered in first pass; now analyze body
263
+ const fnScope = new Scope(scope);
264
+ for (const p of stmt.params) {
265
+ fnScope.define(p, { mutable: false, kind: "parameter" });
266
+ }
267
+ analyzeExpr(stmt.body, fnScope);
268
+ break;
269
+ }
270
+ case "ForStmt": {
271
+ analyzeExpr(stmt.iterable, scope);
272
+ const forScope = new Scope(scope);
273
+ forScope.define(stmt.variable, { mutable: false, kind: "loop-var" });
274
+ analyzeExpr(stmt.body, forScope);
275
+ break;
276
+ }
277
+ case "DoStmt":
278
+ analyzeExpr(stmt.body, scope);
279
+ analyzeExpr(stmt.condition, scope);
280
+ break;
281
+ case "ExprStmt":
282
+ analyzeExpr(stmt.expr, scope);
283
+ break;
284
+ case "UseStmt":
285
+ // Register imported names
286
+ if (stmt.imports) {
287
+ for (const imp of stmt.imports) {
288
+ scope.define(imp, { mutable: false, kind: "import" });
289
+ }
290
+ }
291
+ else if (stmt.wildcard) {
292
+ // Wildcard import — can't track names statically
293
+ }
294
+ else {
295
+ // Default: import the module name
296
+ const moduleName = stmt.path[stmt.path.length - 1];
297
+ scope.define(moduleName, { mutable: false, kind: "import" });
298
+ }
299
+ break;
300
+ case "TypeStmt":
301
+ scope.define(stmt.name, { mutable: false, kind: "type" });
302
+ break;
303
+ case "AssignStmt": {
304
+ const sym = scope.lookup(stmt.target);
305
+ if (!sym && !BUILTINS.has(stmt.target)) {
306
+ error(stmt.loc, `Undefined variable: '${stmt.target}'`);
307
+ }
308
+ else if (sym && !sym.mutable) {
309
+ error(stmt.loc, `Cannot reassign immutable variable: '${stmt.target}'`);
310
+ }
311
+ analyzeExpr(stmt.value, scope);
312
+ break;
313
+ }
314
+ case "MemberAssignStmt":
315
+ analyzeExpr(stmt.object, scope);
316
+ analyzeExpr(stmt.value, scope);
317
+ break;
318
+ case "IndexAssignStmt":
319
+ analyzeExpr(stmt.object, scope);
320
+ analyzeExpr(stmt.index, scope);
321
+ analyzeExpr(stmt.value, scope);
322
+ break;
323
+ }
324
+ }
325
+ analyzeStmts(program.stmts, globalScope);
326
+ return diagnostics;
327
+ }
@@ -0,0 +1,7 @@
1
+ import * as AST from "./ast.js";
2
+ export interface Diagnostic {
3
+ level: "error" | "warning";
4
+ message: string;
5
+ loc?: AST.Loc;
6
+ }
7
+ export declare function typecheck(program: AST.Program): Diagnostic[];
@@ -0,0 +1,132 @@
1
+ // Arc Language Type Checker (basic)
2
+ export function typecheck(program) {
3
+ const diagnostics = [];
4
+ const typeDefinitions = new Map();
5
+ const knownBaseTypes = new Set(["Int", "Float", "String", "Bool", "Nil", "Any"]);
6
+ // First pass: collect type definitions
7
+ for (const stmt of program.stmts) {
8
+ if (stmt.kind === "TypeStmt") {
9
+ typeDefinitions.set(stmt.name, stmt.def);
10
+ }
11
+ }
12
+ // Second pass: validate type definitions
13
+ for (const [name, def] of typeDefinitions) {
14
+ validateTypeExpr(def, name);
15
+ }
16
+ // Third pass: check match exhaustiveness
17
+ for (const stmt of program.stmts) {
18
+ walkStmt(stmt);
19
+ }
20
+ function validateTypeExpr(typeExpr, context) {
21
+ switch (typeExpr.kind) {
22
+ case "NamedType":
23
+ if (!knownBaseTypes.has(typeExpr.name) && !typeDefinitions.has(typeExpr.name)) {
24
+ // Could be a type parameter, so just warn
25
+ // Don't warn for single-letter names (type params)
26
+ if (typeExpr.name.length > 1) {
27
+ diagnostics.push({
28
+ level: "warning",
29
+ message: `Unknown type '${typeExpr.name}' in definition of '${context}'`,
30
+ });
31
+ }
32
+ }
33
+ break;
34
+ case "ConstrainedType":
35
+ validateTypeExpr(typeExpr.base, context);
36
+ if (typeExpr.base.kind === "NamedType") {
37
+ const baseName = typeExpr.base.name;
38
+ if (typeExpr.constraint === "matching" && baseName !== "String") {
39
+ diagnostics.push({
40
+ level: "error",
41
+ message: `'matching' constraint can only be applied to String type, got '${baseName}' in '${context}'`,
42
+ });
43
+ }
44
+ if (typeExpr.constraint === "where" && !knownBaseTypes.has(baseName) && !typeDefinitions.has(baseName)) {
45
+ diagnostics.push({
46
+ level: "warning",
47
+ message: `'where' constraint on unknown base type '${baseName}' in '${context}'`,
48
+ });
49
+ }
50
+ }
51
+ break;
52
+ case "RecordType":
53
+ for (const field of typeExpr.fields) {
54
+ validateTypeExpr(field.type, context);
55
+ }
56
+ break;
57
+ case "FunctionType":
58
+ for (const param of typeExpr.params) {
59
+ validateTypeExpr(param, context);
60
+ }
61
+ validateTypeExpr(typeExpr.ret, context);
62
+ break;
63
+ case "EnumType":
64
+ for (const variant of typeExpr.variants) {
65
+ if (variant.params) {
66
+ for (const p of variant.params) {
67
+ validateTypeExpr(p, context);
68
+ }
69
+ }
70
+ }
71
+ break;
72
+ case "GenericType":
73
+ for (const p of typeExpr.params) {
74
+ validateTypeExpr(p, context);
75
+ }
76
+ break;
77
+ case "UnionType":
78
+ for (const v of typeExpr.variants) {
79
+ validateTypeExpr(v, context);
80
+ }
81
+ break;
82
+ }
83
+ }
84
+ function walkStmt(stmt) {
85
+ if (stmt.kind === "ExprStmt") {
86
+ walkExpr(stmt.expr);
87
+ }
88
+ else if (stmt.kind === "LetStmt") {
89
+ walkExpr(stmt.value);
90
+ }
91
+ else if (stmt.kind === "FnStmt") {
92
+ walkExpr(stmt.body);
93
+ }
94
+ else if (stmt.kind === "ForStmt") {
95
+ walkExpr(stmt.iterable);
96
+ walkExpr(stmt.body);
97
+ }
98
+ }
99
+ function walkExpr(expr) {
100
+ if (expr.kind === "MatchExpr") {
101
+ checkMatchExhaustiveness(expr);
102
+ for (const arm of expr.arms) {
103
+ walkExpr(arm.body);
104
+ }
105
+ }
106
+ else if (expr.kind === "BlockExpr") {
107
+ for (const s of expr.stmts) {
108
+ walkStmt(s);
109
+ }
110
+ }
111
+ else if (expr.kind === "IfExpr") {
112
+ walkExpr(expr.then);
113
+ if (expr.else_)
114
+ walkExpr(expr.else_);
115
+ }
116
+ }
117
+ function checkMatchExhaustiveness(matchExpr) {
118
+ const hasWildcard = matchExpr.arms.some(a => a.pattern.kind === "WildcardPattern");
119
+ if (!hasWildcard) {
120
+ // Check if subject is a known enum type
121
+ if (matchExpr.subject.kind === "Identifier") {
122
+ // Can't easily determine type without full type inference, so just warn
123
+ diagnostics.push({
124
+ level: "warning",
125
+ message: `Match expression may not be exhaustive (no wildcard pattern)`,
126
+ loc: matchExpr.loc,
127
+ });
128
+ }
129
+ }
130
+ }
131
+ return diagnostics;
132
+ }
@@ -0,0 +1,26 @@
1
+ export declare const ARC_VERSION = "0.5.0";
2
+ export declare const ARC_BUILD_DATE: string;
3
+ export declare const ARC_PLATFORM: string;
4
+ /** Print version info */
5
+ export declare function printVersion(): void;
6
+ /** Semver comparison: returns -1, 0, or 1 */
7
+ export declare function compareSemver(a: string, b: string): number;
8
+ /** Check if a manifest's arc version requirement is compatible */
9
+ export declare function checkVersionCompatibility(required: string): {
10
+ compatible: boolean;
11
+ message: string;
12
+ };
13
+ /** Deprecation registry */
14
+ interface DeprecationEntry {
15
+ feature: string;
16
+ since: string;
17
+ removeIn: string;
18
+ migration: string;
19
+ }
20
+ /** Register a deprecated feature */
21
+ export declare function deprecate(feature: string, since: string, removeIn: string, migration: string): void;
22
+ /** Emit a deprecation warning (once per feature per session) */
23
+ export declare function emitDeprecationWarning(feature: string): void;
24
+ /** Get all registered deprecations */
25
+ export declare function getDeprecations(): readonly DeprecationEntry[];
26
+ export {};
@@ -0,0 +1,71 @@
1
+ // Arc Version System
2
+ export const ARC_VERSION = "0.5.0";
3
+ export const ARC_BUILD_DATE = new Date().toISOString().split("T")[0];
4
+ export const ARC_PLATFORM = `${process.platform}-${process.arch}`;
5
+ /** Print version info */
6
+ export function printVersion() {
7
+ console.log(`Arc ${ARC_VERSION}`);
8
+ console.log(`Build date: ${ARC_BUILD_DATE}`);
9
+ console.log(`Platform: ${ARC_PLATFORM}`);
10
+ console.log(`Node.js: ${process.version}`);
11
+ }
12
+ /** Semver comparison: returns -1, 0, or 1 */
13
+ export function compareSemver(a, b) {
14
+ const pa = a.split(".").map(Number);
15
+ const pb = b.split(".").map(Number);
16
+ for (let i = 0; i < 3; i++) {
17
+ if (pa[i] < pb[i])
18
+ return -1;
19
+ if (pa[i] > pb[i])
20
+ return 1;
21
+ }
22
+ return 0;
23
+ }
24
+ /** Check if a manifest's arc version requirement is compatible */
25
+ export function checkVersionCompatibility(required) {
26
+ // Support formats: "0.5.0", ">=0.4.0", "^0.5.0", "~0.5.0"
27
+ const current = ARC_VERSION;
28
+ if (required.startsWith(">=")) {
29
+ const min = required.slice(2);
30
+ const ok = compareSemver(current, min) >= 0;
31
+ return { compatible: ok, message: ok ? "Compatible" : `Requires Arc >=${min}, current is ${current}` };
32
+ }
33
+ if (required.startsWith("^")) {
34
+ const base = required.slice(1);
35
+ const [major] = base.split(".").map(Number);
36
+ const [curMajor] = current.split(".").map(Number);
37
+ const ok = curMajor === major && compareSemver(current, base) >= 0;
38
+ return { compatible: ok, message: ok ? "Compatible" : `Requires Arc ${required}, current is ${current}` };
39
+ }
40
+ if (required.startsWith("~")) {
41
+ const base = required.slice(1);
42
+ const parts = base.split(".").map(Number);
43
+ const curParts = current.split(".").map(Number);
44
+ const ok = curParts[0] === parts[0] && curParts[1] === parts[1] && compareSemver(current, base) >= 0;
45
+ return { compatible: ok, message: ok ? "Compatible" : `Requires Arc ${required}, current is ${current}` };
46
+ }
47
+ // Exact match
48
+ const ok = compareSemver(current, required) >= 0;
49
+ return { compatible: ok, message: ok ? "Compatible" : `Requires Arc ${required}, current is ${current}` };
50
+ }
51
+ const deprecations = [];
52
+ const emittedWarnings = new Set();
53
+ /** Register a deprecated feature */
54
+ export function deprecate(feature, since, removeIn, migration) {
55
+ deprecations.push({ feature, since, removeIn, migration });
56
+ }
57
+ /** Emit a deprecation warning (once per feature per session) */
58
+ export function emitDeprecationWarning(feature) {
59
+ if (emittedWarnings.has(feature))
60
+ return;
61
+ const entry = deprecations.find(d => d.feature === feature);
62
+ if (!entry)
63
+ return;
64
+ emittedWarnings.add(feature);
65
+ console.warn(`⚠ DEPRECATED: '${feature}' was deprecated in v${entry.since} and will be removed in v${entry.removeIn}.`);
66
+ console.warn(` Migration: ${entry.migration}`);
67
+ }
68
+ /** Get all registered deprecations */
69
+ export function getDeprecations() {
70
+ return deprecations;
71
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "arc-lang",
3
+ "version": "0.5.0",
4
+ "description": "Arc ⚡ — A programming language designed by AI agents, for AI agents. 27-63% fewer tokens than JavaScript.",
5
+ "type": "module",
6
+ "bin": {
7
+ "arc": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "files": [
11
+ "dist/",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "prepublishOnly": "tsc",
18
+ "run": "tsx src/index.ts run",
19
+ "parse": "tsx src/index.ts parse"
20
+ },
21
+ "keywords": [
22
+ "arc",
23
+ "programming-language",
24
+ "ai",
25
+ "ai-agents",
26
+ "compiler",
27
+ "token-efficient",
28
+ "language",
29
+ "interpreter",
30
+ "repl"
31
+ ],
32
+ "author": "Kai <nebula7458@proton.me> (https://arclang.dev)",
33
+ "license": "MIT",
34
+ "homepage": "https://arclang.dev",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/kai-builds-ai/arc-lang.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/kai-builds-ai/arc-lang/issues"
41
+ },
42
+ "dependencies": {
43
+ "tsx": "^4.7.0",
44
+ "typescript": "^5.3.0",
45
+ "vscode-languageserver": "^9.0.1",
46
+ "vscode-languageserver-textdocument": "^1.0.12"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^25.2.3"
50
+ }
51
+ }