@coze-editor/code-language-json 0.1.0-alpha.37c297 → 0.1.0-alpha.687604

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -6,7 +6,6 @@ import {
6
6
  DiagnosticSeverity
7
7
  } from "vscode-json-languageservice";
8
8
  import { Text } from "text-mapping";
9
- import Fuse from "fuse.js";
10
9
  import { v4 as uuid } from "@lukeed/uuid";
11
10
  import { parse } from "@coze-editor/parser-json";
12
11
  import {
@@ -61,6 +60,7 @@ var JSONLanguageService = class {
61
60
  }
62
61
  languageService;
63
62
  schemasConfigurations = [];
63
+ triggerCharacters = [":", '"', "'"];
64
64
  configure() {
65
65
  this.languageService.configure({
66
66
  allowComments: false,
@@ -200,16 +200,7 @@ var JSONLanguageService = class {
200
200
  }
201
201
  async doComplete(context) {
202
202
  const { textDocument } = context;
203
- const text = textDocument.getText();
204
203
  const { offset } = context;
205
- const letterBefore = text.slice(
206
- Math.max(0, offset - 1),
207
- Math.min(text.length, offset)
208
- );
209
- const triggerCharacters = [":", '"', "'"];
210
- if (!triggerCharacters.includes(letterBefore) && !/^\w+$/.test(letterBefore)) {
211
- return;
212
- }
213
204
  const { line, character } = textDocument.positionAt(offset);
214
205
  const jsonDocument = this.parseJSONDocument(textDocument);
215
206
  if (!jsonDocument) {
@@ -226,30 +217,10 @@ var JSONLanguageService = class {
226
217
  if (!completionResult || !completionResult.items.length) {
227
218
  return;
228
219
  }
229
- const fuse = new Fuse(completionResult.items, {
230
- threshold: 0,
231
- // allow matches appear in any place in target string
232
- ignoreLocation: true,
233
- keys: ["label"]
234
- });
235
- let i = context.offset - 1;
236
- let query = "";
237
- const content = context.textDocument.getText();
238
- while (i >= 0) {
239
- const char = content.slice(i, i + 1);
240
- if (char === "\n") {
241
- break;
242
- }
243
- if (triggerCharacters.includes(char) && i + 1 <= context.offset) {
244
- query = content.slice(i + 1, context.offset);
245
- break;
246
- }
247
- i--;
248
- }
249
- return query ? {
220
+ return {
250
221
  isIncomplete: true,
251
- items: fuse.search(query).map((v) => v.item)
252
- } : completionResult;
222
+ items: completionResult.items
223
+ };
253
224
  }
254
225
  async findLinks(context) {
255
226
  const { textDocument } = context;
@@ -1 +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 Fuse from 'fuse.js';\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\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 text = textDocument.getText();\n const { offset } = context;\n\n const letterBefore = text.slice(\n Math.max(0, offset - 1),\n Math.min(text.length, offset),\n );\n\n const triggerCharacters = [':', '\"', \"'\"];\n if (\n !triggerCharacters.includes(letterBefore) &&\n !/^\\w+$/.test(letterBefore)\n ) {\n return;\n }\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 const fuse = new Fuse(completionResult.items, {\n threshold: 0,\n // allow matches appear in any place in target string\n ignoreLocation: true,\n keys: ['label'],\n });\n\n let i = context.offset - 1;\n let query = '';\n\n const content = context.textDocument.getText();\n\n while (i >= 0) {\n const char = content.slice(i, i + 1);\n\n if (char === '\\n') {\n break;\n }\n\n if (triggerCharacters.includes(char) && i + 1 <= context.offset) {\n query = content.slice(i + 1, context.offset);\n break;\n }\n i--;\n }\n\n // cannot use validFor here as range changes during filtering\n return query\n ? {\n isIncomplete: true,\n items: fuse.search(query).map(v => v.item),\n }\n : completionResult;\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":[]}
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":[]}
package/dist/index.d.mts CHANGED
@@ -22,6 +22,7 @@ declare class JSONLanguageService implements LanguageService {
22
22
  options: LanguageServiceOptions;
23
23
  protected languageService: LanguageService$1;
24
24
  private schemasConfigurations;
25
+ triggerCharacters: string[];
25
26
  constructor(options: LanguageServiceOptions);
26
27
  private configure;
27
28
  private parseJSONDocument;
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ declare class JSONLanguageService implements LanguageService {
22
22
  options: LanguageServiceOptions;
23
23
  protected languageService: LanguageService$1;
24
24
  private schemasConfigurations;
25
+ triggerCharacters: string[];
25
26
  constructor(options: LanguageServiceOptions);
26
27
  private configure;
27
28
  private parseJSONDocument;
package/dist/index.js CHANGED
@@ -1,8 +1,6 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
5
  var __export = (target, all) => {
8
6
  for (var name in all)
@@ -16,14 +14,6 @@ var __copyProps = (to, from, except, desc) => {
16
14
  }
17
15
  return to;
18
16
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
18
 
29
19
  // src/index.ts
@@ -40,7 +30,6 @@ module.exports = __toCommonJS(index_exports);
40
30
  var import_vscode_uri = require("vscode-uri");
41
31
  var import_vscode_json_languageservice = require("vscode-json-languageservice");
42
32
  var import_text_mapping = require("text-mapping");
43
- var import_fuse = __toESM(require("fuse.js"));
44
33
  var import_uuid = require("@lukeed/uuid");
45
34
  var import_parser_json = require("@coze-editor/parser-json");
46
35
  var import_code_language_shared = require("@coze-editor/code-language-shared");
@@ -87,6 +76,7 @@ var JSONLanguageService = class {
87
76
  }
88
77
  languageService;
89
78
  schemasConfigurations = [];
79
+ triggerCharacters = [":", '"', "'"];
90
80
  configure() {
91
81
  this.languageService.configure({
92
82
  allowComments: false,
@@ -226,16 +216,7 @@ var JSONLanguageService = class {
226
216
  }
227
217
  async doComplete(context) {
228
218
  const { textDocument } = context;
229
- const text = textDocument.getText();
230
219
  const { offset } = context;
231
- const letterBefore = text.slice(
232
- Math.max(0, offset - 1),
233
- Math.min(text.length, offset)
234
- );
235
- const triggerCharacters = [":", '"', "'"];
236
- if (!triggerCharacters.includes(letterBefore) && !/^\w+$/.test(letterBefore)) {
237
- return;
238
- }
239
220
  const { line, character } = textDocument.positionAt(offset);
240
221
  const jsonDocument = this.parseJSONDocument(textDocument);
241
222
  if (!jsonDocument) {
@@ -252,30 +233,10 @@ var JSONLanguageService = class {
252
233
  if (!completionResult || !completionResult.items.length) {
253
234
  return;
254
235
  }
255
- const fuse = new import_fuse.default(completionResult.items, {
256
- threshold: 0,
257
- // allow matches appear in any place in target string
258
- ignoreLocation: true,
259
- keys: ["label"]
260
- });
261
- let i = context.offset - 1;
262
- let query = "";
263
- const content = context.textDocument.getText();
264
- while (i >= 0) {
265
- const char = content.slice(i, i + 1);
266
- if (char === "\n") {
267
- break;
268
- }
269
- if (triggerCharacters.includes(char) && i + 1 <= context.offset) {
270
- query = content.slice(i + 1, context.offset);
271
- break;
272
- }
273
- i--;
274
- }
275
- return query ? {
236
+ return {
276
237
  isIncomplete: true,
277
- items: fuse.search(query).map((v) => v.item)
278
- } : completionResult;
238
+ items: completionResult.items
239
+ };
279
240
  }
280
241
  async findLinks(context) {
281
242
  const { textDocument } = context;
package/dist/index.js.map CHANGED
@@ -1 +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 Fuse from 'fuse.js';\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\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 text = textDocument.getText();\n const { offset } = context;\n\n const letterBefore = text.slice(\n Math.max(0, offset - 1),\n Math.min(text.length, offset),\n );\n\n const triggerCharacters = [':', '\"', \"'\"];\n if (\n !triggerCharacters.includes(letterBefore) &&\n !/^\\w+$/.test(letterBefore)\n ) {\n return;\n }\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 const fuse = new Fuse(completionResult.items, {\n threshold: 0,\n // allow matches appear in any place in target string\n ignoreLocation: true,\n keys: ['label'],\n });\n\n let i = context.offset - 1;\n let query = '';\n\n const content = context.textDocument.getText();\n\n while (i >= 0) {\n const char = content.slice(i, i + 1);\n\n if (char === '\\n') {\n break;\n }\n\n if (triggerCharacters.includes(char) && i + 1 <= context.offset) {\n query = content.slice(i + 1, context.offset);\n break;\n }\n i--;\n }\n\n // cannot use validFor here as range changes during filtering\n return query\n ? {\n isIncomplete: true,\n items: fuse.search(query).map(v => v.item),\n }\n : completionResult;\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","Fuse"]}
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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coze-editor/code-language-json",
3
- "version": "0.1.0-alpha.37c297",
3
+ "version": "0.1.0-alpha.687604",
4
4
  "description": "code-language-json",
5
5
  "license": "MIT",
6
6
  "author": "fengzilong",
@@ -23,12 +23,11 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@codemirror/autocomplete": "^6.18.0",
26
- "@coze-editor/extension-lint": "0.1.0-alpha.37c297",
27
- "@coze-editor/lezer-parser-json": "0.1.0-alpha.37c297",
28
- "@coze-editor/parser-json": "0.1.0-alpha.37c297",
26
+ "@coze-editor/extension-lint": "0.1.0-alpha.687604",
27
+ "@coze-editor/lezer-parser-json": "0.1.0-alpha.687604",
28
+ "@coze-editor/parser-json": "0.1.0-alpha.687604",
29
29
  "@lezer/json": "^1.0.2",
30
30
  "@lukeed/uuid": "^2.0.1",
31
- "fuse.js": "^7.0.0",
32
31
  "text-mapping": "^1.0.1",
33
32
  "vscode-json-languageservice": "^5.4.2",
34
33
  "vscode-uri": "^3.0.8"
@@ -49,7 +48,7 @@
49
48
  "@codemirror/language": "^6.0.0",
50
49
  "@codemirror/state": "^6.4.1",
51
50
  "@codemirror/view": "^6.26.1",
52
- "@coze-editor/code-language-shared": "0.1.0-alpha.37c297"
51
+ "@coze-editor/code-language-shared": "0.1.0-alpha.687604"
53
52
  },
54
53
  "publishConfig": {
55
54
  "access": "public",