@coldsmirk/inkstone-mongodb 0.26.0 → 0.27.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @coldsmirk/inkstone-mongodb
2
2
 
3
- MongoDB command editing intelligence for Monaco: a command document in the shell's own spelling (`{ find: "orders", filter: { status: "open" }, limit: 20 }` — keys bare or quoted, `ObjectId("…")`, `ISODate("…")`, `/regex/i`), the database commands and their fields, the query, update and aggregation operators by where the caret stands, collection and database completion, the document read as the engine reads it, markers, and a drop-in React `<MongodbEditor>`.
3
+ MongoDB command editing intelligence for Monaco and CodeMirror: a command document in the shell's own spelling (`{ find: "orders", filter: { status: "open" }, limit: 20 }` — keys bare or quoted, `ObjectId("…")`, `ISODate("…")`, `/regex/i`), the database commands and their fields, the query, update and aggregation operators by where the caret stands, collection and database completion, the document read as the engine reads it, markers, and a drop-in React `<MongodbEditor>`.
4
4
 
5
5
  Part of [inkstone](https://github.com/coldsmirk/inkstone). Built for the [**polyglot**](https://github.com/coldsmirk/polyglot) sidecar's MongoDB engine, which takes one command document — the command as its first key, `$db` naming the database — and parses it with the driver's own `BsonDocument.parse`.
6
6
 
@@ -8,6 +8,7 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). Built for the [**poly
8
8
 
9
9
  - **`@coldsmirk/inkstone-mongodb`** — the framework-free core: the document reader, the command table, the operator vocabularies, the assist, the markers. Zero editor dependencies.
10
10
  - **`@coldsmirk/inkstone-mongodb/monaco`** — `defineMongodbLanguage(monaco)` (the `mongodb` id with its Monarch grammar, once per monaco module), `registerMongodbLanguage(monaco, modelPath, hooks)` (completion and hover for one model), `setMongodbMarkers`. Peer: `monaco-editor`.
11
+ - **`@coldsmirk/inkstone-mongodb/codemirror`** — the same assist bound to CodeMirror 6: `mongodbCompletion(assist)` and `mongodbFilterCompletion(assist)` (completion sources), `mongodbHover(assist, wording)`, `mongodbDiagnostics(markers, wording)`. No grammar of its own — a filter document is JSON, so pair it with `@codemirror/lang-json`; it does not close brackets or quotes either, so add `closeBrackets()` where a key's own quotes matter. Peers: `@codemirror/autocomplete`, `@codemirror/view`.
11
12
  - **`@coldsmirk/inkstone-mongodb/react`** — `<MongodbEditor>`: a controlled command editor built on `@coldsmirk/inkstone-react`'s `<MonacoEditor>`, with a run key (Ctrl/Cmd-Enter handing over the live caret), caret tracking, an insert handle for collection trees, and the markers refreshed on every change. Peers: `monaco-editor`, `react`.
12
13
 
13
14
  ## The shape
@@ -1,4 +1,4 @@
1
- import { _ as MongodbFilterAssist, m as MongodbAssist, t as MongodbMarker } from "./markers-DjjkoOJP.js";
1
+ import { _ as MongodbFilterAssist, m as MongodbAssist, t as MongodbMarker } from "./markers-Co8ntyUI.js";
2
2
  import { CompletionSource } from "@codemirror/autocomplete";
3
3
  import { Diagnostic } from "@codemirror/lint";
4
4
  import { Extension } from "@codemirror/state";
@@ -1,4 +1,3 @@
1
- import { snippet } from "@codemirror/autocomplete";
2
1
  import { hoverTooltip } from "@codemirror/view";
3
2
  //#region src/codemirror.ts
4
3
  const TYPES = {
@@ -16,7 +15,7 @@ function completion(candidate, at) {
16
15
  detail: candidate.detail,
17
16
  info: candidate.documentation,
18
17
  boost: -candidate.sortGroup * 10 - at / 1e3,
19
- apply: candidate.snippet === true ? snippet(candidate.insertText) : candidate.insertText
18
+ apply: candidate.insertText
20
19
  };
21
20
  }
22
21
  function resultOf(candidates, pos) {
@@ -52,7 +51,7 @@ function mongodbDiagnostics(markers, wording) {
52
51
  return {
53
52
  from: marker.from,
54
53
  to: marker.to,
55
- severity: marker.severity === "error" ? "error" : "info",
54
+ severity: marker.severity,
56
55
  message: wording(marker)
57
56
  };
58
57
  });
@@ -299,13 +299,14 @@ function atKey(frame) {
299
299
  function valueKey(frame) {
300
300
  return frame !== void 0 && !frame.transparent && !frame.valueStarted ? frame.key : null;
301
301
  }
302
- function keyContext(frames, top, typed, quoted) {
302
+ function keyContext(frames, top, typed, quoted, reach = typed.length) {
303
303
  return {
304
304
  kind: "key",
305
305
  path: pathOf(frames),
306
306
  siblings: top.seen,
307
307
  typed,
308
- quoted
308
+ quoted,
309
+ reach
309
310
  };
310
311
  }
311
312
  function valueContext(frames, key, typed, quoted) {
@@ -400,7 +401,10 @@ function caretContext(text, offset) {
400
401
  i++;
401
402
  }
402
403
  const top = frames.at(-1);
403
- if (top !== void 0 && atKey(top)) return keyContext(frames, top, "", false);
404
+ if (top !== void 0 && atKey(top)) {
405
+ const closed = /"(?<double>(?:[^"\\]|\\.)*)"$|'(?<single>(?:[^'\\]|\\.)*)'$/u.exec(body);
406
+ return keyContext(frames, top, closed?.groups?.double ?? closed?.groups?.single ?? "", false, closed?.[0].length ?? 0);
407
+ }
404
408
  const key = valueKey(top);
405
409
  return key === null ? { kind: "none" } : valueContext(frames, key, "", false);
406
410
  }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as keysAt, C as MONGO_COMMANDS, D as QUERY_OPERATORS, E as QUERY_HOLDERS, O as STAGES, S as FIELD_OPERATORS, T as PUSH_MODIFIERS, _ as MongodbFilterAssist, a as CaretContext, b as createMongodbFilterAssist, c as LITERALS, d as readDocument, f as runnableDocument, g as MongodbCompletionCandidate, h as MongodbCatalog, i as CONSTRUCTORS, k as UPDATE_OPERATORS, l as RunnableDocument, m as MongodbAssist, n as MongodbMarkerCode, o as DocumentRead, p as CatalogCollection, r as documentMarkers, s as DocumentRefusal, t as MongodbMarker, u as caretContext, v as MongodbHoverCard, w as MongoCommand, x as EXPRESSION_OPERATORS, y as createMongodbAssist } from "./markers-DjjkoOJP.js";
