neon 3.0.0 → 3.1.1
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 +70 -5
- package/dist/_chunks/auth_selection-DGgq6ifc.js +83 -0
- package/dist/_chunks/cmd_pipeline-CUbBO9U_.js +2818 -0
- package/dist/_chunks/credentials-MYdHdKah.js +188 -0
- package/dist/_chunks/env-NbA61JR3.js +585 -0
- package/dist/_chunks/env_services-Tz9G4JeT.js +531 -0
- package/dist/_chunks/paths-DMq0Lt7a.js +151 -0
- package/dist/_chunks/profiles-Ir29rqns.js +217 -0
- package/dist/_chunks/psql-DWH-kc69.js +2169 -0
- package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/_chunks/secure_file-BucZj4yQ.js +39 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +573 -690
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +639 -719
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +255 -305
- package/dist/commands/functions.js +275 -355
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +615 -846
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +2 -446
- package/dist/dev/functions.js +54 -68
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +2 -51
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +728 -984
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +2 -2193
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +2 -1148
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +260 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +2 -1253
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1303
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +2 -846
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +2 -2030
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +8 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +130 -189
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +39 -45
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +11 -6
- package/dist/_shared/auth_selection.js +0 -86
- package/dist/_shared/credentials.js +0 -209
- package/dist/_shared/env-core/env.js +0 -558
- package/dist/_shared/env-core/reuse-secrets.js +0 -223
- package/dist/_shared/paths.js +0 -148
- package/dist/_shared/profiles.js +0 -276
- package/dist/_shared/secure_file.js +0 -43
|
@@ -1,315 +1,251 @@
|
|
|
1
|
+
//#region src/psql/complete/matcher.ts
|
|
1
2
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
3
|
+
* Matches / TailMatches / HeadMatches DSL.
|
|
4
|
+
*
|
|
5
|
+
* TypeScript port of the pattern-matching helpers in psql's tab-complete.in.c.
|
|
6
|
+
* The C source uses a varargs macro layered on top of `word_matches()` to
|
|
7
|
+
* decide whether a sequence of "previous words" matches a pattern. We
|
|
8
|
+
* reproduce the same shape with plain functions because (a) JS has no
|
|
9
|
+
* preprocessor macros and (b) array spread is the natural varargs analogue.
|
|
10
|
+
*
|
|
11
|
+
* Matches('SELECT', MatchAny, 'FROM') — exact word-count match.
|
|
12
|
+
* TailMatches('SELECT', MatchAny, 'FROM') — match the last N words.
|
|
13
|
+
* HeadMatches('ALTER', 'TABLE') — match the first N words.
|
|
14
|
+
*
|
|
15
|
+
* Wildcards and special tokens (mirroring the upstream constants):
|
|
16
|
+
*
|
|
17
|
+
* MatchAny — any single word (`NULL` upstream).
|
|
18
|
+
* MatchAnyExcept(x) — any word that doesn't match `x` (upstream `"!x"`).
|
|
19
|
+
* '*' inside a pattern — wildcard within a single word (e.g. `'pg_*'`).
|
|
20
|
+
* '|' inside a pattern — alternation (e.g. `'TABLE|VIEW'`).
|
|
21
|
+
*
|
|
22
|
+
* Comparisons are case-insensitive by default (SQL keywords); pass
|
|
23
|
+
* `caseSensitive: true` to the DSL helpers when matching strictly.
|
|
24
|
+
*
|
|
25
|
+
* The tokenizer is exported separately because the `index.ts` entry point
|
|
26
|
+
* needs to do the same word-split-then-match dance.
|
|
27
|
+
*/
|
|
28
|
+
const MatchAny = null;
|
|
29
|
+
const MatchAnyExcept = (pattern) => "!" + pattern;
|
|
29
30
|
const cimatch = (s1, s2, n, caseSensitive) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return a === b;
|
|
36
|
-
return a.toLowerCase() === b.toLowerCase();
|
|
31
|
+
if (s1.length < n || s2.length < n) return false;
|
|
32
|
+
const a = s1.slice(0, n);
|
|
33
|
+
const b = s2.slice(0, n);
|
|
34
|
+
if (caseSensitive) return a === b;
|
|
35
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
37
36
|
};
|
|
38
37
|
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
cimatch(word.slice(wordlen - afterLen), cursor.slice(starIdx + 1), afterLen, caseSensitive)) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
if (wordlen === i &&
|
|
70
|
-
cimatch(word, cursor, wordlen, caseSensitive)) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (i >= cursor.length)
|
|
75
|
-
break;
|
|
76
|
-
cursor = cursor.slice(i + 1);
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
38
|
+
* Return true iff `word` matches `pattern`. `null`/`MatchAny` matches
|
|
39
|
+
* everything. A leading `!` inverts the match. `|` separates alternatives.
|
|
40
|
+
* `*` is a single-word wildcard.
|
|
41
|
+
*/
|
|
42
|
+
const wordMatches = (pattern, word, caseSensitive = false) => {
|
|
43
|
+
if (pattern === null) return true;
|
|
44
|
+
if (pattern.startsWith("!")) return !wordMatches(pattern.slice(1), word, caseSensitive);
|
|
45
|
+
const wordlen = word.length;
|
|
46
|
+
let cursor = pattern;
|
|
47
|
+
for (;;) {
|
|
48
|
+
let starIdx = -1;
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < cursor.length && cursor[i] !== "|") {
|
|
51
|
+
if (cursor[i] === "*") starIdx = i;
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
if (starIdx >= 0) {
|
|
55
|
+
const beforeLen = starIdx;
|
|
56
|
+
const afterLen = i - starIdx - 1;
|
|
57
|
+
if (wordlen >= beforeLen + afterLen && cimatch(word, cursor, beforeLen, caseSensitive) && cimatch(word.slice(wordlen - afterLen), cursor.slice(starIdx + 1), afterLen, caseSensitive)) return true;
|
|
58
|
+
} else if (wordlen === i && cimatch(word, cursor, wordlen, caseSensitive)) return true;
|
|
59
|
+
if (i >= cursor.length) break;
|
|
60
|
+
cursor = cursor.slice(i + 1);
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
79
63
|
};
|
|
80
64
|
/**
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (!wordMatches(patterns[k], prev[k], caseSensitive))
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
return true;
|
|
65
|
+
* Exact-length match: every word in `words` must match the corresponding
|
|
66
|
+
* pattern. `words` here is "previous words" — i.e. the words BEFORE the
|
|
67
|
+
* current (in-progress) word.
|
|
68
|
+
*
|
|
69
|
+
* The upstream uses `previous_words_count + 1 == narg` because the C array
|
|
70
|
+
* includes both prev words AND the current. Our representation only stores
|
|
71
|
+
* prev words; the caller passes the in-progress word separately.
|
|
72
|
+
*
|
|
73
|
+
* prev = ['SELECT'], pattern = ['SELECT'] → true (1 == 1)
|
|
74
|
+
* prev = ['SELECT', 'a'], pattern = ['SELECT'] → false (2 != 1)
|
|
75
|
+
*/
|
|
76
|
+
const Matches = (prev, patterns, caseSensitive = false) => {
|
|
77
|
+
if (prev.length !== patterns.length) return false;
|
|
78
|
+
for (let k = 0; k < patterns.length; k++) if (!wordMatches(patterns[k], prev[k], caseSensitive)) return false;
|
|
79
|
+
return true;
|
|
100
80
|
};
|
|
101
81
|
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (!wordMatches(patterns[k], prev[offset + k], caseSensitive))
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
return true;
|
|
82
|
+
* Tail match: the LAST N words of `prev` must match the patterns.
|
|
83
|
+
*
|
|
84
|
+
* prev = ['SELECT', 'a', 'FROM'], patterns = ['FROM'] → true
|
|
85
|
+
* prev = ['SELECT'], patterns = ['SELECT', 'FROM'] → false (too few)
|
|
86
|
+
*/
|
|
87
|
+
const TailMatches = (prev, patterns, caseSensitive = false) => {
|
|
88
|
+
if (prev.length < patterns.length) return false;
|
|
89
|
+
const offset = prev.length - patterns.length;
|
|
90
|
+
for (let k = 0; k < patterns.length; k++) if (!wordMatches(patterns[k], prev[offset + k], caseSensitive)) return false;
|
|
91
|
+
return true;
|
|
116
92
|
};
|
|
117
93
|
/**
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (!wordMatches(patterns[k], prev[k], caseSensitive))
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
return true;
|
|
94
|
+
* Head match: the FIRST N words of `prev` must match.
|
|
95
|
+
*
|
|
96
|
+
* prev = ['ALTER', 'TABLE', 'foo'], patterns = ['ALTER', 'TABLE'] → true
|
|
97
|
+
*/
|
|
98
|
+
const HeadMatches = (prev, patterns, caseSensitive = false) => {
|
|
99
|
+
if (prev.length < patterns.length) return false;
|
|
100
|
+
for (let k = 0; k < patterns.length; k++) if (!wordMatches(patterns[k], prev[k], caseSensitive)) return false;
|
|
101
|
+
return true;
|
|
130
102
|
};
|
|
131
103
|
/**
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
i++;
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
// Bareword: letters, digits, underscore, `.` (schema qualifier), `:` (var
|
|
246
|
-
// expansion marker is kept inside the word), `$` (positional param).
|
|
247
|
-
const start = i;
|
|
248
|
-
while (i < input.length) {
|
|
249
|
-
const c = input[i];
|
|
250
|
-
if (c === " " ||
|
|
251
|
-
c === "\t" ||
|
|
252
|
-
c === "\n" ||
|
|
253
|
-
c === "\r" ||
|
|
254
|
-
c === "," ||
|
|
255
|
-
c === ";" ||
|
|
256
|
-
c === "(" ||
|
|
257
|
-
c === ")" ||
|
|
258
|
-
c === "[" ||
|
|
259
|
-
c === "]" ||
|
|
260
|
-
c === '"' ||
|
|
261
|
-
c === "'" ||
|
|
262
|
-
c === "\\") {
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
265
|
-
i++;
|
|
266
|
-
}
|
|
267
|
-
out.push({
|
|
268
|
-
text: input.slice(start, i),
|
|
269
|
-
raw: input.slice(start, i),
|
|
270
|
-
start,
|
|
271
|
-
end: i,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
return out;
|
|
104
|
+
* Split `input` into psql-style words for completion purposes.
|
|
105
|
+
*
|
|
106
|
+
* - Whitespace is the basic separator.
|
|
107
|
+
* - "..." treated as ONE word (quoted identifier).
|
|
108
|
+
* - '...' treated as ONE word (string literal).
|
|
109
|
+
* - \backslash... treated as ONE word (the backslash command).
|
|
110
|
+
* - Punctuation (commas, parens, semicolons) is broken into its own word.
|
|
111
|
+
* - Embedded `.` (schema-qualifier) keeps the dotted name as a single word
|
|
112
|
+
* so completion sees `pg_catalog.pg_class` whole.
|
|
113
|
+
*
|
|
114
|
+
* The tokenizer is intentionally pragmatic — it doesn't validate SQL, it
|
|
115
|
+
* just slices well enough for the rule body to inspect previous words.
|
|
116
|
+
*/
|
|
117
|
+
const tokenize = (input) => {
|
|
118
|
+
const out = [];
|
|
119
|
+
let i = 0;
|
|
120
|
+
while (i < input.length) {
|
|
121
|
+
const ch = input[i];
|
|
122
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
123
|
+
i++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (ch === "\\") {
|
|
127
|
+
const start = i;
|
|
128
|
+
i++;
|
|
129
|
+
if (i < input.length && /[!?]/.test(input[i])) i++;
|
|
130
|
+
else {
|
|
131
|
+
while (i < input.length && /[A-Za-z_]/.test(input[i])) i++;
|
|
132
|
+
while (i < input.length && input[i] === "+") i++;
|
|
133
|
+
}
|
|
134
|
+
out.push({
|
|
135
|
+
text: input.slice(start, i),
|
|
136
|
+
raw: input.slice(start, i),
|
|
137
|
+
start,
|
|
138
|
+
end: i
|
|
139
|
+
});
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (ch === "\"") {
|
|
143
|
+
const start = i;
|
|
144
|
+
i++;
|
|
145
|
+
while (i < input.length) {
|
|
146
|
+
if (input[i] === "\"") {
|
|
147
|
+
if (input[i + 1] === "\"") {
|
|
148
|
+
i += 2;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
i++;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
i++;
|
|
155
|
+
}
|
|
156
|
+
out.push({
|
|
157
|
+
text: input.slice(start, i),
|
|
158
|
+
raw: input.slice(start, i),
|
|
159
|
+
start,
|
|
160
|
+
end: i
|
|
161
|
+
});
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (ch === "'") {
|
|
165
|
+
const start = i;
|
|
166
|
+
i++;
|
|
167
|
+
while (i < input.length) {
|
|
168
|
+
if (input[i] === "\\" && i + 1 < input.length) {
|
|
169
|
+
i += 2;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (input[i] === "'") {
|
|
173
|
+
if (input[i + 1] === "'") {
|
|
174
|
+
i += 2;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
i++;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
i++;
|
|
181
|
+
}
|
|
182
|
+
out.push({
|
|
183
|
+
text: input.slice(start, i),
|
|
184
|
+
raw: input.slice(start, i),
|
|
185
|
+
start,
|
|
186
|
+
end: i
|
|
187
|
+
});
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (ch === "," || ch === ";" || ch === "(" || ch === ")" || ch === "[" || ch === "]") {
|
|
191
|
+
out.push({
|
|
192
|
+
text: ch,
|
|
193
|
+
raw: ch,
|
|
194
|
+
start: i,
|
|
195
|
+
end: i + 1
|
|
196
|
+
});
|
|
197
|
+
i++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const start = i;
|
|
201
|
+
while (i < input.length) {
|
|
202
|
+
const c = input[i];
|
|
203
|
+
if (c === " " || c === " " || c === "\n" || c === "\r" || c === "," || c === ";" || c === "(" || c === ")" || c === "[" || c === "]" || c === "\"" || c === "'" || c === "\\") break;
|
|
204
|
+
i++;
|
|
205
|
+
}
|
|
206
|
+
out.push({
|
|
207
|
+
text: input.slice(start, i),
|
|
208
|
+
raw: input.slice(start, i),
|
|
209
|
+
start,
|
|
210
|
+
end: i
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
275
214
|
};
|
|
276
215
|
/**
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
prevWords: tokens.map((t) => t.text),
|
|
312
|
-
currentWord: "",
|
|
313
|
-
replaceLength: 0,
|
|
314
|
-
};
|
|
216
|
+
* Slice `input` at `cursor`, then determine what's being completed:
|
|
217
|
+
*
|
|
218
|
+
* - `prevWords`: the completed words ENTIRELY before the cursor.
|
|
219
|
+
* - `currentWord`: the partial word the cursor is sitting in (may be '').
|
|
220
|
+
* - `replaceLength`: number of code points to chop off the input before
|
|
221
|
+
* inserting the completion (= length of currentWord in code points).
|
|
222
|
+
*
|
|
223
|
+
* The tokenizer is run on `input.slice(0, cursor)` and the LAST token, if
|
|
224
|
+
* it ends exactly at cursor and didn't start with whitespace/punctuation,
|
|
225
|
+
* becomes the current word. Otherwise the current word is empty (the user
|
|
226
|
+
* just typed a space and is starting a new word).
|
|
227
|
+
*/
|
|
228
|
+
const splitForCompletion = (input, cursor) => {
|
|
229
|
+
const head = input.slice(0, cursor);
|
|
230
|
+
const tokens = tokenize(head);
|
|
231
|
+
if (tokens.length === 0) return {
|
|
232
|
+
prevWords: [],
|
|
233
|
+
currentWord: "",
|
|
234
|
+
replaceLength: 0
|
|
235
|
+
};
|
|
236
|
+
const last = tokens[tokens.length - 1];
|
|
237
|
+
const charBefore = head[head.length - 1];
|
|
238
|
+
const inWhitespace = charBefore === " " || charBefore === " " || charBefore === "\n" || charBefore === "\r";
|
|
239
|
+
if (last.end === head.length && !inWhitespace) return {
|
|
240
|
+
prevWords: tokens.slice(0, -1).map((t) => t.text),
|
|
241
|
+
currentWord: last.text,
|
|
242
|
+
replaceLength: Array.from(last.text).length
|
|
243
|
+
};
|
|
244
|
+
return {
|
|
245
|
+
prevWords: tokens.map((t) => t.text),
|
|
246
|
+
currentWord: "",
|
|
247
|
+
replaceLength: 0
|
|
248
|
+
};
|
|
315
249
|
};
|
|
250
|
+
//#endregion
|
|
251
|
+
export { HeadMatches, MatchAny, MatchAnyExcept, Matches, TailMatches, splitForCompletion, tokenize, wordMatches };
|