@coldsmirk/inkstone-sql 0.26.1 → 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.
@@ -326,9 +326,15 @@ interface SqlCompletionCandidate {
326
326
  kind: "keyword" | "function" | "schema" | "table" | "view" | "column" | "snippet";
327
327
  insertText: string;
328
328
  /**
329
- * `insertText` is a snippet (`$0` marks the caret) rather than plain text.
330
- */
331
- snippet?: boolean;
329
+ * Where the caret lands once `insertText` is written, as an offset into it — a call's own
330
+ * parentheses put it between them. Absent, it lands at the end, which is where the next
331
+ * word goes.
332
+ *
333
+ * An offset and not a marker in the text: a marker is an editor's own snippet dialect, and
334
+ * this half of the package states facts about SQL and nothing about any editor. Spelling
335
+ * one here once cost every `$`-prefixed key its name, the editor reading it as a variable.
336
+ */
337
+ caret?: number;
332
338
  /**
333
339
  * Characters immediately before the caret that this insert replaces, beyond the partial word
334
340
  * the editor already replaces on its own. Only the `*` expansion uses it — it stands in for a
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CatalogTable, S as CatalogFunction, _ as readCall, a as createSqlAssist, b as runnableStatement, c as SqlSource, d as CallRead, f as IdentifierRead, g as TableRef, h as StatementRead, i as SqlSignatureHelp, l as createSqlSchema, m as StatementContext, n as SqlCompletionCandidate, o as SqlCatalog, p as Runnable, r as SqlHoverCard, s as SqlSchema, t as SqlAssist, u as qualifiedName, v as readIdentifier, w as SqlKind, x as CatalogColumn, y as readStatement } from "./assist-DTWNM9if.js";
1
+ import { C as CatalogTable, S as CatalogFunction, _ as readCall, a as createSqlAssist, b as runnableStatement, c as SqlSource, d as CallRead, f as IdentifierRead, g as TableRef, h as StatementRead, i as SqlSignatureHelp, l as createSqlSchema, m as StatementContext, n as SqlCompletionCandidate, o as SqlCatalog, p as Runnable, r as SqlHoverCard, s as SqlSchema, t as SqlAssist, u as qualifiedName, v as readIdentifier, w as SqlKind, x as CatalogColumn, y as readStatement } from "./assist-BM4bNDhw.js";
2
2
  //#region src/functions.d.ts
3
3
  /**
4
4
  * The function vocabulary this bench speaks: the curated floor this project wrote
package/dist/index.js CHANGED
@@ -1041,11 +1041,12 @@ function createSqlCompletion(kind, schema, functions) {
1041
1041
  }), ...known.map((entry) => {
1042
1042
  const name = entry.origin === "curated" ? spell(entry.name) : entry.name;
1043
1043
  const written = entry.origin === "curated" ? name : spellCallable(kind, name);
1044
+ const call = entry.qualifier === "" ? written : `${spellIdentifier(kind, entry.qualifier)}.${written}`;
1044
1045
  return {
1045
1046
  label: name,
1046
1047
  kind: "function",
1047
- insertText: `${entry.qualifier === "" ? written : `${spellIdentifier(kind, entry.qualifier)}.${written}`}($0)`,
1048
- snippet: true,
1048
+ insertText: `${call}()`,
1049
+ caret: call.length + 1,
1049
1050
  detail: entry.signature,
1050
1051
  documentation: entry.summary === "" ? void 0 : entry.summary,
1051
1052
  sortGroup: entry.origin === "builtin" ? RANK_VENDOR : RANK_FUNCTION
@@ -0,0 +1,136 @@
1
+ //#region src/snippet.ts
2
+ function asSnippet(text, caret) {
3
+ return `${literal(text.slice(0, caret))}$0${literal(text.slice(caret))}`;
4
+ }
5
+ function literal(part) {
6
+ return part.replaceAll(/[$}\\]/gu, String.raw`\$&`);
7
+ }
8
+ //#endregion
9
+ //#region src/monaco.ts
10
+ function itemKinds(monaco) {
11
+ const kinds = monaco.languages.CompletionItemKind;
12
+ return {
13
+ keyword: kinds.Keyword,
14
+ function: kinds.Function,
15
+ schema: kinds.Module,
16
+ table: kinds.Struct,
17
+ view: kinds.Interface,
18
+ column: kinds.Field,
19
+ snippet: kinds.Snippet
20
+ };
21
+ }
22
+ const FORMATTING_KEY = Symbol.for("coldsmirk.inkstone.sql.formattingRegistry");
23
+ function formattingLedgers(monaco) {
24
+ const holder = globalThis;
25
+ const registries = holder[FORMATTING_KEY] ?? /* @__PURE__ */ new WeakMap();
26
+ holder[FORMATTING_KEY] = registries;
27
+ const existing = registries.get(monaco);
28
+ if (existing) return existing;
29
+ const created = /* @__PURE__ */ new Map();
30
+ registries.set(monaco, created);
31
+ return created;
32
+ }
33
+ function registerFormatting(monaco, languageId, modelPath, hooks) {
34
+ const ledgers = formattingLedgers(monaco);
35
+ let ledger = ledgers.get(languageId);
36
+ if (ledger === void 0) {
37
+ const byPath = /* @__PURE__ */ new Map();
38
+ ledger = {
39
+ hooks: byPath,
40
+ registration: monaco.languages.registerDocumentFormattingEditProvider(languageId, { provideDocumentFormattingEdits: async (model) => {
41
+ const owner = byPath.get(model.uri.toString());
42
+ const assist = owner?.assist() ?? null;
43
+ const text = model.getValue();
44
+ if (owner === void 0 || assist === null || text.trim() === "") return [];
45
+ const formatted = await assist.format(text);
46
+ if (formatted === null) {
47
+ owner.onFormatRefused();
48
+ return [];
49
+ }
50
+ return formatted === text ? [] : [{
51
+ range: model.getFullModelRange(),
52
+ text: formatted
53
+ }];
54
+ } })
55
+ };
56
+ ledgers.set(languageId, ledger);
57
+ }
58
+ const entered = ledger;
59
+ entered.hooks.set(modelPath, hooks);
60
+ return { dispose: () => {
61
+ entered.hooks.delete(modelPath);
62
+ if (entered.hooks.size === 0) {
63
+ entered.registration.dispose();
64
+ ledgers.delete(languageId);
65
+ }
66
+ } };
67
+ }
68
+ function registerSqlLanguage(monaco, modelPath, hooks, languageId = "sql") {
69
+ const kinds = itemKinds(monaco);
70
+ const path = monaco.Uri.parse(modelPath).toString();
71
+ const answering = (model) => model.uri.toString() === path ? hooks.assist() : null;
72
+ return [
73
+ monaco.languages.registerCompletionItemProvider(languageId, {
74
+ triggerCharacters: ["."],
75
+ provideCompletionItems: async (model, position) => {
76
+ const assist = answering(model);
77
+ if (assist === null) return { suggestions: [] };
78
+ const candidates = await assist.complete(model.getValue(), model.getOffsetAt(position));
79
+ const word = model.getWordUntilPosition(position);
80
+ return { suggestions: candidates.map((candidate, index) => {
81
+ return {
82
+ label: candidate.label,
83
+ kind: kinds[candidate.kind],
84
+ insertText: candidate.caret === void 0 ? candidate.insertText : asSnippet(candidate.insertText, candidate.caret),
85
+ insertTextRules: candidate.caret === void 0 ? void 0 : monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
86
+ detail: candidate.detail,
87
+ documentation: candidate.documentation,
88
+ range: new monaco.Range(position.lineNumber, Math.max(1, word.startColumn - (candidate.replace ?? 0)), position.lineNumber, word.endColumn),
89
+ sortText: `${candidate.sortGroup}:${String(index).padStart(5, "0")}`
90
+ };
91
+ }) };
92
+ }
93
+ }),
94
+ monaco.languages.registerHoverProvider(languageId, { provideHover: async (model, position) => {
95
+ const assist = answering(model);
96
+ if (assist === null) return null;
97
+ const card = await assist.hover(model.getValue(), model.getOffsetAt(position));
98
+ if (card === null) return null;
99
+ const from = model.getPositionAt(card.from);
100
+ const to = model.getPositionAt(card.to);
101
+ return {
102
+ range: new monaco.Range(from.lineNumber, from.column, to.lineNumber, to.column),
103
+ contents: card.markdown.map((value) => {
104
+ return { value };
105
+ })
106
+ };
107
+ } }),
108
+ monaco.languages.registerSignatureHelpProvider(languageId, {
109
+ signatureHelpTriggerCharacters: ["(", ","],
110
+ signatureHelpRetriggerCharacters: [","],
111
+ provideSignatureHelp: async (model, position) => {
112
+ const assist = answering(model);
113
+ if (assist === null) return null;
114
+ const help = await assist.signature(model.getValue(), model.getOffsetAt(position));
115
+ if (help === null) return null;
116
+ return {
117
+ value: {
118
+ signatures: [{
119
+ label: help.label,
120
+ documentation: help.documentation,
121
+ parameters: help.parameters.map((span) => {
122
+ return { label: span };
123
+ })
124
+ }],
125
+ activeSignature: 0,
126
+ activeParameter: help.active
127
+ },
128
+ dispose: () => void 0
129
+ };
130
+ }
131
+ }),
132
+ registerFormatting(monaco, languageId, path, hooks)
133
+ ];
134
+ }
135
+ //#endregion
136
+ export { registerSqlLanguage as t };
package/dist/monaco.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as SqlAssist } from "./assist-DTWNM9if.js";
1
+ import { t as SqlAssist } from "./assist-BM4bNDhw.js";
2
2
  import * as monacoEditor from "monaco-editor";