1
+ import { A as keysAt, C as MONGO_COMMANDS, D as QUERY_OPERATORS, E as QUERY_HOLDERS, O as STAGES, S as FIELD_OPERATORS, T as PUSH_MODIFIERS, _ as MongodbFilterAssist, a as CaretContext, b as createMongodbFilterAssist, c as LITERALS, d as readDocument, f as runnableDocument, g as MongodbCompletionCandidate, h as MongodbCatalog, i as CONSTRUCTORS, k as UPDATE_OPERATORS, l as RunnableDocument, m as MongodbAssist, n as MongodbMarkerCode, o as DocumentRead, p as CatalogCollection, r as documentMarkers, s as DocumentRefusal, t as MongodbMarker, u as caretContext, v as MongodbHoverCard, w as MongoCommand, x as EXPRESSION_OPERATORS, y as createMongodbAssist } from "./markers-Co8ntyUI.js";
2
2
  export { CONSTRUCTORS, type CaretContext, type CatalogCollection, type DocumentRead, type DocumentRefusal, EXPRESSION_OPERATORS, FIELD_OPERATORS, LITERALS, MONGO_COMMANDS, type MongoCommand, type MongodbAssist, type MongodbCatalog, type MongodbCompletionCandidate, type MongodbFilterAssist, type MongodbHoverCard, type MongodbMarker, type MongodbMarkerCode, PUSH_MODIFIERS, QUERY_HOLDERS, QUERY_OPERATORS, type RunnableDocument, STAGES, UPDATE_OPERATORS, caretContext, createMongodbAssist, createMongodbFilterAssist, documentMarkers, keysAt, readDocument, runnableDocument };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as PUSH_MODIFIERS, c as STAGES, i as MONGO_COMMANDS, l as UPDATE_OPERATORS, n as EXPRESSION_OPERATORS, o as QUERY_HOLDERS, r as FIELD_OPERATORS, s as QUERY_OPERATORS, t as documentMarkers, u as keysAt } from "./markers-CbwviTiD.js";
