@coldsmirk/inkstone-sql 0.31.0 → 0.33.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 +3 -3
- package/dist/{assist-BM4bNDhw.d.ts → assist-Cr2idunB.d.ts} +8 -4
- package/dist/index.d.ts +27 -14
- package/dist/index.js +115 -19
- package/dist/monaco.d.ts +1 -1
- package/dist/react.d.ts +16 -91
- package/dist/react.js +39 -128
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). Extracted from dragom
|
|
|
8
8
|
|
|
9
9
|
- **`@coldsmirk/inkstone-sql`** — the framework-free core. Zero editor dependencies; runs anywhere.
|
|
10
10
|
- **`@coldsmirk/inkstone-sql/monaco`** — `registerSqlLanguage(monaco, modelPath, hooks)`: the Monaco providers (completion, hover, signature help, formatting) over an assist read per-request through a hook. Peer: `monaco-editor`.
|
|
11
|
-
- **`@coldsmirk/inkstone-sql/react`** — `<SqlEditor>`: a controlled SQL editor built on `@coldsmirk/inkstone-react`'s `<
|
|
11
|
+
- **`@coldsmirk/inkstone-sql/react`** — `<SqlEditor>`: a controlled SQL editor built on `@coldsmirk/inkstone-react`'s `<MonacoConsoleEditor>`, with a run key (Ctrl/Cmd-Enter handing over the live caret), a runnable-statement gutter mark, caret tracking, and an insert/focus/format handle for schema trees and toolbars. Peers: `monaco-editor`, `react`.
|
|
12
12
|
|
|
13
13
|
## The shape
|
|
14
14
|
|
|
@@ -31,7 +31,7 @@ const runnable = runnableStatement(text, from, to, "postgres");
|
|
|
31
31
|
if (runnable.kind === "one") {
|
|
32
32
|
// Markers are read off the BLANKED form — `select '?'` binds nothing — and under the kind's
|
|
33
33
|
// own binding rules: `markers.refusal` mirrors the engine scanner's own faults (mixed forms,
|
|
34
|
-
// `??` on mysql/dm, a hand-written `$1` beside a minted marker), so the editor can say so
|
|
34
|
+
// `??` on mysql/dm/clickhouse, a hand-written `$1` beside a minted marker), so the editor can say so
|
|
35
35
|
// before the round trip does.
|
|
36
36
|
const markers = statementMarkers(runnable.blanked, "postgres");
|
|
37
37
|
}
|
|
@@ -41,7 +41,7 @@ Everything the intelligence answers goes through one lexical reader taken under
|
|
|
41
41
|
|
|
42
42
|
## The mirror invariant
|
|
43
43
|
|
|
44
|
-
`noise.ts` (which runs of a statement are strings / comments / quoted names, per kind) and the marker grammar mirror [**polyglot's engine scanner**](https://github.com/coldsmirk/polyglot) (`
|
|
44
|
+
`noise.ts` (which runs of a statement are strings / comments / quoted names, per kind) and the marker grammar mirror [**polyglot's engine scanner**](https://github.com/coldsmirk/polyglot) (`sql/Placeholders`, over its profiles in `kinds/Dialect`) flag for flag, each kind under the two lexicons the sidecar reads it by: the database's own says where a statement ends and what is prose, and the one the kind's driver finds a `?` by says where the markers are — SQL Server nests a block comment, but Microsoft's driver ends one at its first close and binds a `?` past it. The scanner decides what actually binds; a reader that diverged would prompt for a parameter the engine refuses, or send a statement short of one it binds. **A scanner change requires a matching release of this package**, and the per-kind cases in `reader.test.ts` are the invariant's guard.
|
|
45
45
|
|
|
46
46
|
## Structured refusals
|
|
47
47
|
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
* Doris (`doris`, StarRocks and SelectDB with it) speaks MySQL's protocol and grammar and reads
|
|
15
15
|
* here as the MySQL idiom throughout, but its own parser admits no identifier past ASCII bare —
|
|
16
16
|
* `患者` must be backticked where MySQL takes it as written — so it earned a kind for its spelling.
|
|
17
|
+
* ClickHouse (`clickhouse`) is a lexicon of its own on the engine — backslash escapes and backtick
|
|
18
|
+
* names as MySQL's, but `--` a comment without its space, `?` its own bind marker — and names its
|
|
19
|
+
* functions by their case (`toDate`, never `TODATE`).
|
|
17
20
|
*/
|
|
18
|
-
type SqlKind = "postgres" | "mysql" | "oracle" | "sqlserver" | "dm" | "kingbase" | "doris";
|
|
21
|
+
type SqlKind = "postgres" | "mysql" | "oracle" | "sqlserver" | "dm" | "kingbase" | "doris" | "clickhouse";
|
|
19
22
|
/**
|
|
20
23
|
* One table or view as the catalog reports it. Names carry the vendor's own casing — that casing
|
|
21
24
|
* is information, and everything downstream preserves it.
|
|
@@ -170,9 +173,10 @@ type Runnable = {
|
|
|
170
173
|
*/
|
|
171
174
|
text: string;
|
|
172
175
|
/**
|
|
173
|
-
* The
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
+
* The statement as the engine's own scanner reads it when it is sent — under the lexicon the
|
|
177
|
+
* kind's driver finds a `?` by, from the statement's own start — with everything the scanner
|
|
178
|
+
* skips whole (literals, comments and quoted names) overwritten by spaces, character for
|
|
179
|
+
* character, so offsets still line up with `text`. A marker scan must read this: in
|
|
176
180
|
* `select '?'` the `?` is prose, and a marker scan of the raw text would ask the operator for
|
|
177
181
|
* a value the engine then refuses as an extra argument.
|
|
178
182
|
*/
|
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-
|
|
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-Cr2idunB.js";
|
|
2
2
|
//#region src/functions.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The function vocabulary this bench speaks: the curated floor this project wrote
|
|
@@ -78,11 +78,17 @@ interface SqlFunction {
|
|
|
78
78
|
* manual: the words an integration engineer writes at this console, weighted toward reading — a
|
|
79
79
|
* keyword or function missing here costs one suggestion, so the lists stay honest rather than
|
|
80
80
|
* exhaustive. Everything is lowercase, the casing the bench itself writes (the tree's
|
|
81
|
-
* `select * from`, the editor placeholder); completion re-cases it to follow the operator's hand
|
|
81
|
+
* `select * from`, the editor placeholder); completion re-cases it to follow the operator's hand —
|
|
82
|
+
* but for the functions of a kind that names them by their case, spelled as the vendor spells them.
|
|
82
83
|
*/
|
|
83
84
|
interface SqlDialect {
|
|
84
85
|
keywords: string[];
|
|
85
86
|
functions: SqlFunction[];
|
|
87
|
+
/**
|
|
88
|
+
* The kind names a function by its case (ClickHouse's `toDate`, never `TODATE`): its curated
|
|
89
|
+
* functions are written as listed, whatever the operator's hand.
|
|
90
|
+
*/
|
|
91
|
+
functionsByCase?: boolean;
|
|
86
92
|
}
|
|
87
93
|
export declare const SQL_DIALECTS: Record<SqlKind, SqlDialect>;
|
|
88
94
|
/**
|
|
@@ -133,11 +139,11 @@ export declare function joinGuesses(kind: SqlKind, target: SqlSource, others: Sq
|
|
|
133
139
|
* Placeholder detection for what a run asks the operator for.
|
|
134
140
|
*
|
|
135
141
|
* This is **not** validation and must never become it: the engine-side scanner (the polyglot
|
|
136
|
-
* sidecar's `
|
|
137
|
-
* implementation here would drift from it the first time a dialect gained a quoting
|
|
138
|
-
* this decides is whether the run has values to ask for, which form the parameter
|
|
139
|
-
* offers, and — where the statement is one the scanner refuses outright — the refusal, as
|
|
140
|
-
* code, so the editor can say so before the round trip does.
|
|
142
|
+
* sidecar's `sql/Placeholders`) is the authority on what binds, it is lexical and per-dialect,
|
|
143
|
+
* and a second implementation here would drift from it the first time a dialect gained a quoting
|
|
144
|
+
* form. All this decides is whether the run has values to ask for, which form the parameter
|
|
145
|
+
* dialog offers, and — where the statement is one the scanner refuses outright — the refusal, as
|
|
146
|
+
* a code, so the editor can say so before the round trip does.
|
|
141
147
|
*
|
|
142
148
|
* **Callers pass the statement's blanked form** (`Runnable.blanked`), never its raw text. A
|
|
143
149
|
* disagreement with the engine's scanner is not cosmetic in either direction — it answers both
|
|
@@ -146,8 +152,9 @@ export declare function joinGuesses(kind: SqlKind, target: SqlSource, others: Sq
|
|
|
146
152
|
* has no placeholder in it. Blanking is the reader's job because the reader already owns what is
|
|
147
153
|
* prose and what is SQL for this page, and it takes that decision under the data source's own
|
|
148
154
|
* lexical profile (`noise.ts`), mode for mode with the scanner — MySQL's `#` comments and
|
|
149
|
-
* backslash escapes, Postgres's `$tag$` bodies, Oracle's `q'…'`, every kind's quoted names
|
|
150
|
-
* what reaches this file is exactly the
|
|
155
|
+
* backslash escapes, Postgres's `$tag$` bodies, Oracle's `q'…'`, every kind's quoted names, and
|
|
156
|
+
* SQL Server's block comments as its driver ends them — so what reaches this file is exactly the
|
|
157
|
+
* text the engine would mint markers from.
|
|
151
158
|
*/
|
|
152
159
|
/**
|
|
153
160
|
* The binding form a statement's markers suggest.
|
|
@@ -159,8 +166,8 @@ type MarkerForm = "none" | "positional" | "named";
|
|
|
159
166
|
*
|
|
160
167
|
* - `"mixed-forms"` — the statement writes both `?` and `:name`; the scanner binds neither.
|
|
161
168
|
* - `"question-escape-unsupported"` — `??` on a kind whose native form is itself `?` (MySQL,
|
|
162
|
-
*
|
|
163
|
-
* escape in the first place.
|
|
169
|
+
* 达梦, ClickHouse): the escape has no rendering that survives, and none of them has a `?`
|
|
170
|
+
* operator to escape in the first place.
|
|
164
171
|
* - `"native-marker-collision"` — a marker hand-written in the kind's own bind form (`$1`,
|
|
165
172
|
* `:1`, `@p1`) beside a `?`/`:name` the scanner would mint: both would bind the same slot.
|
|
166
173
|
*/
|
|
@@ -191,6 +198,11 @@ interface StatementMarkers {
|
|
|
191
198
|
export declare function statementMarkers(statement: string, kind: SqlKind): StatementMarkers;
|
|
192
199
|
//#endregion
|
|
193
200
|
//#region src/noise.d.ts
|
|
201
|
+
/**
|
|
202
|
+
* Which lexicon a text is read under: the database's own — where a statement ends, what is prose
|
|
203
|
+
* — or the one the kind's driver finds a `?` by, which the sidecar mints its markers under.
|
|
204
|
+
*/
|
|
205
|
+
type NoiseLexicon = "database" | "driver";
|
|
194
206
|
/**
|
|
195
207
|
* A run the reader must not look inside. `sealed` says the closing delimiter was found: a caret
|
|
196
208
|
* right after a sealed run is back in the statement, while a caret at the end of an unterminated
|
|
@@ -223,9 +235,10 @@ interface BlankedSql {
|
|
|
223
235
|
/**
|
|
224
236
|
* The statement with its noise blanked out, char for char, so every offset survives — in the two
|
|
225
237
|
* renderings the reader needs (see [BlankedSql]). One pass, mirroring the sidecar scanner's own
|
|
226
|
-
* loop over its mutually exclusive lexical modes
|
|
238
|
+
* loop over its mutually exclusive lexical modes, under the database's own lexicon unless the
|
|
239
|
+
* driver's is asked for.
|
|
227
240
|
*/
|
|
228
|
-
export declare function blankNoise(text: string, kind: SqlKind): BlankedSql;
|
|
241
|
+
export declare function blankNoise(text: string, kind: SqlKind, lexicon?: NoiseLexicon): BlankedSql;
|
|
229
242
|
/**
|
|
230
243
|
* Whether the caret sits inside a string or a comment, where the bench has nothing to say. A
|
|
231
244
|
* quoted name is not one: it is a name the operator is writing, and the reader is about names.
|
|
@@ -373,4 +386,4 @@ export declare function spellQualifiedName(kind: SqlKind, table: {
|
|
|
373
386
|
name: string;
|
|
374
387
|
}): string;
|
|
375
388
|
//#endregion
|
|
376
|
-
export { type BenchFunction, type BindRefusal, type BlankedSql, type Bound, type BoundParams, type CallRead, type CatalogColumn, type CatalogFunction, type CatalogTable, type IdentifierRead, type JoinGuess, type JoinReason, type MarkerForm, type MarkerRefusal, type NoiseSpan, type ParamType, type ParamValue, type Runnable, type SqlAssist, type SqlCatalog, type SqlCompletionCandidate, type SqlDialect, type SqlFunction, type SqlFunctions, type SqlHoverCard, type SqlKind, type SqlScalar, type SqlSchema, type SqlSignatureHelp, type SqlSource, type StatementContext, type StatementMarkers, type StatementOrigin, type StatementRead, type TableRef, createSqlAssist, createSqlSchema, qualifiedName, readCall, readIdentifier, readStatement, runnableStatement };
|
|
389
|
+
export { type BenchFunction, type BindRefusal, type BlankedSql, type Bound, type BoundParams, type CallRead, type CatalogColumn, type CatalogFunction, type CatalogTable, type IdentifierRead, type JoinGuess, type JoinReason, type MarkerForm, type MarkerRefusal, type NoiseLexicon, type NoiseSpan, type ParamType, type ParamValue, type Runnable, type SqlAssist, type SqlCatalog, type SqlCompletionCandidate, type SqlDialect, type SqlFunction, type SqlFunctions, type SqlHoverCard, type SqlKind, type SqlScalar, type SqlSchema, type SqlSignatureHelp, type SqlSource, type StatementContext, type StatementMarkers, type StatementOrigin, type StatementRead, type TableRef, createSqlAssist, createSqlSchema, qualifiedName, readCall, readIdentifier, readStatement, runnableStatement };
|
package/dist/index.js
CHANGED
|
@@ -181,6 +181,63 @@ const MYSQL = dialect([
|
|
|
181
181
|
fn("group_concat", "group_concat(expr)", "Aggregate: joins each row's value into one string; takes `separator '…'`."),
|
|
182
182
|
fn("json_extract", "json_extract(json, path)", "Reads a JSON path, as in `'$.id'`.")
|
|
183
183
|
]);
|
|
184
|
+
const CLICKHOUSE = {
|
|
185
|
+
...dialect([
|
|
186
|
+
"final",
|
|
187
|
+
"prewhere",
|
|
188
|
+
"sample",
|
|
189
|
+
"array",
|
|
190
|
+
"global",
|
|
191
|
+
"any",
|
|
192
|
+
"asof",
|
|
193
|
+
"semi",
|
|
194
|
+
"anti",
|
|
195
|
+
"limit",
|
|
196
|
+
"offset",
|
|
197
|
+
"settings",
|
|
198
|
+
"format",
|
|
199
|
+
"totals",
|
|
200
|
+
"rollup",
|
|
201
|
+
"cube",
|
|
202
|
+
"ilike",
|
|
203
|
+
"interval",
|
|
204
|
+
"true",
|
|
205
|
+
"false"
|
|
206
|
+
], [
|
|
207
|
+
fn("now", "now(timezone)", "Current date and time, in the server's time zone unless one is named."),
|
|
208
|
+
fn("today", "today()", "Current date."),
|
|
209
|
+
fn("toDate", "toDate(value)", "Converts to a Date."),
|
|
210
|
+
fn("toDateTime", "toDateTime(value, timezone)", "Converts to a DateTime, in a time zone where one is named."),
|
|
211
|
+
fn("toString", "toString(value)", "Converts to a String."),
|
|
212
|
+
fn("toInt64", "toInt64(value)", "Converts to a 64-bit integer."),
|
|
213
|
+
fn("toFloat64", "toFloat64(value)", "Converts to a 64-bit float."),
|
|
214
|
+
fn("toStartOfDay", "toStartOfDay(time)", "Rounds a time down to the start of its day."),
|
|
215
|
+
fn("toStartOfHour", "toStartOfHour(time)", "Rounds a time down to the start of its hour."),
|
|
216
|
+
fn("toStartOfMonth", "toStartOfMonth(date)", "Rounds a date down to the first day of its month."),
|
|
217
|
+
fn("formatDateTime", "formatDateTime(time, format)", "Formats a time through a format string, as in `'%Y-%m-%d'`."),
|
|
218
|
+
fn("dateDiff", "dateDiff(unit, start, end)", "Unit boundaries crossed between two times, as in `dateDiff('day', a, b)`."),
|
|
219
|
+
fn("if", "if(condition, then, else)", "Ternary choice."),
|
|
220
|
+
fn("multiIf", "multiIf(condition, then, …, else)", "The value of the first condition that holds, or the last argument."),
|
|
221
|
+
fn("ifNull", "ifNull(value, fallback)", "The second argument when the first is NULL."),
|
|
222
|
+
fn("concat", "concat(value, …)", "Joins the arguments as strings."),
|
|
223
|
+
fn("length", "length(value)", "Bytes in a string, elements in an array; `lengthUTF8` counts characters."),
|
|
224
|
+
fn("substring", "substring(text, offset, length)", "`length` bytes from byte `offset`, counting from 1; `substringUTF8` counts characters."),
|
|
225
|
+
fn("position", "position(text, search)", "Byte position of a substring, counting from 1, or 0 when it is absent."),
|
|
226
|
+
fn("replaceAll", "replaceAll(text, search, replacement)", "Replaces every occurrence of a substring."),
|
|
227
|
+
fn("splitByChar", "splitByChar(separator, text)", "Splits a string on a one-character separator into an array."),
|
|
228
|
+
fn("JSONExtractString", "JSONExtractString(json, key, …)", "A string read out of JSON by key or index, empty where there is none."),
|
|
229
|
+
fn("has", "has(array, value)", "Whether the array holds the value."),
|
|
230
|
+
fn("arrayJoin", "arrayJoin(array)", "One row per element of the array."),
|
|
231
|
+
fn("countIf", "countIf(condition)", "Aggregate: rows for which the condition holds."),
|
|
232
|
+
fn("sumIf", "sumIf(value, condition)", "Aggregate: the sum over the rows for which the condition holds."),
|
|
233
|
+
fn("uniq", "uniq(expr)", "Aggregate: the distinct values, counted approximately."),
|
|
234
|
+
fn("uniqExact", "uniqExact(expr)", "Aggregate: the distinct values, counted exactly."),
|
|
235
|
+
fn("groupArray", "groupArray(expr)", "Aggregate: collects each row's value into an array."),
|
|
236
|
+
fn("argMax", "argMax(value, by)", "Aggregate: `value` from the row where `by` is largest."),
|
|
237
|
+
fn("any", "any(expr)", "Aggregate: one value of the group, whichever is met first.")
|
|
238
|
+
]),
|
|
239
|
+
functionsByCase: true
|
|
240
|
+
};
|
|
184
241
|
const SQL_DIALECTS = {
|
|
185
242
|
postgres: POSTGRES$1,
|
|
186
243
|
kingbase: POSTGRES$1,
|
|
@@ -222,7 +279,8 @@ const SQL_DIALECTS = {
|
|
|
222
279
|
fn("rtrim", "rtrim(text)", "Strips trailing whitespace."),
|
|
223
280
|
fn("string_agg", "string_agg(expr, delimiter)", "Aggregate: joins each row's value with a delimiter.")
|
|
224
281
|
]),
|
|
225
|
-
dm: ORACLE$1
|
|
282
|
+
dm: ORACLE$1,
|
|
283
|
+
clickhouse: CLICKHOUSE
|
|
226
284
|
};
|
|
227
285
|
function signatureParameters(signature) {
|
|
228
286
|
const open = signature.indexOf("(");
|
|
@@ -323,6 +381,13 @@ const TSQL_RESERVED = reservedWords(`
|
|
|
323
381
|
tran transaction trigger truncate try_convert tsequal union unique unpivot update updatetext
|
|
324
382
|
use user values varying view waitfor when where while with within writetext
|
|
325
383
|
`);
|
|
384
|
+
const CLICKHOUSE_RESERVED = reservedWords(`
|
|
385
|
+
all and anti any array as asc asof between by case cast collate cross cube desc distinct else
|
|
386
|
+
end except exists false fill final first format from full global group having ilike in inner
|
|
387
|
+
insert interpolate intersect interval into is join last left like limit not null nulls offset
|
|
388
|
+
on or order outer paste prewhere qualify right rollup sample select semi settings step table
|
|
389
|
+
then totals true union using values when where window with
|
|
390
|
+
`);
|
|
326
391
|
const ORACLE = {
|
|
327
392
|
open: "\"",
|
|
328
393
|
close: "\"",
|
|
@@ -357,10 +422,18 @@ const SPELLINGS = {
|
|
|
357
422
|
regular: /^[a-z_@#][\w@#$]*$/i,
|
|
358
423
|
reserved: TSQL_RESERVED
|
|
359
424
|
},
|
|
360
|
-
dm: ORACLE
|
|
425
|
+
dm: ORACLE,
|
|
426
|
+
clickhouse: {
|
|
427
|
+
open: "`",
|
|
428
|
+
close: "`",
|
|
429
|
+
backslash: true,
|
|
430
|
+
regular: /^[a-z_]\w*$/i,
|
|
431
|
+
reserved: CLICKHOUSE_RESERVED
|
|
432
|
+
}
|
|
361
433
|
};
|
|
362
434
|
function delimited(spelling, name) {
|
|
363
|
-
|
|
435
|
+
const escaped = spelling.backslash === true ? name.replaceAll("\\", () => "\\\\") : name;
|
|
436
|
+
return `${spelling.open}${escaped.replaceAll(spelling.close, () => spelling.close + spelling.close)}${spelling.close}`;
|
|
364
437
|
}
|
|
365
438
|
function spellIdentifier(kind, name) {
|
|
366
439
|
const spelling = SPELLINGS[kind];
|
|
@@ -434,6 +507,11 @@ const BASE = {
|
|
|
434
507
|
nestedBlockComments: false,
|
|
435
508
|
alternativeQuoting: false
|
|
436
509
|
};
|
|
510
|
+
const SQLSERVER = {
|
|
511
|
+
...BASE,
|
|
512
|
+
bracketIdentifiers: true,
|
|
513
|
+
nestedBlockComments: true
|
|
514
|
+
};
|
|
437
515
|
const NOISE_PROFILES = {
|
|
438
516
|
postgres: {
|
|
439
517
|
...BASE,
|
|
@@ -461,18 +539,25 @@ const NOISE_PROFILES = {
|
|
|
461
539
|
...BASE,
|
|
462
540
|
alternativeQuoting: true
|
|
463
541
|
},
|
|
464
|
-
sqlserver:
|
|
465
|
-
...BASE,
|
|
466
|
-
bracketIdentifiers: true
|
|
467
|
-
},
|
|
542
|
+
sqlserver: SQLSERVER,
|
|
468
543
|
dm: BASE,
|
|
469
544
|
kingbase: {
|
|
470
545
|
...BASE,
|
|
471
546
|
escapeStrings: true,
|
|
472
547
|
nestedBlockComments: true,
|
|
473
548
|
dollarQuoting: true
|
|
549
|
+
},
|
|
550
|
+
clickhouse: {
|
|
551
|
+
...BASE,
|
|
552
|
+
backslashEscapes: true,
|
|
553
|
+
hashLineComments: true,
|
|
554
|
+
backtickIdentifiers: true
|
|
474
555
|
}
|
|
475
556
|
};
|
|
557
|
+
const DRIVER_PROFILES = { sqlserver: {
|
|
558
|
+
...SQLSERVER,
|
|
559
|
+
nestedBlockComments: false
|
|
560
|
+
} };
|
|
476
561
|
const WORD_START = /[a-z_\u{0080}-\u{FFFF}]/iu;
|
|
477
562
|
const WORD_BYTE = /[\w$\u{0080}-\u{FFFF}]/u;
|
|
478
563
|
const NAME_BYTE = /\w/;
|
|
@@ -575,10 +660,14 @@ function opensLineComment(text, from, profile) {
|
|
|
575
660
|
const after = text[from + 2];
|
|
576
661
|
return !profile.lineCommentNeedsSpace || after === void 0 || after <= " ";
|
|
577
662
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
663
|
+
const lastBlanked = {
|
|
664
|
+
database: null,
|
|
665
|
+
driver: null
|
|
666
|
+
};
|
|
667
|
+
function blankNoise(text, kind, lexicon = "database") {
|
|
668
|
+
const last = lastBlanked[lexicon];
|
|
669
|
+
if (last !== null && last.text === text && last.kind === kind) return last.result;
|
|
670
|
+
const profile = lexicon === "driver" ? DRIVER_PROFILES[kind] ?? NOISE_PROFILES[kind] : NOISE_PROFILES[kind];
|
|
582
671
|
const withNames = text.split("");
|
|
583
672
|
const blanked = text.split("");
|
|
584
673
|
const spans = [];
|
|
@@ -622,7 +711,7 @@ function blankNoise(text, kind) {
|
|
|
622
711
|
blanked: blanked.join(""),
|
|
623
712
|
spans
|
|
624
713
|
};
|
|
625
|
-
lastBlanked = {
|
|
714
|
+
lastBlanked[lexicon] = {
|
|
626
715
|
text,
|
|
627
716
|
kind,
|
|
628
717
|
result
|
|
@@ -918,10 +1007,11 @@ function runnableStatement(text, from, to, kind) {
|
|
|
918
1007
|
if (spans.length === 0) return { kind: "none" };
|
|
919
1008
|
if (selected && spans.length > 1) return { kind: "several" };
|
|
920
1009
|
const span = spans[0];
|
|
1010
|
+
const statement = text.slice(span.from, span.to);
|
|
921
1011
|
return {
|
|
922
1012
|
kind: "one",
|
|
923
|
-
text:
|
|
924
|
-
blanked:
|
|
1013
|
+
text: statement,
|
|
1014
|
+
blanked: blankNoise(statement, kind, "driver").blanked,
|
|
925
1015
|
from: span.from,
|
|
926
1016
|
to: span.to,
|
|
927
1017
|
alone: statementSpans(text, blanked, 0, text.length).length <= 1
|
|
@@ -1023,7 +1113,7 @@ function expansionCandidate(kind, sources, replacesStar) {
|
|
|
1023
1113
|
};
|
|
1024
1114
|
}
|
|
1025
1115
|
function createSqlCompletion(kind, schema, functions) {
|
|
1026
|
-
const { keywords } = SQL_DIALECTS[kind];
|
|
1116
|
+
const { keywords, functionsByCase = false } = SQL_DIALECTS[kind];
|
|
1027
1117
|
const spelled = /* @__PURE__ */ new Map();
|
|
1028
1118
|
async function wordCandidates(typed) {
|
|
1029
1119
|
const upper = typed !== "" && typed === typed.toUpperCase() && typed !== typed.toLowerCase();
|
|
@@ -1039,7 +1129,7 @@ function createSqlCompletion(kind, schema, functions) {
|
|
|
1039
1129
|
sortGroup: RANK_KEYWORD
|
|
1040
1130
|
};
|
|
1041
1131
|
}), ...known.map((entry) => {
|
|
1042
|
-
const name = entry.origin === "curated" ? spell(entry.name) : entry.name;
|
|
1132
|
+
const name = entry.origin === "curated" && !functionsByCase ? spell(entry.name) : entry.name;
|
|
1043
1133
|
const written = entry.origin === "curated" ? name : spellCallable(kind, name);
|
|
1044
1134
|
const call = entry.qualifier === "" ? written : `${spellIdentifier(kind, entry.qualifier)}.${written}`;
|
|
1045
1135
|
return {
|
|
@@ -1161,7 +1251,8 @@ const DIALECTS = {
|
|
|
1161
1251
|
oracle: "plsql",
|
|
1162
1252
|
dm: "plsql",
|
|
1163
1253
|
sqlserver: "transactsql",
|
|
1164
|
-
kingbase: "postgresql"
|
|
1254
|
+
kingbase: "postgresql",
|
|
1255
|
+
clickhouse: "clickhouse"
|
|
1165
1256
|
};
|
|
1166
1257
|
const PLACEHOLDERS = String.raw`\?|:[A-Za-z_]\w*`;
|
|
1167
1258
|
function sentinelFor(text) {
|
|
@@ -1427,7 +1518,11 @@ function createSqlAssist(kind, catalog) {
|
|
|
1427
1518
|
//#endregion
|
|
1428
1519
|
//#region src/markers.ts
|
|
1429
1520
|
const SCAN = /[A-Z_\u0080-\uFFFF][\w$\u0080-\uFFFF]*|(?<qq>\?\?)|::|(?<q>\?)|:(?<name>[A-Z_]\w*)|(?<colonDigits>:\d+)|(?<dollarDigits>\$\d+)|(?<atDigits>@P\d+)/gi;
|
|
1430
|
-
const QUESTION_IS_NATIVE = /* @__PURE__ */ new Set([
|
|
1521
|
+
const QUESTION_IS_NATIVE = /* @__PURE__ */ new Set([
|
|
1522
|
+
"mysql",
|
|
1523
|
+
"dm",
|
|
1524
|
+
"clickhouse"
|
|
1525
|
+
]);
|
|
1431
1526
|
const NATIVE_GROUP = {
|
|
1432
1527
|
postgres: "dollarDigits",
|
|
1433
1528
|
mysql: null,
|
|
@@ -1435,7 +1530,8 @@ const NATIVE_GROUP = {
|
|
|
1435
1530
|
oracle: "colonDigits",
|
|
1436
1531
|
sqlserver: "atDigits",
|
|
1437
1532
|
dm: null,
|
|
1438
|
-
kingbase: "dollarDigits"
|
|
1533
|
+
kingbase: "dollarDigits",
|
|
1534
|
+
clickhouse: null
|
|
1439
1535
|
};
|
|
1440
1536
|
function statementMarkers(statement, kind) {
|
|
1441
1537
|
const names = [];
|
package/dist/monaco.d.ts
CHANGED
package/dist/react.d.ts
CHANGED
|
@@ -1,92 +1,33 @@
|
|
|
1
|
-
import { t as SqlAssist } from "./assist-
|
|
2
|
-
import {
|
|
1
|
+
import { t as SqlAssist } from "./assist-Cr2idunB.js";
|
|
2
|
+
import { ConsoleCaret, ConsoleEditorHandle, ConsoleEditorProps } from "@coldsmirk/inkstone-react/monaco";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
|
-
import { editor } from "monaco-editor";
|
|
5
4
|
//#region src/react.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* What a host needs to reach into the editor for: inserting at the caret (a schema tree is an
|
|
8
|
-
* input device, not a browser), and reformatting from a toolbar — which goes through
|
|
9
|
-
* formatting action, so the button and `Shift+Alt+F` are one path and one undo.
|
|
7
|
+
* input device, not a browser), the focus, and reformatting from a toolbar — which goes through
|
|
8
|
+
* Monaco's own formatting action, so the button and `Shift+Alt+F` are one path and one undo.
|
|
10
9
|
*/
|
|
11
|
-
export interface SqlEditorHandle {
|
|
12
|
-
insert: (text: string) => void;
|
|
10
|
+
export interface SqlEditorHandle extends ConsoleEditorHandle {
|
|
13
11
|
format: () => void;
|
|
14
12
|
}
|
|
15
13
|
/**
|
|
16
14
|
* Where the operator is in the document, in offsets — everything a host needs to decide which
|
|
17
|
-
* statement a run should send, and nothing about SQL.
|
|
18
|
-
* bounds and are equal where nothing is selected: a caret is a selection of nothing.
|
|
19
|
-
*
|
|
20
|
-
* It rides with the text rather than beside it because the two must belong to the same instant.
|
|
21
|
-
* The controlled `value` is one React render behind the keystroke that triggered a run, and a
|
|
22
|
-
* console must run the statement the operator is looking at.
|
|
15
|
+
* statement a run should send, and nothing about SQL.
|
|
23
16
|
*/
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
from: number;
|
|
27
|
-
to: number;
|
|
28
|
-
}
|
|
29
|
-
export interface SqlEditorProps {
|
|
30
|
-
value: string;
|
|
31
|
-
onChange: (value: string) => void;
|
|
32
|
-
/**
|
|
33
|
-
* Render with the dark theme. Like every inkstone editor, the component never reads the OS
|
|
34
|
-
* `prefers-color-scheme`; wire this to the app's color-scheme state.
|
|
35
|
-
*
|
|
36
|
-
* @default false
|
|
37
|
-
*/
|
|
38
|
-
dark?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Editor height in px, or `"fill"` to consume the parent's resolved height (the parent must be
|
|
41
|
-
* a `min-height: 0` flex item). Monaco's loading placeholder is `height: 100%`, so a height
|
|
42
|
-
* that resolves to nothing collapses the field to one line while the editor loads.
|
|
43
|
-
*/
|
|
44
|
-
height?: number | "fill";
|
|
45
|
-
/**
|
|
46
|
-
* Editor font size in px. Omit to keep the inkstone default.
|
|
47
|
-
*/
|
|
48
|
-
fontSize?: number;
|
|
49
|
-
/**
|
|
50
|
-
* UI locale for Monaco's built-in chrome — page-global and locked by the first editor to
|
|
51
|
-
* mount, exactly as on `<MonacoEditor>`.
|
|
52
|
-
*/
|
|
53
|
-
locale?: "en" | "zh-cn";
|
|
54
|
-
placeholder?: string;
|
|
55
|
-
/**
|
|
56
|
-
* The editor's accessible name, set on Monaco's own input surface — several SQL editors on one
|
|
57
|
-
* page are indistinguishable to assistive tech without one.
|
|
58
|
-
*/
|
|
59
|
-
ariaLabel: string;
|
|
17
|
+
export type SqlCaret = ConsoleCaret;
|
|
18
|
+
export interface SqlEditorProps extends ConsoleEditorProps<SqlEditorHandle> {
|
|
60
19
|
/**
|
|
61
20
|
* The Monaco language id the model registers under.
|
|
62
21
|
*
|
|
63
22
|
* @default "sql"
|
|
64
23
|
*/
|
|
65
24
|
languageId?: string;
|
|
66
|
-
/**
|
|
67
|
-
* Shown while the Monaco host loads / when it fails to load — passed through to
|
|
68
|
-
* `<MonacoEditor>`, whose English defaults apply when omitted.
|
|
69
|
-
*/
|
|
70
|
-
loading?: ReactNode;
|
|
71
|
-
failure?: ReactNode;
|
|
72
|
-
/**
|
|
73
|
-
* Ctrl/Cmd-Enter — the run key, bound inside the editor because that is where the operator's
|
|
74
|
-
* hands are. It is handed the editor's live caret, from which the host works out what to send.
|
|
75
|
-
* Read through a ref at every press, so it always runs against the connection the *current*
|
|
76
|
-
* render is bound to.
|
|
77
|
-
*/
|
|
78
|
-
onRun?: (caret: SqlCaret) => void;
|
|
79
25
|
/**
|
|
80
26
|
* The label the run action shows in Monaco's own chrome (command palette, context menu).
|
|
81
27
|
*
|
|
82
28
|
* @default "Run statement"
|
|
83
29
|
*/
|
|
84
30
|
runActionLabel?: string;
|
|
85
|
-
/**
|
|
86
|
-
* The caret moved, or the text under it changed. The host tracks it to show what a run would
|
|
87
|
-
* send; the run key does not depend on that tracking having caught up.
|
|
88
|
-
*/
|
|
89
|
-
onCaret?: (caret: SqlCaret) => void;
|
|
90
31
|
/**
|
|
91
32
|
* The span to mark as the one a run would send. Null leaves the gutter clean, which is the
|
|
92
33
|
* right answer while there is nothing to choose between.
|
|
@@ -108,35 +49,19 @@ export interface SqlEditorProps {
|
|
|
108
49
|
* says so — a deliberate keystroke that changes nothing needs to explain itself.
|
|
109
50
|
*/
|
|
110
51
|
onFormatRefused?: () => void;
|
|
111
|
-
onReady?: (handle: SqlEditorHandle) => void;
|
|
112
|
-
/**
|
|
113
|
-
* Runs after this component's own mount wiring, with the live editor and the monaco module —
|
|
114
|
-
* the escape hatch for host-specific concerns (focus shields, extra actions).
|
|
115
|
-
*/
|
|
116
|
-
onMount?: (instance: editor.IStandaloneCodeEditor, monaco: MonacoModule) => void;
|
|
117
|
-
/**
|
|
118
|
-
* Extra construction options, merged under this editor's own (`ariaLabel`): the escape hatch
|
|
119
|
-
* a host reaches for a construction option no prop names — `overflowWidgetsDomNode`, where
|
|
120
|
-
* the page's own layers would otherwise stand over the editor's floating widgets (hover,
|
|
121
|
-
* completion, parameter hints) left inside it.
|
|
122
|
-
*/
|
|
123
|
-
options?: editor.IStandaloneEditorConstructionOptions;
|
|
124
52
|
/**
|
|
125
53
|
* What the editor's language features answer from — the schema and dialect of the connection
|
|
126
|
-
* being edited (`createSqlAssist`). Read
|
|
127
|
-
*
|
|
54
|
+
* being edited (`createSqlAssist`). Read at every request, so the host can swap it without
|
|
55
|
+
* re-registering anything with Monaco.
|
|
128
56
|
*/
|
|
129
57
|
assist?: SqlAssist;
|
|
130
58
|
}
|
|
131
59
|
/**
|
|
132
|
-
* The SQL editing surface:
|
|
133
|
-
* other inkstone surface uses. It is deliberately not a script editor — a
|
|
134
|
-
* service and an ambient profile have no meaning for a vendor's SQL. Its
|
|
135
|
-
* the host's: the `assist` knows the catalog and the dialect and this
|
|
136
|
-
* Monaco (`registerSqlLanguage`) — it never guesses at SQL itself.
|
|
137
|
-
*
|
|
138
|
-
* The editor draws no chrome of its own: it is a band of its host's surface, and the separation
|
|
139
|
-
* is the host's hairline rules — a border here would dress a pane up as a form input.
|
|
60
|
+
* The SQL editing surface: `<MonacoConsoleEditor>` in `sql`, highlighted by the same shared Shiki
|
|
61
|
+
* grammar every other inkstone surface uses. It is deliberately not a script editor — a
|
|
62
|
+
* TypeScript language service and an ambient profile have no meaning for a vendor's SQL. Its
|
|
63
|
+
* language features are the host's: the `assist` knows the catalog and the dialect and this
|
|
64
|
+
* component only wires it to Monaco (`registerSqlLanguage`) — it never guesses at SQL itself.
|
|
140
65
|
*/
|
|
141
|
-
export declare function SqlEditor({
|
|
66
|
+
export declare function SqlEditor({ languageId, runActionLabel, assist, onFormatRefused, onReady, options, ...props }: SqlEditorProps): ReactNode;
|
|
142
67
|
//#endregion
|
package/dist/react.js
CHANGED
|
@@ -1,135 +1,46 @@
|
|
|
1
1
|
import { t as registerSqlLanguage } from "./monaco-DEMsSuzD.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { MonacoConsoleEditor } from "@coldsmirk/inkstone-react/monaco";
|
|
3
|
+
import { useMemo, useRef } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/react.tsx
|
|
6
|
-
const EDITOR_ID_KEY = Symbol.for("coldsmirk.inkstone.sql.editorId");
|
|
7
|
-
function nextEditorId() {
|
|
8
|
-
const holder = globalThis;
|
|
9
|
-
const id = holder[EDITOR_ID_KEY] ?? 0;
|
|
10
|
-
holder[EDITOR_ID_KEY] = id + 1;
|
|
11
|
-
return id;
|
|
12
|
-
}
|
|
13
6
|
const FORMAT_CHORD_CONTEXT_KEY = "inkstoneSqlFormatChord";
|
|
14
|
-
function
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const caretChangedRef = useLatest(onCaret);
|
|
52
|
-
const readyRef = useLatest(onReady);
|
|
53
|
-
const mountRef = useLatest(onMount);
|
|
54
|
-
const instance = useRef(null);
|
|
55
|
-
const marked = useRef(null);
|
|
56
|
-
const [mounted, setMounted] = useState(false);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
const model = instance.current?.getModel();
|
|
59
|
-
if (model === null || model === void 0) return;
|
|
60
|
-
marked.current?.clear();
|
|
61
|
-
marked.current = highlight === null ? null : instance.current.createDecorationsCollection([{
|
|
62
|
-
range: monacoRange(model, highlight),
|
|
63
|
-
options: {
|
|
64
|
-
linesDecorationsClassName: highlightClassName,
|
|
65
|
-
isWholeLine: true
|
|
66
|
-
}
|
|
67
|
-
}]);
|
|
68
|
-
}, [
|
|
69
|
-
highlight,
|
|
70
|
-
highlightClassName,
|
|
71
|
-
mounted
|
|
72
|
-
]);
|
|
73
|
-
useEffect(() => () => {
|
|
74
|
-
for (const binding of bindings.current) binding.dispose();
|
|
75
|
-
bindings.current = [];
|
|
76
|
-
}, []);
|
|
77
|
-
const fill = height === "fill";
|
|
78
|
-
return /* @__PURE__ */ jsx("div", {
|
|
79
|
-
style: fill ? {
|
|
80
|
-
height: "100%",
|
|
81
|
-
minHeight: 0
|
|
82
|
-
} : { height },
|
|
83
|
-
children: /* @__PURE__ */ jsx(MonacoEditor, {
|
|
84
|
-
showLineNumbers: true,
|
|
85
|
-
dark,
|
|
86
|
-
failure,
|
|
87
|
-
fontSize,
|
|
88
|
-
height: fill ? "100%" : height,
|
|
89
|
-
language: languageId,
|
|
90
|
-
loading,
|
|
91
|
-
locale,
|
|
92
|
-
path: modelPath,
|
|
93
|
-
placeholder,
|
|
94
|
-
value,
|
|
95
|
-
options: {
|
|
96
|
-
...options,
|
|
97
|
-
ariaLabel,
|
|
98
|
-
suggest: { snippetsPreventQuickSuggestions: false }
|
|
99
|
-
},
|
|
100
|
-
onChange,
|
|
101
|
-
onMount: (live, monaco) => {
|
|
102
|
-
instance.current = live;
|
|
103
|
-
live.createContextKey(FORMAT_CHORD_CONTEXT_KEY, true);
|
|
104
|
-
bindings.current.push(live.onDidChangeCursorSelection(() => caretChangedRef.current?.(caretOf(live))), live.addAction({
|
|
105
|
-
id: "inkstone-sql.run",
|
|
106
|
-
label: runActionLabel,
|
|
107
|
-
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
|
|
108
|
-
run: (current) => runRef.current?.(caretOf(current))
|
|
109
|
-
}), monaco.editor.addKeybindingRule({
|
|
110
|
-
keybinding: monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF,
|
|
111
|
-
command: "editor.action.formatDocument",
|
|
112
|
-
when: `${FORMAT_CHORD_CONTEXT_KEY} && editorTextFocus && !editorReadonly`
|
|
113
|
-
}), ...registerSqlLanguage(monaco, modelPath, {
|
|
114
|
-
assist: () => assistRef.current,
|
|
115
|
-
onFormatRefused: () => formatRefusedRef.current?.()
|
|
116
|
-
}, languageId));
|
|
117
|
-
readyRef.current?.({
|
|
118
|
-
format: () => void live.getAction("editor.action.formatDocument")?.run(),
|
|
119
|
-
insert: (text) => {
|
|
120
|
-
const selection = live.getSelection();
|
|
121
|
-
if (selection) live.executeEdits("inkstone-sql-insert", [{
|
|
122
|
-
range: selection,
|
|
123
|
-
text,
|
|
124
|
-
forceMoveMarkers: true
|
|
125
|
-
}]);
|
|
126
|
-
live.focus();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
mountRef.current?.(live, monaco);
|
|
130
|
-
setMounted(true);
|
|
131
|
-
}
|
|
132
|
-
})
|
|
7
|
+
function SqlEditor({ languageId = "sql", runActionLabel = "Run statement", assist, onFormatRefused, onReady, options, ...props }) {
|
|
8
|
+
const live = useRef(null);
|
|
9
|
+
const sqlOptions = useMemo(() => {
|
|
10
|
+
return {
|
|
11
|
+
...options,
|
|
12
|
+
suggest: { snippetsPreventQuickSuggestions: false }
|
|
13
|
+
};
|
|
14
|
+
}, [options]);
|
|
15
|
+
return /* @__PURE__ */ jsx(MonacoConsoleEditor, {
|
|
16
|
+
...props,
|
|
17
|
+
context: {
|
|
18
|
+
assist,
|
|
19
|
+
onFormatRefused
|
|
20
|
+
},
|
|
21
|
+
extension: "sql",
|
|
22
|
+
language: languageId,
|
|
23
|
+
namespace: "inkstone-sql",
|
|
24
|
+
options: sqlOptions,
|
|
25
|
+
runActionLabel,
|
|
26
|
+
register: ({ monaco, editor: instance, path, context }) => {
|
|
27
|
+
live.current = instance;
|
|
28
|
+
instance.createContextKey(FORMAT_CHORD_CONTEXT_KEY, true);
|
|
29
|
+
return [monaco.editor.addKeybindingRule({
|
|
30
|
+
keybinding: monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF,
|
|
31
|
+
command: "editor.action.formatDocument",
|
|
32
|
+
when: `${FORMAT_CHORD_CONTEXT_KEY} && editorTextFocus && !editorReadonly`
|
|
33
|
+
}), ...registerSqlLanguage(monaco, path, {
|
|
34
|
+
assist: () => context().assist ?? null,
|
|
35
|
+
onFormatRefused: () => context().onFormatRefused?.()
|
|
36
|
+
}, languageId)];
|
|
37
|
+
},
|
|
38
|
+
onReady: (handle) => {
|
|
39
|
+
onReady?.({
|
|
40
|
+
...handle,
|
|
41
|
+
format: () => void live.current?.getAction("editor.action.formatDocument")?.run()
|
|
42
|
+
});
|
|
43
|
+
}
|
|
133
44
|
});
|
|
134
45
|
}
|
|
135
46
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldsmirk/inkstone-sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.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",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"monaco-editor": "^0.57.0",
|
|
50
50
|
"react": "^19.3.0",
|
|
51
|
-
"@coldsmirk/inkstone-react": "^0.
|
|
51
|
+
"@coldsmirk/inkstone-react": "^0.33.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"monaco-editor": "^0.57.0",
|
|
55
55
|
"react": ">=19",
|
|
56
|
-
"@coldsmirk/inkstone-react": "^0.
|
|
56
|
+
"@coldsmirk/inkstone-react": "^0.33.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"@coldsmirk/inkstone-react": {
|