3
3
  import { IDisposable } from "monaco-editor";
4
4
  //#region src/monaco.d.ts
package/dist/monaco.js CHANGED
@@ -1,128 +1,2 @@
1
- //#region src/monaco.ts
2
- function itemKinds(monaco) {
3
- const kinds = monaco.languages.CompletionItemKind;
4
- return {
5
- keyword: kinds.Keyword,
6
- function: kinds.Function,
7
- schema: kinds.Module,
8
- table: kinds.Struct,
9
- view: kinds.Interface,
10
- column: kinds.Field,
11
- snippet: kinds.Snippet
12
- };
13
- }
14
- const FORMATTING_KEY = Symbol.for("coldsmirk.inkstone.sql.formattingRegistry");
15
- function formattingLedgers(monaco) {
16
- const holder = globalThis;
17
- const registries = holder[FORMATTING_KEY] ?? /* @__PURE__ */ new WeakMap();
18
- holder[FORMATTING_KEY] = registries;
19
- const existing = registries.get(monaco);
20
- if (existing) return existing;
21
- const created = /* @__PURE__ */ new Map();
22
- registries.set(monaco, created);
23
- return created;
24
- }
25
- function registerFormatting(monaco, languageId, modelPath, hooks) {
26
- const ledgers = formattingLedgers(monaco);
27
- let ledger = ledgers.get(languageId);
28
- if (ledger === void 0) {
29
- const byPath = /* @__PURE__ */ new Map();
30
- ledger = {
31
- hooks: byPath,
32
- registration: monaco.languages.registerDocumentFormattingEditProvider(languageId, { provideDocumentFormattingEdits: async (model) => {
33
- const owner = byPath.get(model.uri.toString());
34
- const assist = owner?.assist() ?? null;
35
- const text = model.getValue();
36
- if (owner === void 0 || assist === null || text.trim() === "") return [];
37
- const formatted = await assist.format(text);
38
- if (formatted === null) {
39
- owner.onFormatRefused();
40
- return [];
41
- }
42
- return formatted === text ? [] : [{
43
- range: model.getFullModelRange(),
44
- text: formatted
45
- }];
46
- } })
47
- };
48
- ledgers.set(languageId, ledger);
49
- }
50
- const entered = ledger;
51
- entered.hooks.set(modelPath, hooks);
52
- return { dispose: () => {
53
- entered.hooks.delete(modelPath);
54
- if (entered.hooks.size === 0) {
55
- entered.registration.dispose();
56
- ledgers.delete(languageId);
57
- }
58
- } };
59
- }
60
- function registerSqlLanguage(monaco, modelPath, hooks, languageId = "sql") {
61
- const kinds = itemKinds(monaco);
62
- const path = monaco.Uri.parse(modelPath).toString();
63
- const answering = (model) => model.uri.toString() === path ? hooks.assist() : null;
64
- return [
65
- monaco.languages.registerCompletionItemProvider(languageId, {
66
- triggerCharacters: ["."],
67
- provideCompletionItems: async (model, position) => {
68
- const assist = answering(model);
69
- if (assist === null) return { suggestions: [] };
70
- const candidates = await assist.complete(model.getValue(), model.getOffsetAt(position));
71
- const word = model.getWordUntilPosition(position);
72
- return { suggestions: candidates.map((candidate, index) => {
73
- return {
74
- label: candidate.label,
75
- kind: kinds[candidate.kind],
76
- insertText: candidate.insertText,
77
- insertTextRules: candidate.snippet ? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet : void 0,
78
- detail: candidate.detail,
79
- documentation: candidate.documentation,
80
- range: new monaco.Range(position.lineNumber, Math.max(1, word.startColumn - (candidate.replace ?? 0)), position.lineNumber, word.endColumn),
81
- sortText: `${candidate.sortGroup}:${String(index).padStart(5, "0")}`
82
- };
83
- }) };
84
- }
85
- }),
86
- monaco.languages.registerHoverProvider(languageId, { provideHover: async (model, position) => {
87
- const assist = answering(model);
88
- if (assist === null) return null;
89
- const card = await assist.hover(model.getValue(), model.getOffsetAt(position));
90
- if (card === null) return null;
91
- const from = model.getPositionAt(card.from);
92
- const to = model.getPositionAt(card.to);
93
- return {
94
- range: new monaco.Range(from.lineNumber, from.column, to.lineNumber, to.column),
95
- contents: card.markdown.map((value) => {
96
- return { value };
97
- })
98
- };
99
- } }),
100
- monaco.languages.registerSignatureHelpProvider(languageId, {
101
- signatureHelpTriggerCharacters: ["(", ","],
102
- signatureHelpRetriggerCharacters: [","],
103
- provideSignatureHelp: async (model, position) => {
104
- const assist = answering(model);
105
- if (assist === null) return null;
106
- const help = await assist.signature(model.getValue(), model.getOffsetAt(position));
107
- if (help === null) return null;
108
- return {
109
- value: {
110
- signatures: [{
111
- label: help.label,
112
- documentation: help.documentation,
113
- parameters: help.parameters.map((span) => {
114
- return { label: span };
115
- })
116
- }],
117
- activeSignature: 0,
118
- activeParameter: help.active
119
- },
120
- dispose: () => void 0
121
- };
122
- }
123
- }),
124
- registerFormatting(monaco, languageId, path, hooks)
125
- ];
126
- }
127
- //#endregion
1
+ import { t as registerSqlLanguage } from "./monaco-DEMsSuzD.js";
128
2
  export { registerSqlLanguage };
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as SqlAssist } from "./assist-DTWNM9if.js";
1
+ import { t as SqlAssist } from "./assist-BM4bNDhw.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 { registerSqlLanguage } from "./monaco.js";
1
+ import { t as registerSqlLanguage } from "./monaco-DEMsSuzD.js";
2
2
  import { MonacoEditor } from "@coldsmirk/inkstone-react/monaco";
3
3
  import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldsmirk/inkstone-sql",
3
- "version": "0.26.1",
3
+ "version": "0.27.0",
4
4
  "description": "Schema-aware SQL editing intelligence for Monaco: lexical statement reading under per-dialect noise profiles, catalog-driven completion/hover/signature help, unified-placeholder awareness, formatting, and a drop-in React SQL editor.",
5
5
  "keywords": [
6
6
  "sql",
@@ -49,12 +49,12 @@
49
49
  "monaco-editor": "^0.56.0",
50
50
  "react": "^19.2.8",
51
51
  "react-dom": "^19.2.8",
52
- "@coldsmirk/inkstone-react": "^0.26.1"
52
+ "@coldsmirk/inkstone-react": "^0.27.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "monaco-editor": "^0.56.0",
56
56
  "react": ">=19",
57
- "@coldsmirk/inkstone-react": "^0.26.1"
57
+ "@coldsmirk/inkstone-react": "^0.27.0"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "@coldsmirk/inkstone-react": {