2
- import { a as runnableDocument, i as readDocument, n as LITERALS, r as caretContext, t as CONSTRUCTORS } from "./document-CVB9YunA.js";
1
+ import { a as PUSH_MODIFIERS, c as STAGES, i as MONGO_COMMANDS, l as UPDATE_OPERATORS, n as EXPRESSION_OPERATORS, o as QUERY_HOLDERS, r as FIELD_OPERATORS, s as QUERY_OPERATORS, t as documentMarkers, u as keysAt } from "./markers-30Z4EFiH.js";
2
+ import { a as runnableDocument, i as readDocument, n as LITERALS, r as caretContext, t as CONSTRUCTORS } from "./document-CvsIw1Q8.js";
3
3
  //#region src/assist.ts
4
4
  const NO_CATALOG = { collections: () => [] };
5
5
  function createMongodbFilterAssist(fields = () => []) {
@@ -13,9 +13,8 @@ function createMongodbFilterAssist(fields = () => []) {
13
13
  return {
14
14
  label: key,
15
15
  kind: key.startsWith("$") ? "operator" : "field",
16
- insertText: context.quoted ? key : `"${key}": $0`,
17
- ...!context.quoted && { snippet: true },
18
- replace: context.typed.length,
16
+ insertText: context.quoted ? key : `"${key}": `,
17
+ replace: context.reach,
19
18
  sortGroup: key.startsWith("$") ? 1 : 0
20
19
  };
21
20
  });
