@coze-editor/code-language-json 0.1.0-alpha.09ffeb

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 coze-dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,266 @@
1
+ // src/index.ts
2
+ import { URI } from "vscode-uri";
3
+ import {
4
+ getLanguageService,
5
+ TextDocument,
6
+ DiagnosticSeverity
7
+ } from "vscode-json-languageservice";
8
+ import { Text } from "text-mapping";
9
+ import { v4 as uuid } from "@lukeed/uuid";
10
+ import { parse } from "@coze-editor/parser-json";
11
+ import {
12
+ textDocumentField
13
+ } from "@coze-editor/code-language-shared";
14
+
15
+ // src/json.ts
16
+ import { parser } from "@coze-editor/lezer-parser-json";
17
+ import {
18
+ continuedIndent,
19
+ indentNodeProp,
20
+ foldNodeProp,
21
+ foldInside,
22
+ LRLanguage
23
+ } from "@codemirror/language";
24
+ var jsonLanguage = LRLanguage.define({
25
+ name: "json",
26
+ parser: parser.configure({
27
+ props: [
28
+ indentNodeProp.add({
29
+ Object: continuedIndent({ except: /^\s*\}/ }),
30
+ Array: continuedIndent({ except: /^\s*\]/ })
31
+ }),
32
+ foldNodeProp.add({
33
+ "Object Array": foldInside
34
+ })
35
+ ]
36
+ }),
37
+ languageData: {
38
+ closeBrackets: { brackets: ["[", "{", '"', "'"] },
39
+ indentOnInput: /^\s*[\}\]]$/
40
+ }
41
+ });
42
+
43
+ // src/index.ts
44
+ function normalizeId(id) {
45
+ try {
46
+ return URI.parse(id).toString(true);
47
+ } catch (e) {
48
+ return id;
49
+ }
50
+ }
51
+ function isNonNull(value) {
52
+ return Boolean(value);
53
+ }
54
+ var urlReg = /^(https?:\/\/|www\.)[\w-\.]+\.[\w-\.]+(\/([\S]+)?)?$/i;
55
+ var JSONLanguageService = class {
56
+ constructor(options) {
57
+ this.options = options;
58
+ this.languageService = getLanguageService({});
59
+ this.configure();
60
+ }
61
+ languageService;
62
+ schemasConfigurations = [];
63
+ triggerCharacters = [":", '"', "'"];
64
+ configure() {
65
+ this.languageService.configure({
66
+ allowComments: false,
67
+ schemas: this.schemasConfigurations.map((e) => ({
68
+ fileMatch: e.fileMatch,
69
+ uri: normalizeId(e.uri),
70
+ schema: e.schema
71
+ }))
72
+ });
73
+ }
74
+ parseJSONDocument(textDocument) {
75
+ const text = parse(textDocument, { collectComments: true });
76
+ if (!text.ast) {
77
+ return;
78
+ }
79
+ const jsonDocument = this.languageService.newJSONDocument(
80
+ text.ast,
81
+ text.problems
82
+ );
83
+ jsonDocument.comments = text.commentRanges;
84
+ return jsonDocument;
85
+ }
86
+ async validate(source, options) {
87
+ let text = new Text(source);
88
+ if (typeof (options == null ? void 0 : options.transform) === "function") {
89
+ text = options.transform(text);
90
+ }
91
+ const textDocument = TextDocument.create(
92
+ `file:///anonymous-${uuid()}.json`,
93
+ "json",
94
+ 0,
95
+ text.toString()
96
+ );
97
+ const jsonDocument = this.parseJSONDocument(textDocument);
98
+ if (!jsonDocument) {
99
+ return [];
100
+ }
101
+ const diagnostics = await this.languageService.doValidation(
102
+ textDocument,
103
+ jsonDocument,
104
+ {},
105
+ options == null ? void 0 : options.schema
106
+ );
107
+ return diagnostics.map((e) => {
108
+ const from = textDocument.offsetAt(e.range.start);
109
+ const to = textDocument.offsetAt(e.range.end);
110
+ return {
111
+ from,
112
+ to,
113
+ severity: e.severity,
114
+ message: e.message
115
+ };
116
+ }).map((e) => {
117
+ const oRange = text.originalRangeFor({
118
+ from: e.from,
119
+ to: e.to
120
+ });
121
+ if (!oRange) {
122
+ return;
123
+ }
124
+ return {
125
+ ...e,
126
+ ...oRange
127
+ };
128
+ }).filter(isNonNull);
129
+ }
130
+ configureSchemas(config) {
131
+ let configs = [];
132
+ configs = configs.concat(config);
133
+ configs.forEach((c) => {
134
+ const match = this.schemasConfigurations.find((e) => e.uri === c.uri);
135
+ if (match) {
136
+ match.schema = c.schema;
137
+ match.fileMatch = c.fileMatch;
138
+ } else {
139
+ this.schemasConfigurations.push(c);
140
+ }
141
+ });
142
+ this.configure();
143
+ }
144
+ deleteSchemas(uri) {
145
+ let allURI = [];
146
+ allURI = allURI.concat(uri);
147
+ this.schemasConfigurations = this.schemasConfigurations.filter(
148
+ (c) => !allURI.includes(c.uri)
149
+ );
150
+ this.configure();
151
+ }
152
+ async doValidation(context) {
153
+ const { textDocument } = context;
154
+ const jsonDocument = this.parseJSONDocument(textDocument);
155
+ if (!jsonDocument) {
156
+ return [];
157
+ }
158
+ const diagnostics = await this.languageService.doValidation(
159
+ textDocument,
160
+ jsonDocument
161
+ );
162
+ return diagnostics.map((e) => {
163
+ const from = textDocument.offsetAt(e.range.start);
164
+ const to = textDocument.offsetAt(e.range.end);
165
+ return {
166
+ from,
167
+ to,
168
+ severity: "error",
169
+ message: e.message
170
+ };
171
+ });
172
+ }
173
+ async format(state, options) {
174
+ const { textDocument, originalRangeFor } = state.field(textDocumentField);
175
+ const edits = this.languageService.format(
176
+ textDocument,
177
+ // @ts-expect-error range can be undefined
178
+ void 0,
179
+ {
180
+ tabSize: (options == null ? void 0 : options.tabSize) ?? 4,
181
+ insertSpaces: true,
182
+ insertFinalNewline: false
183
+ }
184
+ );
185
+ const changes = edits.map((edit) => {
186
+ const range = originalRangeFor({
187
+ from: textDocument.offsetAt(edit.range.start),
188
+ to: textDocument.offsetAt(edit.range.end)
189
+ });
190
+ if (range) {
191
+ return {
192
+ ...range,
193
+ insert: edit.newText
194
+ };
195
+ }
196
+ }).filter((v) => isChangeDesc(v));
197
+ return {
198
+ changes
199
+ };
200
+ }
201
+ async doComplete(context) {
202
+ const { textDocument } = context;
203
+ const { offset } = context;
204
+ const { line, character } = textDocument.positionAt(offset);
205
+ const jsonDocument = this.parseJSONDocument(textDocument);
206
+ if (!jsonDocument) {
207
+ return;
208
+ }
209
+ const completionResult = await this.languageService.doComplete(
210
+ textDocument,
211
+ {
212
+ line,
213
+ character
214
+ },
215
+ jsonDocument
216
+ );
217
+ if (!completionResult || !completionResult.items.length) {
218
+ return;
219
+ }
220
+ return {
221
+ isIncomplete: true,
222
+ items: completionResult.items
223
+ };
224
+ }
225
+ async findLinks(context) {
226
+ const { textDocument } = context;
227
+ const doc = this.parseJSONDocument(textDocument);
228
+ if (!doc) {
229
+ return [];
230
+ }
231
+ const links = [];
232
+ doc.visit((node) => {
233
+ if (node.type === "string" && urlReg.test(node.value)) {
234
+ const range = {
235
+ from: node.offset + 1,
236
+ to: node.offset + node.length - 1
237
+ };
238
+ links.push({
239
+ target: node.value,
240
+ range
241
+ });
242
+ }
243
+ return true;
244
+ });
245
+ return links;
246
+ }
247
+ };
248
+ function isChangeDesc(v) {
249
+ return Boolean(v);
250
+ }
251
+ var jsonLanguageService = new JSONLanguageService({
252
+ lintDelay: 0
253
+ });
254
+ var json = {
255
+ language: jsonLanguage,
256
+ languageService: jsonLanguageService
257
+ };
258
+ export {
259
+ DiagnosticSeverity,
260
+ JSONLanguageService,
261
+ Text,
262
+ json,
263
+ jsonLanguage,
264
+ jsonLanguageService
265
+ };
266
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/index.ts","../../src/json.ts"],"sourcesContent":["// Copyright (c) 2025 coze-dev\n// SPDX-License-Identifier: MIT\n\nimport { URI } from 'vscode-uri';\nimport {\n getLanguageService,\n TextDocument,\n type LanguageService,\n type JSONSchema,\n type CompletionList,\n type JSONDocument,\n DiagnosticSeverity,\n} from 'vscode-json-languageservice';\nimport { Text } from 'text-mapping';\nimport { v4 as uuid } from '@lukeed/uuid';\nimport { parse } from '@coze-editor/parser-json';\nimport {\n type LanguageService as ILanguageService,\n type LanguageServiceOptions,\n type Link,\n textDocumentField,\n} from '@coze-editor/code-language-shared';\nimport {\n type ChangeSpec,\n type EditorState,\n type TransactionSpec,\n} from '@codemirror/state';\n\nimport { jsonLanguage } from './json';\n\ninterface SchemasConfiguration {\n uri: string;\n fileMatch: string[];\n schema: JSONSchema;\n}\n\ninterface ValidateOptions {\n schema?: JSONSchema;\n transform?: (text: Text) => Text;\n}\n\nfunction normalizeId(id: string) {\n // remove trailing '#', normalize drive capitalization\n try {\n return URI.parse(id).toString(true);\n } catch (e) {\n return id;\n }\n}\n\nfunction isNonNull<T>(value: T | undefined): value is T {\n return Boolean(value);\n}\n\nconst urlReg = /^(https?:\\/\\/|www\\.)[\\w-\\.]+\\.[\\w-\\.]+(\\/([\\S]+)?)?$/i;\n\nclass JSONLanguageService implements ILanguageService {\n protected languageService: LanguageService;\n private schemasConfigurations: SchemasConfiguration[] = [];\n public triggerCharacters = [':', '\"', \"'\"];\n\n constructor(public options: LanguageServiceOptions) {\n this.languageService = getLanguageService({});\n this.configure();\n }\n\n private configure() {\n this.languageService.configure({\n allowComments: false,\n schemas: this.schemasConfigurations.map(e => ({\n fileMatch: e.fileMatch,\n uri: normalizeId(e.uri),\n schema: e.schema,\n })),\n });\n }\n\n private parseJSONDocument(\n textDocument: TextDocument,\n ): JSONDocument | undefined {\n const text = parse(textDocument, { collectComments: true });\n if (!text.ast) {\n return;\n }\n\n const jsonDocument = this.languageService.newJSONDocument(\n text.ast,\n text.problems,\n );\n // @ts-expect-error comments type is not exported\n jsonDocument.comments = text.commentRanges;\n return jsonDocument;\n }\n\n public async validate(source: string, options?: ValidateOptions) {\n let text = new Text(source);\n\n if (typeof options?.transform === 'function') {\n text = options.transform(text);\n }\n\n const textDocument = TextDocument.create(\n `file:///anonymous-${uuid()}.json`,\n 'json',\n 0,\n text.toString(),\n );\n const jsonDocument = this.parseJSONDocument(textDocument);\n\n if (!jsonDocument) {\n return [];\n }\n\n const diagnostics = await this.languageService.doValidation(\n textDocument,\n jsonDocument,\n {},\n options?.schema,\n );\n\n return diagnostics\n .map(e => {\n const from = textDocument.offsetAt(e.range.start);\n const to = textDocument.offsetAt(e.range.end);\n\n return {\n from,\n to,\n severity: e.severity,\n message: e.message,\n };\n })\n .map(e => {\n const oRange = text.originalRangeFor({\n from: e.from,\n to: e.to,\n });\n if (!oRange) {\n return;\n }\n return {\n ...e,\n ...oRange,\n };\n })\n .filter(isNonNull);\n }\n\n public configureSchemas(\n config: SchemasConfiguration | SchemasConfiguration[],\n ) {\n let configs: SchemasConfiguration[] = [];\n configs = configs.concat(config);\n\n configs.forEach(c => {\n const match = this.schemasConfigurations.find(e => e.uri === c.uri);\n if (match) {\n match.schema = c.schema;\n match.fileMatch = c.fileMatch;\n } else {\n this.schemasConfigurations.push(c);\n }\n });\n\n this.configure();\n }\n\n public deleteSchemas(uri: string | string[]) {\n let allURI: string[] = [];\n allURI = allURI.concat(uri);\n\n this.schemasConfigurations = this.schemasConfigurations.filter(\n c => !allURI.includes(c.uri),\n );\n\n this.configure();\n }\n\n public async doValidation(\n context: Parameters<NonNullable<ILanguageService['doValidation']>>[0],\n ) {\n const { textDocument } = context;\n const jsonDocument = this.parseJSONDocument(textDocument);\n\n if (!jsonDocument) {\n return [];\n }\n\n const diagnostics = await this.languageService.doValidation(\n textDocument,\n jsonDocument,\n );\n\n return diagnostics.map(e => {\n const from = textDocument.offsetAt(e.range.start);\n const to = textDocument.offsetAt(e.range.end);\n\n return {\n from,\n to,\n severity: 'error' as const,\n message: e.message,\n };\n });\n }\n\n async format(\n state: EditorState,\n options?: { tabSize: number },\n ): Promise<TransactionSpec> {\n const { textDocument, originalRangeFor } = state.field(textDocumentField);\n\n const edits = this.languageService.format(\n textDocument,\n // @ts-expect-error range can be undefined\n undefined,\n {\n tabSize: options?.tabSize ?? 4,\n insertSpaces: true,\n insertFinalNewline: false,\n },\n );\n\n const changes = edits\n .map(edit => {\n const range = originalRangeFor({\n from: textDocument.offsetAt(edit.range.start),\n to: textDocument.offsetAt(edit.range.end),\n });\n if (range) {\n return {\n ...range,\n insert: edit.newText,\n };\n }\n })\n .filter(v => isChangeDesc(v));\n\n return {\n changes,\n };\n }\n\n public async doComplete(\n context: Parameters<NonNullable<ILanguageService['doComplete']>>[0],\n ): Promise<CompletionList | null | undefined> {\n const { textDocument } = context;\n const { offset } = context;\n\n const { line, character } = textDocument.positionAt(offset);\n\n const jsonDocument = this.parseJSONDocument(textDocument);\n\n if (!jsonDocument) {\n return;\n }\n\n const completionResult = await this.languageService.doComplete(\n textDocument,\n {\n line,\n character,\n },\n jsonDocument,\n );\n\n if (!completionResult || !completionResult.items.length) {\n return;\n }\n\n return {\n isIncomplete: true,\n items: completionResult.items,\n };\n }\n\n async findLinks(\n context: Parameters<NonNullable<ILanguageService['findLinks']>>[0],\n ) {\n const { textDocument } = context;\n const doc = this.parseJSONDocument(textDocument);\n\n if (!doc) {\n return [];\n }\n\n const links: Link[] = [];\n\n // @ts-expect-error doc.visit is not exposed but indeed exists\n doc.visit(node => {\n if (node.type === 'string' && urlReg.test(node.value)) {\n const range = {\n from: node.offset + 1,\n to: node.offset + node.length - 1,\n };\n\n links.push({\n target: node.value,\n range,\n });\n }\n return true;\n });\n\n return links;\n }\n}\n\nfunction isChangeDesc(v: unknown): v is ChangeSpec {\n return Boolean(v);\n}\n\nconst jsonLanguageService = new JSONLanguageService({\n lintDelay: 0,\n});\n\nconst json = {\n language: jsonLanguage,\n languageService: jsonLanguageService,\n};\n\nexport { json, jsonLanguage, jsonLanguageService, JSONLanguageService };\n\nexport { DiagnosticSeverity, Text };\n","// Copyright (c) 2025 coze-dev\n// SPDX-License-Identifier: MIT\n\nimport { parser } from '@coze-editor/lezer-parser-json';\nimport {\n continuedIndent,\n indentNodeProp,\n foldNodeProp,\n foldInside,\n LRLanguage,\n} from '@codemirror/language';\n\n/// A language provider that provides JSON parsing.\nexport const jsonLanguage = LRLanguage.define({\n name: 'json',\n parser: parser.configure({\n props: [\n indentNodeProp.add({\n Object: continuedIndent({ except: /^\\s*\\}/ }),\n Array: continuedIndent({ except: /^\\s*\\]/ }),\n }),\n foldNodeProp.add({\n 'Object Array': foldInside,\n }),\n ],\n }),\n languageData: {\n closeBrackets: { brackets: ['[', '{', '\"', \"'\"] },\n\n indentOnInput: /^\\s*[\\}\\]]$/,\n },\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,55 @@
1
+ import * as _codemirror_language from '@codemirror/language';
2
+ import { LRLanguage } from '@codemirror/language';
3
+ import { LanguageService as LanguageService$1, JSONSchema, DiagnosticSeverity, CompletionList } from 'vscode-json-languageservice';
4
+ export { DiagnosticSeverity } from 'vscode-json-languageservice';
5
+ import { Text } from 'text-mapping';
6
+ export { Text } from 'text-mapping';
7
+ import { LanguageService, LanguageServiceOptions, Link } from '@coze-editor/code-language-shared';
8
+ import { EditorState, TransactionSpec } from '@codemirror/state';
9
+
10
+ declare const jsonLanguage: LRLanguage;
11
+
12
+ interface SchemasConfiguration {
13
+ uri: string;
14
+ fileMatch: string[];
15
+ schema: JSONSchema;
16
+ }
17
+ interface ValidateOptions {
18
+ schema?: JSONSchema;
19
+ transform?: (text: Text) => Text;
20
+ }
21
+ declare class JSONLanguageService implements LanguageService {
22
+ options: LanguageServiceOptions;
23
+ protected languageService: LanguageService$1;
24
+ private schemasConfigurations;
25
+ triggerCharacters: string[];
26
+ constructor(options: LanguageServiceOptions);
27
+ private configure;
28
+ private parseJSONDocument;
29
+ validate(source: string, options?: ValidateOptions): Promise<{
30
+ from: number;
31
+ to: number;
32
+ severity: DiagnosticSeverity | undefined;
33
+ message: string;
34
+ }[]>;
35
+ configureSchemas(config: SchemasConfiguration | SchemasConfiguration[]): void;
36
+ deleteSchemas(uri: string | string[]): void;
37
+ doValidation(context: Parameters<NonNullable<LanguageService['doValidation']>>[0]): Promise<{
38
+ from: number;
39
+ to: number;
40
+ severity: "error";
41
+ message: string;
42
+ }[]>;
43
+ format(state: EditorState, options?: {
44
+ tabSize: number;
45
+ }): Promise<TransactionSpec>;
46
+ doComplete(context: Parameters<NonNullable<LanguageService['doComplete']>>[0]): Promise<CompletionList | null | undefined>;
47
+ findLinks(context: Parameters<NonNullable<LanguageService['findLinks']>>[0]): Promise<Link[]>;
48
+ }
49
+ declare const jsonLanguageService: JSONLanguageService;
50
+ declare const json: {
51
+ language: _codemirror_language.LRLanguage;
52
+ languageService: JSONLanguageService;
53
+ };
54
+
55
+ export { JSONLanguageService, json, jsonLanguage, jsonLanguageService };
@@ -0,0 +1,55 @@
1
+ import * as _codemirror_language from '@codemirror/language';
2
+ import { LRLanguage } from '@codemirror/language';
3
+ import { LanguageService as LanguageService$1, JSONSchema, DiagnosticSeverity, CompletionList } from 'vscode-json-languageservice';
4
+ export { DiagnosticSeverity } from 'vscode-json-languageservice';
5
+ import { Text } from 'text-mapping';
6
+ export { Text } from 'text-mapping';
7
+ import { LanguageService, LanguageServiceOptions, Link } from '@coze-editor/code-language-shared';
8
+ import { EditorState, TransactionSpec } from '@codemirror/state';
9
+
10
+ declare const jsonLanguage: LRLanguage;
11
+
12
+ interface SchemasConfiguration {
13
+ uri: string;
14
+ fileMatch: string[];
15
+ schema: JSONSchema;
16
+ }
17
+ interface ValidateOptions {
18
+ schema?: JSONSchema;
19
+ transform?: (text: Text) => Text;
20
+ }
21
+ declare class JSONLanguageService implements LanguageService {
22
+ options: LanguageServiceOptions;
23
+ protected languageService: LanguageService$1;
24
+ private schemasConfigurations;
25
+ triggerCharacters: string[];
26
+ constructor(options: LanguageServiceOptions);
27
+ private configure;
28
+ private parseJSONDocument;
29
+ validate(source: string, options?: ValidateOptions): Promise<{
30
+ from: number;
31
+ to: number;
32
+ severity: DiagnosticSeverity | undefined;
33
+ message: string;
34
+ }[]>;
35
+ configureSchemas(config: SchemasConfiguration | SchemasConfiguration[]): void;
36
+ deleteSchemas(uri: string | string[]): void;
37
+ doValidation(context: Parameters<NonNullable<LanguageService['doValidation']>>[0]): Promise<{
38
+ from: number;
39
+ to: number;
40
+ severity: "error";
41
+ message: string;
42
+ }[]>;
43
+ format(state: EditorState, options?: {
44
+ tabSize: number;
45
+ }): Promise<TransactionSpec>;
46
+ doComplete(context: Parameters<NonNullable<LanguageService['doComplete']>>[0]): Promise<CompletionList | null | undefined>;
47
+ findLinks(context: Parameters<NonNullable<LanguageService['findLinks']>>[0]): Promise<Link[]>;
48
+ }
49
+ declare const jsonLanguageService: JSONLanguageService;
50
+ declare const json: {
51
+ language: _codemirror_language.LRLanguage;
52
+ languageService: JSONLanguageService;
53
+ };
54
+
55
+ export { JSONLanguageService, json, jsonLanguage, jsonLanguageService };
package/dist/index.js ADDED
@@ -0,0 +1,283 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/index.ts
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ DiagnosticSeverity: () => import_vscode_json_languageservice.DiagnosticSeverity,
23
+ JSONLanguageService: () => JSONLanguageService,
24
+ Text: () => import_text_mapping.Text,
25
+ json: () => json,
26
+ jsonLanguage: () => jsonLanguage,
27
+ jsonLanguageService: () => jsonLanguageService
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_vscode_uri = require("vscode-uri");
31
+ var import_vscode_json_languageservice = require("vscode-json-languageservice");
32
+ var import_text_mapping = require("text-mapping");
33
+ var import_uuid = require("@lukeed/uuid");
34
+ var import_parser_json = require("@coze-editor/parser-json");
35
+ var import_code_language_shared = require("@coze-editor/code-language-shared");
36
+
37
+ // src/json.ts
38
+ var import_lezer_parser_json = require("@coze-editor/lezer-parser-json");
39
+ var import_language = require("@codemirror/language");
40
+ var jsonLanguage = import_language.LRLanguage.define({
41
+ name: "json",
42
+ parser: import_lezer_parser_json.parser.configure({
43
+ props: [
44
+ import_language.indentNodeProp.add({
45
+ Object: (0, import_language.continuedIndent)({ except: /^\s*\}/ }),
46
+ Array: (0, import_language.continuedIndent)({ except: /^\s*\]/ })
47
+ }),
48
+ import_language.foldNodeProp.add({
49
+ "Object Array": import_language.foldInside
50
+ })
51
+ ]
52
+ }),
53
+ languageData: {
54
+ closeBrackets: { brackets: ["[", "{", '"', "'"] },
55
+ indentOnInput: /^\s*[\}\]]$/
56
+ }
57
+ });
58
+
59
+ // src/index.ts
60
+ function normalizeId(id) {
61
+ try {
62
+ return import_vscode_uri.URI.parse(id).toString(true);
63
+ } catch (e) {
64
+ return id;
65
+ }
66
+ }
67
+ function isNonNull(value) {
68
+ return Boolean(value);
69
+ }
70
+ var urlReg = /^(https?:\/\/|www\.)[\w-\.]+\.[\w-\.]+(\/([\S]+)?)?$/i;
71
+ var JSONLanguageService = class {
72
+ constructor(options) {
73
+ this.options = options;
74
+ this.languageService = (0, import_vscode_json_languageservice.getLanguageService)({});
75
+ this.configure();
76
+ }
77
+ languageService;
78
+ schemasConfigurations = [];
79
+ triggerCharacters = [":", '"', "'"];
80
+ configure() {
81
+ this.languageService.configure({
82
+ allowComments: false,
83
+ schemas: this.schemasConfigurations.map((e) => ({
84
+ fileMatch: e.fileMatch,
85
+ uri: normalizeId(e.uri),
86
+ schema: e.schema
87
+ }))
88
+ });
89
+ }
90
+ parseJSONDocument(textDocument) {
91
+ const text = (0, import_parser_json.parse)(textDocument, { collectComments: true });
92
+ if (!text.ast) {
93
+ return;
94
+ }
95
+ const jsonDocument = this.languageService.newJSONDocument(
96
+ text.ast,
97
+ text.problems
98
+ );
99
+ jsonDocument.comments = text.commentRanges;
100
+ return jsonDocument;
101
+ }
102
+ async validate(source, options) {
103
+ let text = new import_text_mapping.Text(source);
104
+ if (typeof (options == null ? void 0 : options.transform) === "function") {
105
+ text = options.transform(text);
106
+ }
107
+ const textDocument = import_vscode_json_languageservice.TextDocument.create(
108
+ `file:///anonymous-${(0, import_uuid.v4)()}.json`,
109
+ "json",
110
+ 0,
111
+ text.toString()
112
+ );
113
+ const jsonDocument = this.parseJSONDocument(textDocument);
114
+ if (!jsonDocument) {
115
+ return [];
116
+ }
117
+ const diagnostics = await this.languageService.doValidation(
118
+ textDocument,
119
+ jsonDocument,
120
+ {},
121
+ options == null ? void 0 : options.schema
122
+ );
123
+ return diagnostics.map((e) => {
124
+ const from = textDocument.offsetAt(e.range.start);
125
+ const to = textDocument.offsetAt(e.range.end);
126
+ return {
127
+ from,
128
+ to,
129
+ severity: e.severity,
130
+ message: e.message
131
+ };
132
+ }).map((e) => {
133
+ const oRange = text.originalRangeFor({
134
+ from: e.from,
135
+ to: e.to
136
+ });
137
+ if (!oRange) {
138
+ return;
139
+ }
140
+ return {
141
+ ...e,
142
+ ...oRange
143
+ };
144
+ }).filter(isNonNull);
145
+ }
146
+ configureSchemas(config) {
147
+ let configs = [];
148
+ configs = configs.concat(config);
149
+ configs.forEach((c) => {
150
+ const match = this.schemasConfigurations.find((e) => e.uri === c.uri);
151
+ if (match) {
152
+ match.schema = c.schema;
153
+ match.fileMatch = c.fileMatch;
154
+ } else {
155
+ this.schemasConfigurations.push(c);
156
+ }
157
+ });
158
+ this.configure();
159
+ }
160
+ deleteSchemas(uri) {
161
+ let allURI = [];
162
+ allURI = allURI.concat(uri);
163
+ this.schemasConfigurations = this.schemasConfigurations.filter(
164
+ (c) => !allURI.includes(c.uri)
165
+ );
166
+ this.configure();
167
+ }
168
+ async doValidation(context) {
169
+ const { textDocument } = context;
170
+ const jsonDocument = this.parseJSONDocument(textDocument);
171
+ if (!jsonDocument) {
172
+ return [];
173
+ }
174
+ const diagnostics = await this.languageService.doValidation(
175
+ textDocument,
176
+ jsonDocument
177
+ );
178
+ return diagnostics.map((e) => {
179
+ const from = textDocument.offsetAt(e.range.start);
180
+ const to = textDocument.offsetAt(e.range.end);
181
+ return {
182
+ from,
183
+ to,
184
+ severity: "error",
185
+ message: e.message
186
+ };
187
+ });
188
+ }
189
+ async format(state, options) {
190
+ const { textDocument, originalRangeFor } = state.field(import_code_language_shared.textDocumentField);
191
+ const edits = this.languageService.format(
192
+ textDocument,
193
+ // @ts-expect-error range can be undefined
194
+ void 0,
195
+ {
196
+ tabSize: (options == null ? void 0 : options.tabSize) ?? 4,
197
+ insertSpaces: true,
198
+ insertFinalNewline: false
199
+ }
200
+ );
201
+ const changes = edits.map((edit) => {
202
+ const range = originalRangeFor({
203
+ from: textDocument.offsetAt(edit.range.start),
204
+ to: textDocument.offsetAt(edit.range.end)
205
+ });
206
+ if (range) {
207
+ return {
208
+ ...range,
209
+ insert: edit.newText
210
+ };
211
+ }
212
+ }).filter((v) => isChangeDesc(v));
213
+ return {
214
+ changes
215
+ };
216
+ }
217
+ async doComplete(context) {
218
+ const { textDocument } = context;
219
+ const { offset } = context;
220
+ const { line, character } = textDocument.positionAt(offset);
221
+ const jsonDocument = this.parseJSONDocument(textDocument);
222
+ if (!jsonDocument) {
223
+ return;
224
+ }
225
+ const completionResult = await this.languageService.doComplete(
226
+ textDocument,
227
+ {
228
+ line,
229
+ character
230
+ },
231
+ jsonDocument
232
+ );
233
+ if (!completionResult || !completionResult.items.length) {
234
+ return;
235
+ }
236
+ return {
237
+ isIncomplete: true,
238
+ items: completionResult.items
239
+ };
240
+ }
241
+ async findLinks(context) {
242
+ const { textDocument } = context;
243
+ const doc = this.parseJSONDocument(textDocument);
244
+ if (!doc) {
245
+ return [];
246
+ }
247
+ const links = [];
248
+ doc.visit((node) => {
249
+ if (node.type === "string" && urlReg.test(node.value)) {
250
+ const range = {
251
+ from: node.offset + 1,
252
+ to: node.offset + node.length - 1
253
+ };
254
+ links.push({
255
+ target: node.value,
256
+ range
257
+ });
258
+ }
259
+ return true;
260
+ });
261
+ return links;
262
+ }
263
+ };
264
+ function isChangeDesc(v) {
265
+ return Boolean(v);
266
+ }
267
+ var jsonLanguageService = new JSONLanguageService({
268
+ lintDelay: 0
269
+ });
270
+ var json = {
271
+ language: jsonLanguage,
272
+ languageService: jsonLanguageService
273
+ };
274
+ // Annotate the CommonJS export names for ESM import in node:
275
+ 0 && (module.exports = {
276
+ DiagnosticSeverity,
277
+ JSONLanguageService,
278
+ Text,
279
+ json,
280
+ jsonLanguage,
281
+ jsonLanguageService
282
+ });
283
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/json.ts"],"sourcesContent":["// Copyright (c) 2025 coze-dev\n// SPDX-License-Identifier: MIT\n\nimport { URI } from 'vscode-uri';\nimport {\n getLanguageService,\n TextDocument,\n type LanguageService,\n type JSONSchema,\n type CompletionList,\n type JSONDocument,\n DiagnosticSeverity,\n} from 'vscode-json-languageservice';\nimport { Text } from 'text-mapping';\nimport { v4 as uuid } from '@lukeed/uuid';\nimport { parse } from '@coze-editor/parser-json';\nimport {\n type LanguageService as ILanguageService,\n type LanguageServiceOptions,\n type Link,\n textDocumentField,\n} from '@coze-editor/code-language-shared';\nimport {\n type ChangeSpec,\n type EditorState,\n type TransactionSpec,\n} from '@codemirror/state';\n\nimport { jsonLanguage } from './json';\n\ninterface SchemasConfiguration {\n uri: string;\n fileMatch: string[];\n schema: JSONSchema;\n}\n\ninterface ValidateOptions {\n schema?: JSONSchema;\n transform?: (text: Text) => Text;\n}\n\nfunction normalizeId(id: string) {\n // remove trailing '#', normalize drive capitalization\n try {\n return URI.parse(id).toString(true);\n } catch (e) {\n return id;\n }\n}\n\nfunction isNonNull<T>(value: T | undefined): value is T {\n return Boolean(value);\n}\n\nconst urlReg = /^(https?:\\/\\/|www\\.)[\\w-\\.]+\\.[\\w-\\.]+(\\/([\\S]+)?)?$/i;\n\nclass JSONLanguageService implements ILanguageService {\n protected languageService: LanguageService;\n private schemasConfigurations: SchemasConfiguration[] = [];\n public triggerCharacters = [':', '\"', \"'\"];\n\n constructor(public options: LanguageServiceOptions) {\n this.languageService = getLanguageService({});\n this.configure();\n }\n\n private configure() {\n this.languageService.configure({\n allowComments: false,\n schemas: this.schemasConfigurations.map(e => ({\n fileMatch: e.fileMatch,\n uri: normalizeId(e.uri),\n schema: e.schema,\n })),\n });\n }\n\n private parseJSONDocument(\n textDocument: TextDocument,\n ): JSONDocument | undefined {\n const text = parse(textDocument, { collectComments: true });\n if (!text.ast) {\n return;\n }\n\n const jsonDocument = this.languageService.newJSONDocument(\n text.ast,\n text.problems,\n );\n // @ts-expect-error comments type is not exported\n jsonDocument.comments = text.commentRanges;\n return jsonDocument;\n }\n\n public async validate(source: string, options?: ValidateOptions) {\n let text = new Text(source);\n\n if (typeof options?.transform === 'function') {\n text = options.transform(text);\n }\n\n const textDocument = TextDocument.create(\n `file:///anonymous-${uuid()}.json`,\n 'json',\n 0,\n text.toString(),\n );\n const jsonDocument = this.parseJSONDocument(textDocument);\n\n if (!jsonDocument) {\n return [];\n }\n\n const diagnostics = await this.languageService.doValidation(\n textDocument,\n jsonDocument,\n {},\n options?.schema,\n );\n\n return diagnostics\n .map(e => {\n const from = textDocument.offsetAt(e.range.start);\n const to = textDocument.offsetAt(e.range.end);\n\n return {\n from,\n to,\n severity: e.severity,\n message: e.message,\n };\n })\n .map(e => {\n const oRange = text.originalRangeFor({\n from: e.from,\n to: e.to,\n });\n if (!oRange) {\n return;\n }\n return {\n ...e,\n ...oRange,\n };\n })\n .filter(isNonNull);\n }\n\n public configureSchemas(\n config: SchemasConfiguration | SchemasConfiguration[],\n ) {\n let configs: SchemasConfiguration[] = [];\n configs = configs.concat(config);\n\n configs.forEach(c => {\n const match = this.schemasConfigurations.find(e => e.uri === c.uri);\n if (match) {\n match.schema = c.schema;\n match.fileMatch = c.fileMatch;\n } else {\n this.schemasConfigurations.push(c);\n }\n });\n\n this.configure();\n }\n\n public deleteSchemas(uri: string | string[]) {\n let allURI: string[] = [];\n allURI = allURI.concat(uri);\n\n this.schemasConfigurations = this.schemasConfigurations.filter(\n c => !allURI.includes(c.uri),\n );\n\n this.configure();\n }\n\n public async doValidation(\n context: Parameters<NonNullable<ILanguageService['doValidation']>>[0],\n ) {\n const { textDocument } = context;\n const jsonDocument = this.parseJSONDocument(textDocument);\n\n if (!jsonDocument) {\n return [];\n }\n\n const diagnostics = await this.languageService.doValidation(\n textDocument,\n jsonDocument,\n );\n\n return diagnostics.map(e => {\n const from = textDocument.offsetAt(e.range.start);\n const to = textDocument.offsetAt(e.range.end);\n\n return {\n from,\n to,\n severity: 'error' as const,\n message: e.message,\n };\n });\n }\n\n async format(\n state: EditorState,\n options?: { tabSize: number },\n ): Promise<TransactionSpec> {\n const { textDocument, originalRangeFor } = state.field(textDocumentField);\n\n const edits = this.languageService.format(\n textDocument,\n // @ts-expect-error range can be undefined\n undefined,\n {\n tabSize: options?.tabSize ?? 4,\n insertSpaces: true,\n insertFinalNewline: false,\n },\n );\n\n const changes = edits\n .map(edit => {\n const range = originalRangeFor({\n from: textDocument.offsetAt(edit.range.start),\n to: textDocument.offsetAt(edit.range.end),\n });\n if (range) {\n return {\n ...range,\n insert: edit.newText,\n };\n }\n })\n .filter(v => isChangeDesc(v));\n\n return {\n changes,\n };\n }\n\n public async doComplete(\n context: Parameters<NonNullable<ILanguageService['doComplete']>>[0],\n ): Promise<CompletionList | null | undefined> {\n const { textDocument } = context;\n const { offset } = context;\n\n const { line, character } = textDocument.positionAt(offset);\n\n const jsonDocument = this.parseJSONDocument(textDocument);\n\n if (!jsonDocument) {\n return;\n }\n\n const completionResult = await this.languageService.doComplete(\n textDocument,\n {\n line,\n character,\n },\n jsonDocument,\n );\n\n if (!completionResult || !completionResult.items.length) {\n return;\n }\n\n return {\n isIncomplete: true,\n items: completionResult.items,\n };\n }\n\n async findLinks(\n context: Parameters<NonNullable<ILanguageService['findLinks']>>[0],\n ) {\n const { textDocument } = context;\n const doc = this.parseJSONDocument(textDocument);\n\n if (!doc) {\n return [];\n }\n\n const links: Link[] = [];\n\n // @ts-expect-error doc.visit is not exposed but indeed exists\n doc.visit(node => {\n if (node.type === 'string' && urlReg.test(node.value)) {\n const range = {\n from: node.offset + 1,\n to: node.offset + node.length - 1,\n };\n\n links.push({\n target: node.value,\n range,\n });\n }\n return true;\n });\n\n return links;\n }\n}\n\nfunction isChangeDesc(v: unknown): v is ChangeSpec {\n return Boolean(v);\n}\n\nconst jsonLanguageService = new JSONLanguageService({\n lintDelay: 0,\n});\n\nconst json = {\n language: jsonLanguage,\n languageService: jsonLanguageService,\n};\n\nexport { json, jsonLanguage, jsonLanguageService, JSONLanguageService };\n\nexport { DiagnosticSeverity, Text };\n","// Copyright (c) 2025 coze-dev\n// SPDX-License-Identifier: MIT\n\nimport { parser } from '@coze-editor/lezer-parser-json';\nimport {\n continuedIndent,\n indentNodeProp,\n foldNodeProp,\n foldInside,\n LRLanguage,\n} from '@codemirror/language';\n\n/// A language provider that provides JSON parsing.\nexport const jsonLanguage = LRLanguage.define({\n name: 'json',\n parser: parser.configure({\n props: [\n indentNodeProp.add({\n Object: continuedIndent({ except: /^\\s*\\}/ }),\n Array: continuedIndent({ except: /^\\s*\\]/ }),\n }),\n foldNodeProp.add({\n 'Object Array': foldInside,\n }),\n ],\n }),\n languageData: {\n closeBrackets: { brackets: ['[', '{', '\"', \"'\"] },\n\n indentOnInput: /^\\s*[\\}\\]]$/,\n },\n});\n"],"mappings":"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","names":["uuid"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@coze-editor/code-language-json",
3
+ "version": "0.1.0-alpha.09ffeb",
4
+ "description": "code-language-json",
5
+ "license": "MIT",
6
+ "author": "fengzilong",
7
+ "maintainers": [],
8
+ "sideEffects": [
9
+ "**/*.css",
10
+ "**/*.less",
11
+ "**/*.sass",
12
+ "**/*.scss"
13
+ ],
14
+ "main": "./dist/esm/index.js",
15
+ "module": "./dist/esm/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "lint": "eslint && tsc --noEmit"
23
+ },
24
+ "dependencies": {
25
+ "@codemirror/autocomplete": "^6.18.0",
26
+ "@coze-editor/extension-lint": "0.1.0-alpha.09ffeb",
27
+ "@coze-editor/lezer-parser-json": "0.1.0-alpha.09ffeb",
28
+ "@coze-editor/parser-json": "0.1.0-alpha.09ffeb",
29
+ "@lezer/json": "^1.0.2",
30
+ "@lukeed/uuid": "^2.0.1",
31
+ "text-mapping": "^1.0.1",
32
+ "vscode-json-languageservice": "^5.4.2",
33
+ "vscode-uri": "^3.0.8"
34
+ },
35
+ "devDependencies": {
36
+ "@codemirror/language": "^6.10.1",
37
+ "@codemirror/state": "^6.4.1",
38
+ "@codemirror/view": "^6.26.1",
39
+ "@coze-arch/ts-config": "workspace:*",
40
+ "@coze-editor/code-language-shared": "workspace:*",
41
+ "@coze-editor/eslint-config": "workspace:*",
42
+ "@types/node": "^22",
43
+ "eslint": "9.14.0",
44
+ "tsup": "^8.0.1",
45
+ "typescript": "^5.8.2"
46
+ },
47
+ "peerDependencies": {
48
+ "@codemirror/language": "^6.0.0",
49
+ "@codemirror/state": "^6.4.1",
50
+ "@codemirror/view": "^6.26.1",
51
+ "@coze-editor/code-language-shared": "0.1.0-alpha.09ffeb"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public",
55
+ "registry": "https://registry.npmjs.org"
56
+ },
57
+ "test:main": "./src/index.ts"
58
+ }