a-calc 3.0.0-beta.20260130.1 → 3.0.0-beta.20260201.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a-calc",
3
- "version": "3.0.0-beta.20260130.1",
3
+ "version": "3.0.0-beta.20260201.1",
4
4
  "description": "A very powerful and easy-to-use number precision calculation and formatting library.",
5
5
  "main": "./cjs/index.js",
6
6
  "exports": {
@@ -19,7 +19,8 @@
19
19
  "require": "./cjs/index.js",
20
20
  "default": "./cjs/index.js"
21
21
  },
22
- "./mcp-server/src/index.js": "./mcp-server/src/index.js"
22
+ "./mcp-server/src/index.js": "./mcp-server/src/index.js",
23
+ "./ts-plugin": "./ts-plugin/dist/index.js"
23
24
  },
24
25
  "browser": "browser/index.js",
25
26
  "module": "es/index.js",
@@ -51,7 +52,8 @@
51
52
  "a-calc.versions.js",
52
53
  "mcp-server/src",
53
54
  "mcp-server/package.json",
54
- "mcp-server/README.md"
55
+ "mcp-server/README.md",
56
+ "ts-plugin/dist"
55
57
  ],
56
58
  "repository": {
57
59
  "type": "git",
@@ -101,6 +103,7 @@
101
103
  "@rollup/plugin-json": "^6.0.1",
102
104
  "@rollup/plugin-node-resolve": "^15.2.3",
103
105
  "@rollup/plugin-terser": "^0.4.4",
106
+ "@uiw/codemirror-themes-all": "^4.25.4",
104
107
  "@vitest/coverage-v8": "^2.1.9",
105
108
  "a-calc": "^2.2.15",
106
109
  "benchmark": "^2.1.4",
@@ -122,11 +125,10 @@
122
125
  "typescript": "^5.1.6",
123
126
  "vitepress": "^1.6.4",
124
127
  "vitest": "^2.1.0",
125
- "vue": "^3.5.25",
126
- "@uiw/codemirror-themes-all": "^4.25.4"
128
+ "vue": "^3.5.25"
127
129
  },
128
130
  "dependencies": {
129
- "typescript-treasure": "0.0.9",
130
- "@modelcontextprotocol/sdk": "^1.0.0"
131
+ "@modelcontextprotocol/sdk": "^1.0.0",
132
+ "typescript-treasure": "0.0.9"
131
133
  }
132
134
  }
