dolphindb 3.0.32 → 3.0.33

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.
Files changed (6) hide show
  1. package/docs.d.ts +45 -0
  2. package/docs.en.json +24967 -100442
  3. package/docs.js +191 -0
  4. package/docs.js.map +1 -0
  5. package/docs.zh.json +24830 -104392
  6. package/package.json +5 -5
package/docs.js ADDED
@@ -0,0 +1,191 @@
1
+ import { fread_json } from 'xshell';
2
+ import { constants, keywords } from './language.js';
3
+ function is_completion_match(target, search) {
4
+ let j = 0;
5
+ for (const c of search) {
6
+ j = target.indexOf(c, j) + 1;
7
+ if (!j)
8
+ return false;
9
+ }
10
+ return true;
11
+ }
12
+ export class DocsAnalyser {
13
+ /** 文档原始信息 */
14
+ docs;
15
+ /** 函数名列表 */
16
+ funcs = [];
17
+ /** 转化成小写字母的函数名列表 */
18
+ lower_funcs = [];
19
+ update_docs(docs) {
20
+ this.docs = docs;
21
+ this.funcs = Object.keys(docs);
22
+ this.lower_funcs = this.funcs.map(func => func.toLowerCase());
23
+ }
24
+ async load_docs_async(provider) {
25
+ let docs;
26
+ if (typeof provider === 'function')
27
+ docs = await provider();
28
+ else if (typeof provider === 'string')
29
+ docs = await fread_json(provider);
30
+ else
31
+ throw new Error('Invalid docs provider');
32
+ this.update_docs(docs);
33
+ }
34
+ get_function_markdown(name) {
35
+ return this.docs[name]?.markdown;
36
+ }
37
+ get_signatures(name) {
38
+ return this.docs[name]?.signatures;
39
+ }
40
+ /** 查询补全项(包括关键字、常量和函数)
41
+ @param query
42
+ @returns */
43
+ search_completion_items(query) {
44
+ const query_lower = query.toLowerCase();
45
+ return {
46
+ keywords: keywords.filter(keyword => keyword.startsWith(query)),
47
+ constants: constants.filter(constant => is_completion_match(constant, query_lower)),
48
+ functions: this.funcs.filter((func, i) => is_completion_match(this.lower_funcs[i], query_lower)),
49
+ };
50
+ }
51
+ }
52
+ const FUNC_NAME_CHAR_REG_EXP = /[a-zA-Z0-9!_]/;
53
+ function reverse_search_func(text) {
54
+ let depth = 0;
55
+ let param_start_at = -1;
56
+ for (let i = text.length; i >= 0; i--) {
57
+ const char = text[i];
58
+ // 遇到右括号,入栈
59
+ if (char === ')') {
60
+ depth++;
61
+ continue;
62
+ }
63
+ // 遇到左括号,出栈
64
+ else if (char === '(') {
65
+ depth--;
66
+ continue;
67
+ }
68
+ // 栈深度小于0,且遇到合法函数名字符,跳出括号语境,搜索结束:参数搜索开始位置
69
+ if (FUNC_NAME_CHAR_REG_EXP.test(char) && depth < 0) {
70
+ param_start_at = i;
71
+ break;
72
+ }
73
+ }
74
+ // 找不到参数搜索开始位置,返回null
75
+ if (param_start_at === -1)
76
+ return null;
77
+ // 往前找函数名
78
+ let func_name_end = -1;
79
+ let func_name_start = 0;
80
+ for (let i = param_start_at; i >= 0; i--) {
81
+ const char = text[i];
82
+ // 空字符跳过
83
+ if (func_name_end === -1 && char === ' ')
84
+ continue;
85
+ // 合法函数名字字符,继续往前找
86
+ if (FUNC_NAME_CHAR_REG_EXP.test(char)) {
87
+ // 标记函数名字末尾位置
88
+ if (func_name_end === -1)
89
+ func_name_end = i;
90
+ continue;
91
+ }
92
+ // 不合法函数名字符,标记函数名字开头位置
93
+ func_name_start = i + 1;
94
+ break;
95
+ }
96
+ // 找不到函数名
97
+ if (func_name_end === -1)
98
+ return null;
99
+ return {
100
+ param_start_at: param_start_at + 1,
101
+ func_name: text.slice(func_name_start, func_name_end + 1),
102
+ };
103
+ }
104
+ // 栈 token 匹配表
105
+ const PAIR_TOKEN_MAP = {
106
+ ')': '(',
107
+ '}': '{',
108
+ ']': '[',
109
+ };
110
+ const PAIR_START_TOKENS = new Set(Object.values(PAIR_TOKEN_MAP));
111
+ const LAST_IDENTIFIER_NAME_REGEXP = /[a-zA-Z_\u4e00-\u9fa5][\w\u4e00-\u9fa5]*!?$/;
112
+ /** 根据函数参数开始位置分析参数语义,提取出当前参数索引 */
113
+ function find_active_param_index(text, param_start_at) {
114
+ let index = 0;
115
+ const stack = [];
116
+ let commas_count = 0;
117
+ // 是否在转义符作用范围内
118
+ let is_escaping_string = false;
119
+ // 搜索
120
+ for (let i = param_start_at; i < text.length; i++) {
121
+ const char = text[i];
122
+ // 空字符跳过
123
+ if (/\s/.test(char))
124
+ continue;
125
+ // 转义符作用范围下一个字符直接忽略
126
+ if (is_escaping_string) {
127
+ is_escaping_string = false;
128
+ continue;
129
+ }
130
+ const last_stack = stack[stack.length - 1];
131
+ // 字符串内除引号全部忽略
132
+ if (last_stack === '"' || last_stack === "'") {
133
+ // 进入转义符作用范围
134
+ if (char === '\\') {
135
+ is_escaping_string = true;
136
+ continue;
137
+ }
138
+ // 遇到相同引号
139
+ if (char === last_stack)
140
+ stack.pop();
141
+ continue;
142
+ }
143
+ // 开括号入栈
144
+ if (PAIR_START_TOKENS.has(char) || char === '"' || char === "'") {
145
+ stack.push(char);
146
+ continue;
147
+ }
148
+ else if (char in PAIR_TOKEN_MAP)
149
+ if (last_stack === PAIR_TOKEN_MAP[char]) {
150
+ // 括号匹配,出栈
151
+ stack.pop();
152
+ continue;
153
+ }
154
+ else
155
+ return -1;
156
+ // 栈深度为1 且为左小括号:当前语境
157
+ if (stack.length === 1 && stack[0] === '(' && char === ',')
158
+ commas_count++;
159
+ // 根据逗号数量判断高亮参数索引值
160
+ index = commas_count;
161
+ }
162
+ const caller = text.slice(0, param_start_at);
163
+ /** 匹配当前函数名的正则, 并捕获该函数名 */
164
+ const match = LAST_IDENTIFIER_NAME_REGEXP.exec(caller);
165
+ const is_member_call = match && caller[param_start_at - 1 /* 去掉括号 */ - match[0].length] === '.';
166
+ // 是否为对象方法调用,若是,参数索引+1(对象会变成第一个参数)
167
+ return is_member_call ? index + 1 : index;
168
+ }
169
+ export function parse_signature_help_from_text(text, docsAnalyser) {
170
+ const caller = reverse_search_func(text);
171
+ if (!caller)
172
+ return;
173
+ const { func_name, param_start_at } = caller;
174
+ const cursor_param_index = find_active_param_index(text, param_start_at);
175
+ if (cursor_param_index === -1)
176
+ return;
177
+ const signatures = docsAnalyser.get_signatures(func_name);
178
+ if (!signatures)
179
+ return;
180
+ const signature = signatures[0];
181
+ const params_length = signature.parameters.length;
182
+ // 如果输入参数数量超出了签名内声明的参数数量,active_parameter 为 undefined
183
+ const active_parameter = cursor_param_index > params_length - 1 ? undefined : cursor_param_index;
184
+ const documentation_md = docsAnalyser.get_function_markdown(func_name);
185
+ return {
186
+ signature,
187
+ active_parameter,
188
+ documentation_md,
189
+ };
190
+ }
191
+ //# sourceMappingURL=docs.js.map
package/docs.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["docs.ts"],"names":[],"mappings":"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","sourcesContent":["import { fread_json } from 'xshell'\n\nimport { constants, keywords } from './language.js'\n\n\nexport interface FunctionSignature {\n full: string\n name: string\n parameters: {\n full: string\n name: string\n optional?: boolean\n default?: string\n }[]\n}\n\nexport interface FunctionItem {\n /** 文档的公网链接 */\n href: string\n /** 部分函数存在多个签名,例如 append! 和 x.append!, eachPre 和 func:P 这两组,最好在分析阶段就处理好 */\n signatures: FunctionSignature[] | null\n /** 文档内容 */\n markdown: string\n}\n\ntype Docs = Record<string, FunctionItem>\n\nfunction is_completion_match (target: string, search: string) {\n let j = 0\n for (const c of search) {\n j = target.indexOf(c, j) + 1\n if (!j)\n return false\n }\n \n return true\n}\n\nexport class DocsAnalyser {\n /** 文档原始信息 */\n docs?: Docs\n \n /** 函数名列表 */\n funcs: string[] = [ ]\n \n /** 转化成小写字母的函数名列表 */\n lower_funcs: string[] = [ ]\n \n \n update_docs (docs: Docs) {\n this.docs = docs\n this.funcs = Object.keys(docs)\n this.lower_funcs = this.funcs.map(func => func.toLowerCase())\n }\n \n \n async load_docs_async (provider: string | (() => Promise<Docs>)) {\n let docs: Docs\n if (typeof provider === 'function')\n docs = await provider()\n else if (typeof provider === 'string')\n docs = await fread_json(provider)\n else\n throw new Error('Invalid docs provider')\n \n this.update_docs(docs)\n }\n \n \n get_function_markdown (name: string) {\n return this.docs[name]?.markdown\n }\n \n \n get_signatures (name: string) {\n return this.docs[name]?.signatures\n }\n \n \n /** 查询补全项(包括关键字、常量和函数)\n @param query\n @returns */\n search_completion_items (query: string) {\n const query_lower = query.toLowerCase()\n \n return {\n keywords: keywords.filter(keyword => keyword.startsWith(query)),\n constants: constants.filter(constant => is_completion_match(constant, query_lower)),\n functions: this.funcs.filter((func, i) => is_completion_match(this.lower_funcs[i], query_lower)),\n }\n }\n}\n\n\nconst FUNC_NAME_CHAR_REG_EXP = /[a-zA-Z0-9!_]/\n\nfunction reverse_search_func (text: string): null | {\n param_start_at: number\n func_name: string\n} {\n let depth = 0\n let param_start_at = -1\n \n for (let i = text.length; i >= 0; i--) {\n const char = text[i]\n \n // 遇到右括号,入栈\n if (char === ')') {\n depth++\n continue\n }\n // 遇到左括号,出栈\n else if (char === '(') {\n depth--\n continue\n }\n \n // 栈深度小于0,且遇到合法函数名字符,跳出括号语境,搜索结束:参数搜索开始位置\n if (FUNC_NAME_CHAR_REG_EXP.test(char) && depth < 0) {\n param_start_at = i\n break\n }\n }\n \n // 找不到参数搜索开始位置,返回null\n if (param_start_at === -1)\n return null\n \n \n // 往前找函数名\n let func_name_end = -1\n let func_name_start = 0\n for (let i = param_start_at; i >= 0; i--) {\n const char = text[i]\n \n // 空字符跳过\n if (func_name_end === -1 && char === ' ')\n continue\n \n // 合法函数名字字符,继续往前找\n if (FUNC_NAME_CHAR_REG_EXP.test(char)) {\n // 标记函数名字末尾位置\n if (func_name_end === -1)\n func_name_end = i\n \n continue\n }\n \n // 不合法函数名字符,标记函数名字开头位置\n func_name_start = i + 1\n break\n }\n \n // 找不到函数名\n if (func_name_end === -1)\n return null\n \n \n return {\n param_start_at: param_start_at + 1,\n func_name: text.slice(func_name_start, func_name_end + 1),\n }\n}\n\n\n// 栈 token 匹配表\nconst PAIR_TOKEN_MAP: Record<string, string> = {\n ')': '(',\n '}': '{',\n ']': '[',\n}\n\nconst PAIR_START_TOKENS = new Set(Object.values(PAIR_TOKEN_MAP))\n\nconst LAST_IDENTIFIER_NAME_REGEXP = /[a-zA-Z_\\u4e00-\\u9fa5][\\w\\u4e00-\\u9fa5]*!?$/\n\n\n/** 根据函数参数开始位置分析参数语义,提取出当前参数索引 */\nfunction find_active_param_index (text: string, param_start_at: number) {\n let index = 0\n const stack = [ ]\n \n let commas_count = 0\n \n // 是否在转义符作用范围内\n let is_escaping_string = false\n \n // 搜索\n for (let i = param_start_at; i < text.length; i++) {\n const char = text[i]\n \n // 空字符跳过\n if (/\\s/.test(char))\n continue\n \n // 转义符作用范围下一个字符直接忽略\n if (is_escaping_string) {\n is_escaping_string = false\n continue\n }\n \n const last_stack = stack[stack.length - 1]\n // 字符串内除引号全部忽略\n if (last_stack === '\"' || last_stack === \"'\") {\n // 进入转义符作用范围\n if (char === '\\\\') {\n is_escaping_string = true\n continue\n }\n \n // 遇到相同引号\n if (char === last_stack)\n stack.pop()\n \n \n continue\n }\n \n // 开括号入栈\n if (PAIR_START_TOKENS.has(char) || char === '\"' || char === \"'\") {\n stack.push(char)\n continue\n } else if (char in PAIR_TOKEN_MAP)\n if (last_stack === PAIR_TOKEN_MAP[char]) {\n // 括号匹配,出栈\n stack.pop()\n continue\n } else\n return -1\n \n \n \n // 栈深度为1 且为左小括号:当前语境\n if (stack.length === 1 && stack[0] === '(' && char === ',')\n commas_count++\n \n \n // 根据逗号数量判断高亮参数索引值\n index = commas_count\n }\n \n const caller = text.slice(0, param_start_at)\n /** 匹配当前函数名的正则, 并捕获该函数名 */\n const match = LAST_IDENTIFIER_NAME_REGEXP.exec(caller)\n \n const is_member_call = match && caller[param_start_at - 1 /* 去掉括号 */ - match[0].length] === '.'\n \n // 是否为对象方法调用,若是,参数索引+1(对象会变成第一个参数)\n return is_member_call ? index + 1 : index\n}\n\n\nexport function parse_signature_help_from_text (text: string, docsAnalyser: DocsAnalyser) {\n const caller = reverse_search_func(text)\n if (!caller)\n return\n const { func_name, param_start_at } = caller\n \n const cursor_param_index = find_active_param_index(text, param_start_at)\n if (cursor_param_index === -1)\n return\n const signatures = docsAnalyser.get_signatures(func_name)\n if (!signatures)\n return\n const signature = signatures[0]\n const params_length = signature.parameters.length\n // 如果输入参数数量超出了签名内声明的参数数量,active_parameter 为 undefined\n const active_parameter = cursor_param_index > params_length - 1 ? undefined : cursor_param_index\n const documentation_md = docsAnalyser.get_function_markdown(func_name)\n \n return {\n signature,\n active_parameter,\n documentation_md,\n }\n}\n\n"]}