@@ -50,9 +49,8 @@ function createMongodbAssist(catalog = NO_CATALOG, commands = MONGO_COMMANDS) {
50
49
  return {
51
50
  label: key,
52
51
  kind,
53
- insertText: context.quoted ? key : `"${key}": $0`,
54
- ...!context.quoted && { snippet: true },
55
- replace: context.typed.length,
52
+ insertText: context.quoted ? key : `"${key}": `,
53
+ replace: context.reach,
56
54
  ...named !== void 0 && !commanding && { detail: named },
57
55
  ...command !== void 0 && { documentation: documentationOf(command) },
58
56
  sortGroup: kind === "command" || kind === "field" ? 0 : 1
@@ -1,4 +1,4 @@
1
- import { i as readDocument } from "./document-CVB9YunA.js";
1
+ import { i as readDocument } from "./document-CvsIw1Q8.js";
2
2
  //#region src/commands.ts
3
3
  const COMMON = ["comment", "maxTimeMS"];
4
4
  const MONGO_COMMANDS = [
@@ -982,12 +982,12 @@ function keysAt(path, siblings, commands = MONGO_COMMANDS) {
982
982
  if (command === void 0) return [...commands.map((candidate) => candidate.name), "$db"];
983
983
  return [...command.fields, "$db"].filter((key) => !siblings.includes(key));
984
984
  }
985
+ const parent = path.at(-2);
986
+ if (!last.startsWith("$") && parent !== void 0 && QUERY_HOLDERS.has(parent)) return FIELD_OPERATORS;
985
987
  if (QUERY_HOLDERS.has(last)) return QUERY_OPERATORS;
986
988
  if (UPDATE_HOLDERS.has(last)) return UPDATE_OPERATORS;
987
989
  if (PIPELINE_HOLDERS.has(last)) return STAGES;
988
990
  if (last.startsWith("$")) return STAGE_KEYS[last] ?? FIELD_KEYS[last] ?? [];
989
- const parent = path.at(-2);
990
- if (parent !== void 0 && QUERY_HOLDERS.has(parent)) return FIELD_OPERATORS;
991
991
  if (parent === "$push" || parent === "$addToSet") return PUSH_MODIFIERS;
992
992
  if (parent === "$group") return EXPRESSION_OPERATORS;
993
993
  return FIELD_KEYS[last] ?? [];
@@ -28,9 +28,6 @@ declare const UPDATE_OPERATORS: string[];
28
28
  declare const PUSH_MODIFIERS: string[];
29
29
  declare const STAGES: string[];
30
30
  declare const EXPRESSION_OPERATORS: string[];
31
- /**
32
- * The keys whose value is a query: a filter, and every logical operator's branches.
33
- */
34
31
  /**
35
32
  * The keys whose value is a query document: what is under one is a field name or a logical
36
33
  * operator, and what is under a *field* of one is a comparison operator. Exported because a
@@ -67,11 +64,11 @@ interface MongodbCatalog {
67
64
  interface MongodbCompletionCandidate {
68
65
  label: string;
69
66
  kind: "command" | "field" | "operator" | "stage" | "collection" | "database";
70
- insertText: string;
71
67
  /**
72
- * `insertText` is a snippet (`$0` marks the caret) rather than plain text.
68
+ * What the editor writes in place of what `replace` reaches back over. Plain text: the
69
+ * caret lands at its end, which is where a key's value goes.
73
70
  */
74
- snippet?: boolean;
71
+ insertText: string;
75
72
  /**
76
73
  * How many characters before the caret the insert replaces — the key or the name typed so
77
74
  * far, bare or inside its quote.
@@ -207,6 +204,16 @@ type CaretContext = {
207
204
  * Whether the caret is inside an opened quote.
208
205
  */
209
206
  quoted: boolean;
207
+ /**
208
+ * How many characters before the caret a completion replaces: what the reader has
209
+ * already put where the key goes, quotes included where they typed them.
210
+ *
211
+ * Stated rather than derived from `typed`, because the two part company exactly where
212
+ * it matters. A key the reader has closed — `{ "status"`, the caret after the quote, no
213
+ * colon yet — has six characters typed and eight to reach back over, and reaching over
214
+ * none wrote the completion *after* the key: `{ "status""status": `.
215
+ */
216
+ reach: number;
210
217
  } | {
211
218
  kind: "value";
212
219
  path: string[];
package/dist/monaco.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { m as MongodbAssist, t as MongodbMarker } from "./markers-DjjkoOJP.js";
1
+ import { m as MongodbAssist, t as MongodbMarker } from "./markers-Co8ntyUI.js";
2
2
  import * as monacoEditor from "monaco-editor";
3
3
  import { IDisposable, editor } from "monaco-editor";
4
4
  //#region src/monaco.d.ts
package/dist/monaco.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as LITERALS, t as CONSTRUCTORS } from "./document-CVB9YunA.js";
1
+ import { n as LITERALS, t as CONSTRUCTORS } from "./document-CvsIw1Q8.js";
2
2
  //#region src/monaco.ts
3
3
  const MONGODB_LANGUAGE_ID = "mongodb";
4
4
  const LANGUAGES_KEY = Symbol.for("coldsmirk.inkstone.mongodb.languages");
@@ -127,7 +127,6 @@ function registerMongodbLanguage(monaco, modelPath, hooks, languageId = MONGODB_
127
127
  label: candidate.label,
128
128
  kind: kinds[candidate.kind],
129
129
  insertText: candidate.insertText,
130
- insertTextRules: candidate.snippet ? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet : void 0,
131
130
  detail: candidate.detail,
132
131
  documentation: candidate.documentation,
133
132
  range: new monaco.Range(position.lineNumber, Math.max(1, position.column - candidate.replace), position.lineNumber, position.column),
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { m as MongodbAssist, t as MongodbMarker } from "./markers-DjjkoOJP.js";
1
+ import { m as MongodbAssist, t as MongodbMarker } from "./markers-Co8ntyUI.js";
2
2
  import { MonacoModule } from "./monaco.js";
3
3
  import { ReactNode } from "react";
4
4
  import { editor } from "monaco-editor";
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as documentMarkers } from "./markers-CbwviTiD.js";
1
+ import { t as documentMarkers } from "./markers-30Z4EFiH.js";
2
2
  import { MONGODB_LANGUAGE_ID, defineMongodbLanguage, registerMongodbLanguage, setMongodbMarkers } from "./monaco.js";
3
3
  import { MonacoEditor } from "@coldsmirk/inkstone-react/monaco";
4
4
  import { useEffect, useInsertionEffect, useRef, useState } from "react";
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@coldsmirk/inkstone-mongodb",
3
- "version": "0.26.0",
4
- "description": "MongoDB command editing intelligence for Monaco: a command document in the shell's own spelling, the database commands and their fields, query, update and aggregation operators by context, collection completion, markers, and a drop-in React command editor.",
3
+ "version": "0.27.0",
4
+ "description": "MongoDB command editing intelligence for Monaco and CodeMirror: a command document in the shell's own spelling, the database commands and their fields, query, update and aggregation operators by context — a bare filter document included — collection completion, markers, and a drop-in React command editor.",
5
5
  "keywords": [
6
6
  "mongodb",
7
7
  "monaco",
8
+ "codemirror",
8
9
  "completion",
9
10
  "editor",
10
11
  "autocomplete",
@@ -28,15 +29,19 @@
28
29
  "types": "./dist/index.d.ts",
29
30
  "default": "./dist/index.js"
30
31
  },
32
+ "./codemirror": {
33
+ "types": "./dist/codemirror.d.ts",
34
+ "default": "./dist/codemirror.js"
35
+ },
31
36
  "./monaco": {
32
37
  "types": "./dist/monaco.d.ts",
33
38
  "default": "./dist/monaco.js"
34
39
  },
40
+ "./package.json": "./package.json",
35
41
  "./react": {
36
42
  "types": "./dist/react.d.ts",
37
43
  "default": "./dist/react.js"
38
- },
39
- "./package.json": "./package.json"
44
+ }
40
45
  },
41
46
  "types": "./dist/index.d.ts",
42
47
  "files": [
@@ -50,7 +55,7 @@
50
55
  "monaco-editor": "^0.56.0",
51
56
  "react": "^19.2.8",
52
57
  "react-dom": "^19.2.8",
53
- "@coldsmirk/inkstone-react": "^0.26.0"
58
+ "@coldsmirk/inkstone-react": "^0.27.0"
54
59
  },
55
60
  "peerDependencies": {
56
61
  "@codemirror/autocomplete": "^6.20.3",
@@ -59,7 +64,7 @@
59
64
  "@codemirror/view": "^6.43.0",
60
65
  "monaco-editor": "^0.56.0",
61
66
  "react": ">=19",
62
- "@coldsmirk/inkstone-react": "^0.26.0"
67
+ "@coldsmirk/inkstone-react": "^0.27.0"
63
68
  },
64
69
  "peerDependenciesMeta": {
65
70
  "@codemirror/autocomplete": {