@@ -0,0 +1,9 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
+ /**
3
+ * 从项目中提取 set_config 配置的类型信息
4
+ */
5
+ export declare function extract_config_from_project(ts_module: typeof ts, program: ts.Program, logger: ts.server.Logger): ExtractedConfig;
6
+ export interface ExtractedConfig {
7
+ units: string[];
8
+ shortcut_prefix: string;
9
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extract_config_from_project = void 0;
4
+ /**
5
+ * 从项目中提取 set_config 配置的类型信息
6
+ */
7
+ function extract_config_from_project(ts_module, program, logger) {
8
+ const result = {
9
+ units: [],
10
+ shortcut_prefix: '!u',
11
+ };
12
+ const type_checker = program.getTypeChecker();
13
+ for (const source_file of program.getSourceFiles()) {
14
+ // 跳过 node_modules
15
+ if (source_file.fileName.includes('node_modules'))
16
+ continue;
17
+ visit_node(ts_module, source_file, type_checker, result, logger);
18
+ }
19
+ return result;
20
+ }
21
+ exports.extract_config_from_project = extract_config_from_project;
22
+ function visit_node(ts_module, node, type_checker, result, logger) {
23
+ // 查找 set_config 调用
24
+ if (ts_module.isCallExpression(node)) {
25
+ const func_name = get_call_name(ts_module, node);
26
+ if (func_name === 'set_config' && node.arguments.length > 0) {
27
+ const arg = node.arguments[0];
28
+ extract_from_config_arg(ts_module, arg, type_checker, result, logger);
29
+ }
30
+ }
31
+ ts_module.forEachChild(node, child => {
32
+ visit_node(ts_module, child, type_checker, result, logger);
33
+ });
34
+ }
35
+ function get_call_name(ts_module, node) {
36
+ if (ts_module.isIdentifier(node.expression)) {
37
+ return node.expression.text;
38
+ }
39
+ return undefined;
40
+ }
41
+ function extract_from_config_arg(ts_module, arg, type_checker, result, logger) {
42
+ const type = type_checker.getTypeAtLocation(arg);
43
+ const properties = type.getProperties();
44
+ for (const prop of properties) {
45
+ const prop_name = prop.getName();
46
+ if (prop_name === '_unit_convert_out') {
47
+ extract_units_from_convert_out(ts_module, prop, type_checker, result, logger);
48
+ }
49
+ else if (prop_name === '_unit_convert_in') {
50
+ extract_units_from_convert_in(ts_module, prop, type_checker, result, logger);
51
+ }
52
+ else if (prop_name === '_shortcut_prefix') {
53
+ extract_shortcut_prefix(ts_module, prop, type_checker, result, logger);
54
+ }
55
+ }
56
+ }
57
+ function extract_units_from_convert_out(ts_module, prop, type_checker, result, logger) {
58
+ const prop_type = type_checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
59
+ // 获取 _unit_convert_out 对象的所有 key
60
+ const unit_props = prop_type.getProperties();
61
+ for (const unit_prop of unit_props) {
62
+ const unit_name = unit_prop.getName();
63
+ if (!result.units.includes(unit_name)) {
64
+ result.units.push(unit_name);
65
+ }
66
+ }
67
+ logger.info(`a-calc-ts-plugin: extracted units from _unit_convert_out = ${result.units.join(', ')}`);
68
+ }
69
+ function extract_units_from_convert_in(ts_module, prop, type_checker, result, logger) {
70
+ const prop_type = type_checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
71
+ // _unit_convert_in 结构: { 输入单位: { 输出单位: 转换规则 } }
72
+ // 需要提取输出单位(内层的 key)
73
+ const input_unit_props = prop_type.getProperties();
74
+ for (const input_prop of input_unit_props) {
75
+ const input_type = type_checker.getTypeOfSymbolAtLocation(input_prop, input_prop.valueDeclaration);
76
+ // 获取内层的输出单位
77
+ const output_props = input_type.getProperties();
78
+ for (const output_prop of output_props) {
79
+ const unit_name = output_prop.getName();
80
+ if (!result.units.includes(unit_name)) {
81
+ result.units.push(unit_name);
82
+ }
83
+ }
84
+ }
85
+ logger.info(`a-calc-ts-plugin: extracted units from _unit_convert_in = ${result.units.join(', ')}`);
86
+ }
87
+ function extract_shortcut_prefix(ts_module, prop, type_checker, result, logger) {
88
+ const prop_type = type_checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
89
+ // 尝试获取字符串字面量类型的值
90
+ if (prop_type.isStringLiteral()) {
91
+ result.shortcut_prefix = prop_type.value;
92
+ logger.info(`a-calc-ts-plugin: shortcut_prefix (literal) = ${result.shortcut_prefix}`);
93
+ return;
94
+ }
95
+ // 尝试从声明中直接获取值
96
+ const decl = prop.valueDeclaration;
97
+ if (decl && ts_module.isPropertyAssignment(decl)) {
98
+ const init = decl.initializer;
99
+ if (ts_module.isStringLiteral(init)) {
100
+ result.shortcut_prefix = init.text;
101
+ logger.info(`a-calc-ts-plugin: shortcut_prefix (init) = ${result.shortcut_prefix}`);
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * a-calc ! 系统预设
3
+ */
4
+ export declare const ACALC_PRESETS: {
5
+ name: string;
6
+ description: string;
7
+ has_value: boolean;
8
+ value_required: boolean;
9
+ example: string;
10
+ }[];
11
+ /**
12
+ * 千分位预设值
13
+ */
14
+ export declare const THOUSANDS_PRESETS: {
15
+ name: string;
16
+ description: string;
17
+ }[];
18
+ /**
19
+ * 紧凑格式预设值
20
+ */
21
+ export declare const COMPACT_PRESETS: {
22
+ name: string;
23
+ description: string;
24
+ }[];
25
+ /**
26
+ * 格式化语法列表(用于 | 后的补全)
27
+ * insert_text: 实际插入的文本(不含占位符)
28
+ */
29
+ export declare const FORMAT_SYNTAX: {
30
+ name: string;
31
+ insert_text: string;
32
+ description: string;
33
+ example: string;
34
+ }[];
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FORMAT_SYNTAX = exports.COMPACT_PRESETS = exports.THOUSANDS_PRESETS = exports.ACALC_PRESETS = void 0;
4
+ /**
5
+ * a-calc ! 系统预设
6
+ */
7
+ exports.ACALC_PRESETS = [
8
+ {
9
+ name: 't',
10
+ description: '千分位预设',
11
+ has_value: true,
12
+ value_required: false,
13
+ example: '!t 或 !t:indian'
14
+ },
15
+ {
16
+ name: 'c',
17
+ description: '紧凑格式',
18
+ has_value: true,
19
+ value_required: false,
20
+ example: '!c 或 !c:cn'
21
+ },
22
+ {
23
+ name: 'i',
24
+ description: '整数补零',
25
+ has_value: true,
26
+ value_required: true,
27
+ example: '!i:3'
28
+ },
29
+ {
30
+ name: 'g',
31
+ description: '格式化分组',
32
+ has_value: true,
33
+ value_required: true,
34
+ example: '!g:money'
35
+ },
36
+ {
37
+ name: 'u',
38
+ description: '单位(默认位置)',
39
+ has_value: true,
40
+ value_required: true,
41
+ example: '!u:元'
42
+ },
43
+ {
44
+ name: 'ua',
45
+ description: '单位在数字后',
46
+ has_value: true,
47
+ value_required: true,
48
+ example: '!ua:元'
49
+ },
50
+ {
51
+ name: 'ub',
52
+ description: '单位在数字前',
53
+ has_value: true,
54
+ value_required: true,
55
+ example: '!ub:$'
56
+ },
57
+ {
58
+ name: 'um',
59
+ description: '单位在符号后',
60
+ has_value: true,
61
+ value_required: true,
62
+ example: '!um:元'
63
+ },
64
+ {
65
+ name: 'uh',
66
+ description: '转换但隐藏单位',
67
+ has_value: true,
68
+ value_required: false,
69
+ example: '!uh 或 !uh:元'
70
+ },
71
+ ];
72
+ /**
73
+ * 千分位预设值
74
+ */
75
+ exports.THOUSANDS_PRESETS = [
76
+ { name: 'en', description: '英文/国际 (1,234,567)' },
77
+ { name: 'eu', description: '欧洲 (1.234.567)' },
78
+ { name: 'swiss', description: "瑞士 (1'234'567)" },
79
+ { name: 'space', description: '空格分隔 (1 234 567)' },
80
+ { name: 'fr', description: '法国 (1 234 567,89)' },
81
+ { name: 'indian', description: '印度 (12,34,567)' },
82
+ { name: 'wan', description: '万进制 (1234,5678)' },
83
+ ];
84
+ /**
85
+ * 紧凑格式预设值
86
+ */
87
+ exports.COMPACT_PRESETS = [
88
+ { name: 'en', description: '英文 (K/M/B/T)' },
89
+ { name: 'cn', description: '中文千进制 (千/百万/十亿)' },
90
+ { name: 'wan', description: '万进制 (万/亿)' },
91
+ { name: 'storage', description: '存储单位 (KB/MB/GB)' },
92
+ { name: 'indian', description: '印度 (K/L/Cr)' },
93
+ ];
94
+ /**
95
+ * 格式化语法列表(用于 | 后的补全)
96
+ * insert_text: 实际插入的文本(不含占位符)
97
+ */
98
+ exports.FORMAT_SYNTAX = [
99
+ // 小数位控制
100
+ {
101
+ name: '=N',
102
+ insert_text: '=',
103
+ description: '精确 N 位小数',
104
+ example: '=2 → 1.50',
105
+ },
106
+ {
107
+ name: '<=N',
108
+ insert_text: '<=',
109
+ description: '最多 N 位小数(不补零)',
110
+ example: '<=2 → 1.5',
111
+ },
112
+ {
113
+ name: '>=N',
114
+ insert_text: '>=',
115
+ description: '最少 N 位小数(补零)',
116
+ example: '>=3 → 1.500',
117
+ },
118
+ {
119
+ name: '>=N<=M',
120
+ insert_text: '>=',
121
+ description: '小数位数范围',
122
+ example: '>=2<=4 → 1.5 ~ 1.5000',
123
+ },
124
+ // 舍入规则
125
+ {
126
+ name: '~5',
127
+ insert_text: '~5',
128
+ description: '四舍五入',
129
+ example: '~5=2: 1.125 → 1.13',
130
+ },
131
+ {
132
+ name: '~6',
133
+ insert_text: '~6',
134
+ description: '银行家舍入(四舍六入五取偶)',
135
+ example: '~6=2: 1.125 → 1.12',
136
+ },
137
+ {
138
+ name: '~+',
139
+ insert_text: '~+',
140
+ description: '进位(向上取整)',
141
+ example: '~+=2: 1.121 → 1.13',
142
+ },
143
+ {
144
+ name: '~-',
145
+ insert_text: '~-',
146
+ description: '截断(向下取整,默认)',
147
+ example: '~-=2: 1.129 → 1.12',
148
+ },
149
+ // 千分位
150
+ {
151
+ name: ',',
152
+ insert_text: ',',
153
+ description: '千分位分隔',
154
+ example: '1234567 → 1,234,567',
155
+ },
156
+ {
157
+ name: '!t',
158
+ insert_text: '!t',
159
+ description: '千分位(默认预设)',
160
+ example: '1234567 → 1,234,567',
161
+ },
162
+ {
163
+ name: '!t:preset',
164
+ insert_text: '!t:',
165
+ description: '千分位预设',
166
+ example: '!t:indian → 12,34,567',
167
+ },
168
+ // 紧凑格式
169
+ {
170
+ name: '!c',
171
+ insert_text: '!c',
172
+ description: '紧凑格式(默认 K/M/B/T)',
173
+ example: '1500 → 1.5K',
174
+ },
175
+ {
176
+ name: '!c:preset',
177
+ insert_text: '!c:',
178
+ description: '紧凑格式预设',
179
+ example: '!c:wan → 1万',
180
+ },
181
+ // 百分比
182
+ {
183
+ name: '%',
184
+ insert_text: '%',
185
+ description: '百分比格式',
186
+ example: '0.1234 → 12.34%',
187
+ },
188
+ // 正负号
189
+ {
190
+ name: '+',
191
+ insert_text: '+',
192
+ description: '显示正号',
193
+ example: '100 → +100',
194
+ },
195
+ // 整数补零
196
+ {
197
+ name: '!i:N',
198
+ insert_text: '!i:',
199
+ description: '整数部分补零到 N 位',
200
+ example: '!i:3: 5 → 005',
201
+ },
202
+ // 科学计数法
203
+ {
204
+ name: '!e',
205
+ insert_text: '!e',
206
+ description: '科学计数法',
207
+ example: '123456789 → 1.23e+8',
208
+ },
209
+ // 分数
210
+ {
211
+ name: '/',
212
+ insert_text: '/',
213
+ description: '分数形式',
214
+ example: '0.5 → 1/2',
215
+ },
216
+ // 返回类型
217
+ {
218
+ name: '!n',
219
+ insert_text: '!n',
220
+ description: '返回数字类型',
221
+ example: '"3" → 3 (number)',
222
+ },
223
+ {
224
+ name: '!s',
225
+ insert_text: '!s',
226
+ description: '返回字符串类型(默认)',
227
+ example: '3 → "3" (string)',
228
+ },
229
+ // 单位
230
+ {
231
+ name: '!u:unit',
232
+ insert_text: '!u:',
233
+ description: '单位(默认位置)',
234
+ example: '!u:元 → 100元',
235
+ },
236
+ {
237
+ name: '!ua:unit',
238
+ insert_text: '!ua:',
239
+ description: '单位在数字后',
240
+ example: '!ua:$ → 100$',
241
+ },
242
+ {
243
+ name: '!ub:unit',
244
+ insert_text: '!ub:',
245
+ description: '单位在数字前',
246
+ example: '!ub:$ → $100',
247
+ },
248
+ {
249
+ name: '!um:unit',
250
+ insert_text: '!um:',
251
+ description: '单位在符号后',
252
+ example: '!um:$ → +$100',
253
+ },
254
+ {
255
+ name: '!uh:unit',
256
+ insert_text: '!uh:',
257
+ description: '转换但隐藏单位',
258
+ example: '!uh:元 → 100',
259
+ },
260
+ // 范围限制
261
+ {
262
+ name: '[min,max]',
263
+ insert_text: '[',
264
+ description: '范围限制',
265
+ example: '[0,100]: 150 → 100',
266
+ },
267
+ // 格式化分组
268
+ {
269
+ name: '!g:name',
270
+ insert_text: '!g:',
271
+ description: '格式化分组',
272
+ example: '!g:money → 预设格式',
273
+ },
274
+ ];
@@ -0,0 +1,7 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
+ declare function init(modules: {
3
+ typescript: typeof ts;
4
+ }): {
5
+ create: (info: ts.server.PluginCreateInfo) => ts.LanguageService;
6
+ };
7
+ export = init;