@maptec/cli 1.0.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/LICENSE +21 -0
- package/README.md +284 -0
- package/bin/maptec.js +2 -0
- package/dist/chunk-K574OFFK.js +122 -0
- package/dist/chunk-K574OFFK.js.map +1 -0
- package/dist/cli.js +899 -0
- package/dist/cli.js.map +1 -0
- package/dist/store-ZU7HLXCV.js +18 -0
- package/dist/store-ZU7HLXCV.js.map +1 -0
- package/package.json +47 -0
- package/skills/README.md +30 -0
- package/skills/jsapi-skills/README.md +60 -0
- package/skills/jsapi-skills/SKILL.md +145 -0
- package/skills/jsapi-skills/package.json +31 -0
- package/skills/jsapi-skills/references/controls.md +195 -0
- package/skills/jsapi-skills/references/events.md +222 -0
- package/skills/jsapi-skills/references/geocoding.md +184 -0
- package/skills/jsapi-skills/references/map-style.md +123 -0
- package/skills/jsapi-skills/references/map.md +154 -0
- package/skills/jsapi-skills/references/marker.md +136 -0
- package/skills/jsapi-skills/references/operate.md +138 -0
- package/skills/jsapi-skills/references/overlay.md +311 -0
- package/skills/jsapi-skills/references/place-search.md +411 -0
- package/skills/jsapi-skills/references/poi-categories.md +123 -0
- package/skills/jsapi-skills/references/popup.md +146 -0
- package/skills/jsapi-skills/references/re-geocoding.md +183 -0
- package/skills/jsapi-skills/references/routing.md +347 -0
- package/skills/jsapi-skills/references/track.md +240 -0
- package/skills/jsapi-skills/scripts/validate_jsapi_skill.py +160 -0
- package/skills/webapi-skills/README.md +73 -0
- package/skills/webapi-skills/SKILL.md +63 -0
- package/skills/webapi-skills/package.json +32 -0
- package/skills/webapi-skills/references/direction-api.md +175 -0
- package/skills/webapi-skills/references/geocoding.md +195 -0
- package/skills/webapi-skills/references/ip-location.md +87 -0
- package/skills/webapi-skills/references/matrix-api.md +149 -0
- package/skills/webapi-skills/references/nearby-search.md +223 -0
- package/skills/webapi-skills/references/places.md +239 -0
- package/skills/webapi-skills/references/quick-start-cn.md +219 -0
- package/skills/webapi-skills/references/reverse-geocoding.md +157 -0
- package/skills/webapi-skills/references/suggest.md +111 -0
- package/skills/webapi-skills/references/text-search.md +282 -0
- package/skills/webapi-skills/scripts/validate_webapi_skill.py +158 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,899 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
API_VERSION,
|
|
4
|
+
getConfigPath,
|
|
5
|
+
loadConfig,
|
|
6
|
+
maskApiKey,
|
|
7
|
+
normalizeBaseUrl,
|
|
8
|
+
resolveApiKey,
|
|
9
|
+
resolveBaseUrl,
|
|
10
|
+
saveConfig,
|
|
11
|
+
setApiKey,
|
|
12
|
+
setBaseUrl,
|
|
13
|
+
setConfigValue
|
|
14
|
+
} from "./chunk-K574OFFK.js";
|
|
15
|
+
|
|
16
|
+
// src/cli.ts
|
|
17
|
+
import { Command } from "commander";
|
|
18
|
+
import { readFileSync } from "fs";
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
import { dirname, join } from "path";
|
|
21
|
+
|
|
22
|
+
// src/errors.ts
|
|
23
|
+
var ExitCode = {
|
|
24
|
+
USER_ERROR: 1,
|
|
25
|
+
CONFIG_MISSING: 2,
|
|
26
|
+
API_ERROR: 3,
|
|
27
|
+
NETWORK_ERROR: 4,
|
|
28
|
+
INTERNAL_ERROR: 5
|
|
29
|
+
};
|
|
30
|
+
var CliError = class extends Error {
|
|
31
|
+
constructor(message, exitCode, hint) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.exitCode = exitCode;
|
|
34
|
+
this.hint = hint;
|
|
35
|
+
this.name = "CliError";
|
|
36
|
+
}
|
|
37
|
+
exitCode;
|
|
38
|
+
hint;
|
|
39
|
+
};
|
|
40
|
+
function printError(err) {
|
|
41
|
+
if (err instanceof CliError) {
|
|
42
|
+
console.error(`error: ${err.message}`);
|
|
43
|
+
if (err.hint) {
|
|
44
|
+
console.error(`hint: ${err.hint}`);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (err instanceof Error) {
|
|
49
|
+
console.error(`error: ${err.message}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
console.error("error: \u672A\u77E5\u9519\u8BEF");
|
|
53
|
+
}
|
|
54
|
+
function exitWithError(err) {
|
|
55
|
+
printError(err);
|
|
56
|
+
const code = err instanceof CliError ? err.exitCode : ExitCode.INTERNAL_ERROR;
|
|
57
|
+
process.exit(code);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/commands/init.ts
|
|
61
|
+
import * as readline from "readline/promises";
|
|
62
|
+
import { stdin as input, stdout as output } from "process";
|
|
63
|
+
|
|
64
|
+
// src/output/json.ts
|
|
65
|
+
import { writeFile } from "fs/promises";
|
|
66
|
+
|
|
67
|
+
// src/output/fields.ts
|
|
68
|
+
function pickFields(data, fields) {
|
|
69
|
+
if (data === null || data === void 0) return data;
|
|
70
|
+
if (Array.isArray(data)) {
|
|
71
|
+
return data.map((item) => pickFields(item, fields));
|
|
72
|
+
}
|
|
73
|
+
if (typeof data !== "object") return data;
|
|
74
|
+
const fieldSet = new Set(fields.map((f) => f.trim()).filter(Boolean));
|
|
75
|
+
if (fieldSet.size === 0) return data;
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const key of fieldSet) {
|
|
78
|
+
if (key in data) {
|
|
79
|
+
out[key] = data[key];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/output/json.ts
|
|
86
|
+
async function emitSuccess(payload, options) {
|
|
87
|
+
let data = payload.data;
|
|
88
|
+
if (options.fields?.length) {
|
|
89
|
+
data = pickFields(data, options.fields);
|
|
90
|
+
}
|
|
91
|
+
const envelope = {
|
|
92
|
+
ok: true,
|
|
93
|
+
command: payload.command,
|
|
94
|
+
data
|
|
95
|
+
};
|
|
96
|
+
if (options.format === "table") {
|
|
97
|
+
const text = formatTable(data);
|
|
98
|
+
await writeOutput(text, options);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const json = `${JSON.stringify(envelope, null, 2)}
|
|
102
|
+
`;
|
|
103
|
+
await writeOutput(json, options);
|
|
104
|
+
}
|
|
105
|
+
async function writeOutput(text, options) {
|
|
106
|
+
if (options.out) {
|
|
107
|
+
await writeFile(options.out, text, "utf8");
|
|
108
|
+
if (!options.quiet) {
|
|
109
|
+
console.error(`\u5DF2\u5199\u5165 ${options.out}`);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
process.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
114
|
+
`);
|
|
115
|
+
}
|
|
116
|
+
function formatTable(data) {
|
|
117
|
+
if (data === null || data === void 0) {
|
|
118
|
+
return "(empty)";
|
|
119
|
+
}
|
|
120
|
+
if (typeof data !== "object") {
|
|
121
|
+
return String(data);
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(data)) {
|
|
124
|
+
if (data.length === 0) return "(no results)";
|
|
125
|
+
return data.map((item, i) => `[${i}] ${JSON.stringify(item)}`).join("\n");
|
|
126
|
+
}
|
|
127
|
+
return Object.entries(data).map(([k, v]) => `${k}: ${typeof v === "object" ? JSON.stringify(v) : String(v)}`).join("\n");
|
|
128
|
+
}
|
|
129
|
+
function handleApiBusinessStatus(result, command) {
|
|
130
|
+
if (result.status === "ERROR" && result.error) {
|
|
131
|
+
const err = result.error;
|
|
132
|
+
throw new CliError(
|
|
133
|
+
`${err.code} \u2014 ${err.message}`,
|
|
134
|
+
ExitCode.API_ERROR,
|
|
135
|
+
`\u68C0\u67E5\u547D\u4EE4\u53C2\u6570\uFF0C\u5F53\u524D\u547D\u4EE4\uFF1A${command}`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/commands/init.ts
|
|
142
|
+
async function runInit(outputOpts) {
|
|
143
|
+
const rl = readline.createInterface({ input, output });
|
|
144
|
+
try {
|
|
145
|
+
const existing = await loadConfig();
|
|
146
|
+
const apiKeyPrompt = existing.apiKey ? `API Key [\u5F53\u524D ${maskApiKey(existing.apiKey)}\uFF0C\u56DE\u8F66\u4FDD\u7559]: ` : "API Key: ";
|
|
147
|
+
const apiKeyInput = (await rl.question(apiKeyPrompt)).trim();
|
|
148
|
+
const baseUrlPrompt = existing.baseUrl ? `Base URL [\u5F53\u524D ${existing.baseUrl}\uFF0C\u56DE\u8F66\u4FDD\u7559]: ` : "Base URL (https://api.example.com): ";
|
|
149
|
+
const baseUrlInput = (await rl.question(baseUrlPrompt)).trim();
|
|
150
|
+
const config = await loadConfig();
|
|
151
|
+
if (apiKeyInput) {
|
|
152
|
+
config.apiKey = apiKeyInput;
|
|
153
|
+
}
|
|
154
|
+
if (!config.apiKey) {
|
|
155
|
+
throw new CliError(
|
|
156
|
+
"\u5FC5\u987B\u63D0\u4F9B API Key",
|
|
157
|
+
ExitCode.USER_ERROR,
|
|
158
|
+
"\u4ECE Maptec \u5F00\u653E\u5E73\u53F0\u63A7\u5236\u53F0\u83B7\u53D6\uFF0C\u6216\u8BBE\u7F6E MAPTEC_API_KEY"
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
if (baseUrlInput) {
|
|
162
|
+
try {
|
|
163
|
+
config.baseUrl = normalizeBaseUrl(baseUrlInput);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
throw new CliError(
|
|
166
|
+
err instanceof Error ? err.message : "\u65E0\u6548 Base URL",
|
|
167
|
+
ExitCode.USER_ERROR
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (!config.baseUrl) {
|
|
172
|
+
throw new CliError(
|
|
173
|
+
"\u5FC5\u987B\u63D0\u4F9B Base URL",
|
|
174
|
+
ExitCode.USER_ERROR,
|
|
175
|
+
"\u793A\u4F8B\uFF1Ahttps://api.maptec.com \uFF0C\u6216\u8BBE\u7F6E MAPTEC_BASE_URL"
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
delete config.env;
|
|
179
|
+
await saveConfig(config);
|
|
180
|
+
await emitSuccess(
|
|
181
|
+
{
|
|
182
|
+
command: "init",
|
|
183
|
+
data: {
|
|
184
|
+
apiKey: maskApiKey(config.apiKey),
|
|
185
|
+
baseUrl: config.baseUrl,
|
|
186
|
+
configPath: "~/.maptec/config.json"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
outputOpts
|
|
190
|
+
);
|
|
191
|
+
} finally {
|
|
192
|
+
rl.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/commands/config.ts
|
|
197
|
+
async function runConfigGet(outputOpts) {
|
|
198
|
+
const config = await loadConfig();
|
|
199
|
+
const apiKey = resolveApiKey(config);
|
|
200
|
+
await emitSuccess(
|
|
201
|
+
{
|
|
202
|
+
command: "config.get",
|
|
203
|
+
data: {
|
|
204
|
+
apiKey: apiKey ? maskApiKey(apiKey) : null,
|
|
205
|
+
baseUrl: resolveBaseUrl(config) ?? null,
|
|
206
|
+
defaultFormat: config.defaultFormat,
|
|
207
|
+
timeoutMs: config.timeoutMs,
|
|
208
|
+
configPath: getConfigPath()
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
outputOpts
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
async function runConfigSet(key, value, outputOpts) {
|
|
215
|
+
let config;
|
|
216
|
+
switch (key) {
|
|
217
|
+
case "api-key":
|
|
218
|
+
case "apiKey":
|
|
219
|
+
config = await setApiKey(value);
|
|
220
|
+
break;
|
|
221
|
+
case "base-url":
|
|
222
|
+
case "baseUrl":
|
|
223
|
+
try {
|
|
224
|
+
config = await setBaseUrl(value);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
throw new CliError(
|
|
227
|
+
err instanceof Error ? err.message : "\u65E0\u6548 baseUrl",
|
|
228
|
+
ExitCode.USER_ERROR
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
case "default-format":
|
|
233
|
+
case "defaultFormat":
|
|
234
|
+
config = await setConfigValue("defaultFormat", value);
|
|
235
|
+
break;
|
|
236
|
+
case "timeout":
|
|
237
|
+
case "timeoutMs":
|
|
238
|
+
config = await setConfigValue("timeoutMs", Number(value));
|
|
239
|
+
break;
|
|
240
|
+
default:
|
|
241
|
+
throw new CliError(
|
|
242
|
+
`\u672A\u77E5\u914D\u7F6E\u9879 "${key}"`,
|
|
243
|
+
ExitCode.USER_ERROR,
|
|
244
|
+
"\u53EF\u9009\uFF1Aapi-key | base-url | default-format | timeout"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
await emitSuccess(
|
|
248
|
+
{
|
|
249
|
+
command: "config.set",
|
|
250
|
+
data: {
|
|
251
|
+
key,
|
|
252
|
+
baseUrl: config.baseUrl ?? null,
|
|
253
|
+
apiKey: config.apiKey ? maskApiKey(config.apiKey) : null
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
outputOpts
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/api/client.ts
|
|
261
|
+
function buildQueryString(query) {
|
|
262
|
+
const parts = Object.entries(query).filter(([, v]) => v !== void 0 && v !== "").map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`);
|
|
263
|
+
return parts.length ? `?${parts.join("&")}` : "";
|
|
264
|
+
}
|
|
265
|
+
function getAuthorizationValue(apiKey) {
|
|
266
|
+
return apiKey.trim();
|
|
267
|
+
}
|
|
268
|
+
async function apiRequest(config, options) {
|
|
269
|
+
const apiKey = resolveApiKey(config);
|
|
270
|
+
if (!apiKey) {
|
|
271
|
+
throw new CliError(
|
|
272
|
+
"\u672A\u914D\u7F6E API Key",
|
|
273
|
+
ExitCode.CONFIG_MISSING,
|
|
274
|
+
"\u8FD0\u884C maptec init \u6216\u8BBE\u7F6E MAPTEC_API_KEY \u73AF\u5883\u53D8\u91CF"
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
const baseUrl = resolveBaseUrl(config);
|
|
278
|
+
if (!baseUrl) {
|
|
279
|
+
throw new CliError(
|
|
280
|
+
"\u672A\u914D\u7F6E Base URL",
|
|
281
|
+
ExitCode.CONFIG_MISSING,
|
|
282
|
+
"\u8FD0\u884C maptec init \u6216\u8BBE\u7F6E MAPTEC_BASE_URL \u73AF\u5883\u53D8\u91CF"
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
const timeoutMs = options.timeoutMs ?? config.timeoutMs;
|
|
286
|
+
const queryString = options.query ? buildQueryString(options.query) : "";
|
|
287
|
+
const url = `${baseUrl}${options.path}${queryString}`;
|
|
288
|
+
const headers = {
|
|
289
|
+
Authorization: getAuthorizationValue(apiKey)
|
|
290
|
+
};
|
|
291
|
+
const method = options.method ?? "GET";
|
|
292
|
+
const init = {
|
|
293
|
+
method,
|
|
294
|
+
headers,
|
|
295
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
296
|
+
};
|
|
297
|
+
if (options.body !== void 0) {
|
|
298
|
+
headers["Content-Type"] = "application/json";
|
|
299
|
+
init.body = JSON.stringify(options.body);
|
|
300
|
+
}
|
|
301
|
+
let response;
|
|
302
|
+
try {
|
|
303
|
+
response = await fetch(url, init);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
const message = err instanceof Error && err.name === "TimeoutError" ? `\u8BF7\u6C42\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09` : err instanceof Error ? err.message : "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25";
|
|
306
|
+
throw new CliError(message, ExitCode.NETWORK_ERROR);
|
|
307
|
+
}
|
|
308
|
+
let data;
|
|
309
|
+
try {
|
|
310
|
+
data = await response.json();
|
|
311
|
+
} catch {
|
|
312
|
+
throw new CliError(
|
|
313
|
+
`\u65E0\u6CD5\u89E3\u6790 API \u54CD\u5E94\uFF08HTTP ${response.status}\uFF09`,
|
|
314
|
+
response.ok ? ExitCode.INTERNAL_ERROR : ExitCode.API_ERROR
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
if (!response.ok) {
|
|
318
|
+
const code = data.error?.code ?? data.code ?? `HTTP_${response.status}`;
|
|
319
|
+
const message = data.error?.message ?? data.message ?? `HTTP ${response.status}`;
|
|
320
|
+
throw new CliError(message, ExitCode.API_ERROR, code);
|
|
321
|
+
}
|
|
322
|
+
return data;
|
|
323
|
+
}
|
|
324
|
+
function searchPath(segment) {
|
|
325
|
+
return `/search/${API_VERSION}/${segment}`;
|
|
326
|
+
}
|
|
327
|
+
function routesPath(segment) {
|
|
328
|
+
return `/routes/${API_VERSION}/${segment}`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/api/geocode.ts
|
|
332
|
+
async function forwardGeocode(config, params) {
|
|
333
|
+
const query = {
|
|
334
|
+
address: params.address,
|
|
335
|
+
language: params.language,
|
|
336
|
+
region: params.region,
|
|
337
|
+
components: params.components,
|
|
338
|
+
locationBias: params.locationBias
|
|
339
|
+
};
|
|
340
|
+
const data = await apiRequest(config, {
|
|
341
|
+
path: searchPath("geocode"),
|
|
342
|
+
query
|
|
343
|
+
});
|
|
344
|
+
if (!Array.isArray(data.results)) {
|
|
345
|
+
data.results = [];
|
|
346
|
+
}
|
|
347
|
+
if (data.status === "ERROR" && data.error) {
|
|
348
|
+
return data;
|
|
349
|
+
}
|
|
350
|
+
return data;
|
|
351
|
+
}
|
|
352
|
+
async function reverseGeocode(config, params) {
|
|
353
|
+
const query = {
|
|
354
|
+
location: `${params.lat},${params.lng}`,
|
|
355
|
+
language: params.language,
|
|
356
|
+
region: params.region,
|
|
357
|
+
resultType: params.resultType,
|
|
358
|
+
locationType: params.locationType
|
|
359
|
+
};
|
|
360
|
+
const data = await apiRequest(config, {
|
|
361
|
+
path: searchPath("reverse"),
|
|
362
|
+
query
|
|
363
|
+
});
|
|
364
|
+
if (!Array.isArray(data.results)) {
|
|
365
|
+
data.results = [];
|
|
366
|
+
}
|
|
367
|
+
return data;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/commands/geocode.ts
|
|
371
|
+
async function runGeocode(opts, outputOpts) {
|
|
372
|
+
if (!opts.address?.trim()) {
|
|
373
|
+
throw new CliError(
|
|
374
|
+
"\u7F3A\u5C11 --address \u53C2\u6570",
|
|
375
|
+
ExitCode.USER_ERROR,
|
|
376
|
+
'\u793A\u4F8B\uFF1Amaptec geocode --address "\u5317\u4EAC\u5E02\u671D\u9633\u533A\u56FD\u8D38"'
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
const config = await loadConfig();
|
|
380
|
+
const result = await forwardGeocode(config, {
|
|
381
|
+
address: opts.address.trim(),
|
|
382
|
+
language: opts.language,
|
|
383
|
+
region: opts.region
|
|
384
|
+
});
|
|
385
|
+
if (result.status === "ZERO_RESULTS") {
|
|
386
|
+
throw new CliError(
|
|
387
|
+
"ZERO_RESULTS \u2014 \u672A\u627E\u5230\u5339\u914D\u5730\u5740",
|
|
388
|
+
ExitCode.API_ERROR,
|
|
389
|
+
"\u68C0\u67E5 --address \u6216\u6539\u7528 maptec search text"
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
handleApiBusinessStatus(result, "geocode");
|
|
393
|
+
await emitSuccess(
|
|
394
|
+
{ command: "geocode", data: result },
|
|
395
|
+
outputOpts
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/commands/reverse-geocode.ts
|
|
400
|
+
async function runReverseGeocode(opts, outputOpts) {
|
|
401
|
+
if (!Number.isFinite(opts.lat) || !Number.isFinite(opts.lng)) {
|
|
402
|
+
throw new CliError(
|
|
403
|
+
"\u7F3A\u5C11\u6709\u6548\u7684 --lat \u4E0E --lng",
|
|
404
|
+
ExitCode.USER_ERROR,
|
|
405
|
+
"\u793A\u4F8B\uFF1Amaptec reverse-geocode --lat 39.908 --lng 116.397"
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const config = await loadConfig();
|
|
409
|
+
const result = await reverseGeocode(config, opts);
|
|
410
|
+
if (result.status === "ZERO_RESULTS") {
|
|
411
|
+
throw new CliError(
|
|
412
|
+
"ZERO_RESULTS \u2014 \u8BE5\u5750\u6807\u65E0\u5730\u5740\u7ED3\u679C",
|
|
413
|
+
ExitCode.API_ERROR,
|
|
414
|
+
"\u68C0\u67E5\u5750\u6807\u662F\u5426\u5728\u670D\u52A1\u8303\u56F4\u5185"
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
handleApiBusinessStatus(result, "reverse-geocode");
|
|
418
|
+
await emitSuccess(
|
|
419
|
+
{ command: "reverse-geocode", data: result },
|
|
420
|
+
outputOpts
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/api/location.ts
|
|
425
|
+
function parseLngLatPair(value, defaultRadius) {
|
|
426
|
+
const parts = value.split(",").map((s) => s.trim());
|
|
427
|
+
if (parts.length < 2) {
|
|
428
|
+
throw new Error(`\u65E0\u6548\u5750\u6807 "${value}"\uFF0C\u683C\u5F0F\uFF1Alng,lat \u6216 lng,lat,radius`);
|
|
429
|
+
}
|
|
430
|
+
const lng = Number(parts[0]);
|
|
431
|
+
const lat = Number(parts[1]);
|
|
432
|
+
if (!Number.isFinite(lng) || !Number.isFinite(lat)) {
|
|
433
|
+
throw new Error(`\u65E0\u6548\u5750\u6807 "${value}"`);
|
|
434
|
+
}
|
|
435
|
+
const radius = parts[2] !== void 0 ? Number(parts[2]) : defaultRadius;
|
|
436
|
+
return {
|
|
437
|
+
center: { longitude: lng, latitude: lat },
|
|
438
|
+
radius: radius !== void 0 && Number.isFinite(radius) ? radius : void 0
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
function toLocationAreaCircle(lng, lat, radius) {
|
|
442
|
+
return {
|
|
443
|
+
center: { longitude: lng, latitude: lat },
|
|
444
|
+
radius
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function buildRouteEndpoint(point) {
|
|
448
|
+
if (point.kind === "coord") {
|
|
449
|
+
return {
|
|
450
|
+
location: {
|
|
451
|
+
latitude: point.lat,
|
|
452
|
+
longitude: point.lng
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
const text = point.value.trim();
|
|
457
|
+
if (/^[\d.+-]+,[\d.+-]+$/.test(text)) {
|
|
458
|
+
const { center } = parseLngLatPair(text);
|
|
459
|
+
return { location: center };
|
|
460
|
+
}
|
|
461
|
+
return { placeId: text };
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/api/place-search.ts
|
|
465
|
+
async function searchText(config, params) {
|
|
466
|
+
const body = {
|
|
467
|
+
query: params.query,
|
|
468
|
+
pageSize: params.pageSize ?? 20,
|
|
469
|
+
language: params.language ?? "en"
|
|
470
|
+
};
|
|
471
|
+
if (params.region) body.region = params.region;
|
|
472
|
+
if (params.type) body.type = params.type;
|
|
473
|
+
if (params.rank) body.rank = params.rank;
|
|
474
|
+
if (params.location) {
|
|
475
|
+
const { center, radius } = parseLngLatPair(params.location, 5e3);
|
|
476
|
+
body.locationBias = toLocationAreaCircle(
|
|
477
|
+
center.longitude,
|
|
478
|
+
center.latitude,
|
|
479
|
+
radius ?? 5e3
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
return apiRequest(config, {
|
|
483
|
+
method: "POST",
|
|
484
|
+
path: searchPath("text"),
|
|
485
|
+
body
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
async function searchNearby(config, params) {
|
|
489
|
+
const body = {
|
|
490
|
+
locationLimit: toLocationAreaCircle(
|
|
491
|
+
params.lng,
|
|
492
|
+
params.lat,
|
|
493
|
+
params.radius ?? 500
|
|
494
|
+
),
|
|
495
|
+
types: params.types ?? "",
|
|
496
|
+
resultLimit: params.resultLimit ?? 20,
|
|
497
|
+
rank: params.rank ?? "DISTANCE",
|
|
498
|
+
language: params.language ?? "en"
|
|
499
|
+
};
|
|
500
|
+
if (params.region) body.region = params.region;
|
|
501
|
+
return apiRequest(config, {
|
|
502
|
+
method: "POST",
|
|
503
|
+
path: searchPath("nearby"),
|
|
504
|
+
body
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
async function searchSuggest(config, params) {
|
|
508
|
+
const body = {
|
|
509
|
+
query: params.query,
|
|
510
|
+
resultLimit: params.resultLimit ?? 20,
|
|
511
|
+
language: params.language ?? "en",
|
|
512
|
+
region: params.region ?? "",
|
|
513
|
+
types: ""
|
|
514
|
+
};
|
|
515
|
+
if (params.location) {
|
|
516
|
+
const { center, radius } = parseLngLatPair(params.location, 5e3);
|
|
517
|
+
body.locationBias = toLocationAreaCircle(
|
|
518
|
+
center.longitude,
|
|
519
|
+
center.latitude,
|
|
520
|
+
radius ?? 5e3
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
return apiRequest(config, {
|
|
524
|
+
method: "POST",
|
|
525
|
+
path: searchPath("suggest"),
|
|
526
|
+
body
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
async function getPlaceDetails(config, params) {
|
|
530
|
+
const query = {
|
|
531
|
+
language: params.language ?? "en",
|
|
532
|
+
region: params.region,
|
|
533
|
+
sessionToken: params.sessionToken
|
|
534
|
+
};
|
|
535
|
+
return apiRequest(config, {
|
|
536
|
+
path: searchPath(`places/${encodeURIComponent(params.placeId)}`),
|
|
537
|
+
query
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/commands/search.ts
|
|
542
|
+
function assertOkStatus(result, command) {
|
|
543
|
+
if (result.status === "ZERO_RESULTS") {
|
|
544
|
+
throw new CliError(
|
|
545
|
+
"ZERO_RESULTS \u2014 \u672A\u627E\u5230\u5339\u914D\u7ED3\u679C",
|
|
546
|
+
ExitCode.API_ERROR,
|
|
547
|
+
`\u68C0\u67E5\u641C\u7D22\u53C2\u6570\uFF0C\u547D\u4EE4\uFF1A${command}`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
handleApiBusinessStatus(result, command);
|
|
551
|
+
}
|
|
552
|
+
async function runSearchText(opts, outputOpts) {
|
|
553
|
+
if (!opts.query?.trim()) {
|
|
554
|
+
throw new CliError("\u7F3A\u5C11 --query", ExitCode.USER_ERROR);
|
|
555
|
+
}
|
|
556
|
+
const config = await loadConfig();
|
|
557
|
+
const result = await searchText(config, opts);
|
|
558
|
+
assertOkStatus(result, "search.text");
|
|
559
|
+
await emitSuccess({ command: "search.text", data: result }, outputOpts);
|
|
560
|
+
}
|
|
561
|
+
async function runSearchNearby(opts, outputOpts) {
|
|
562
|
+
const config = await loadConfig();
|
|
563
|
+
const result = await searchNearby(config, {
|
|
564
|
+
lat: opts.lat,
|
|
565
|
+
lng: opts.lng,
|
|
566
|
+
radius: opts.radius,
|
|
567
|
+
types: opts.types,
|
|
568
|
+
resultLimit: opts.limit,
|
|
569
|
+
language: opts.language,
|
|
570
|
+
region: opts.region,
|
|
571
|
+
rank: opts.rank
|
|
572
|
+
});
|
|
573
|
+
assertOkStatus(result, "search.nearby");
|
|
574
|
+
await emitSuccess({ command: "search.nearby", data: result }, outputOpts);
|
|
575
|
+
}
|
|
576
|
+
async function runSearchSuggest(opts, outputOpts) {
|
|
577
|
+
const config = await loadConfig();
|
|
578
|
+
const result = await searchSuggest(config, {
|
|
579
|
+
query: opts.query,
|
|
580
|
+
location: opts.location,
|
|
581
|
+
language: opts.language,
|
|
582
|
+
region: opts.region,
|
|
583
|
+
resultLimit: opts.limit
|
|
584
|
+
});
|
|
585
|
+
assertOkStatus(result, "search.suggest");
|
|
586
|
+
await emitSuccess({ command: "search.suggest", data: result }, outputOpts);
|
|
587
|
+
}
|
|
588
|
+
async function runSearchPlace(opts, outputOpts) {
|
|
589
|
+
const config = await loadConfig();
|
|
590
|
+
const result = await getPlaceDetails(config, {
|
|
591
|
+
placeId: opts.id,
|
|
592
|
+
language: opts.language,
|
|
593
|
+
region: opts.region,
|
|
594
|
+
sessionToken: opts.sessionToken
|
|
595
|
+
});
|
|
596
|
+
assertOkStatus(result, "search.place");
|
|
597
|
+
await emitSuccess({ command: "search.place", data: result }, outputOpts);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/api/directions.ts
|
|
601
|
+
async function getDirectionsWithEndpoints(config, params) {
|
|
602
|
+
const body = {
|
|
603
|
+
origin: params.origin,
|
|
604
|
+
destination: params.destination,
|
|
605
|
+
mode: params.mode
|
|
606
|
+
};
|
|
607
|
+
if (params.strategy) body.strategy = params.strategy;
|
|
608
|
+
if (params.language) body.language = params.language;
|
|
609
|
+
if (params.vehicleSpec) body.vehicleSpec = params.vehicleSpec;
|
|
610
|
+
return apiRequest(config, {
|
|
611
|
+
method: "POST",
|
|
612
|
+
path: routesPath("directions"),
|
|
613
|
+
body
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/api/route-resolve.ts
|
|
618
|
+
async function resolveRouteEndpoint(config, point) {
|
|
619
|
+
if (point.kind === "coord") {
|
|
620
|
+
return buildRouteEndpoint(point);
|
|
621
|
+
}
|
|
622
|
+
const text = point.value.trim();
|
|
623
|
+
if (/^[\d.+-]+,[\d.+-]+$/.test(text)) {
|
|
624
|
+
return buildRouteEndpoint(point);
|
|
625
|
+
}
|
|
626
|
+
if (text.startsWith("places/") || text.includes("_v0.") || /^[\d]+$/.test(text)) {
|
|
627
|
+
return buildRouteEndpoint(point);
|
|
628
|
+
}
|
|
629
|
+
const geocoded = await forwardGeocode(config, { address: text });
|
|
630
|
+
const first = geocoded.results?.[0];
|
|
631
|
+
if (geocoded.status !== "OK" || !first?.geometry?.location) {
|
|
632
|
+
throw new Error(
|
|
633
|
+
`\u65E0\u6CD5 geocode \u5730\u5740 "${text}"\uFF08${geocoded.status}\uFF09`
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
const { latitude, longitude } = first.geometry.location;
|
|
637
|
+
return buildRouteEndpoint({ kind: "coord", lat: latitude, lng: longitude });
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// src/output/route-fields.ts
|
|
641
|
+
var DEFAULT_ROUTE_FIELDS = ["distance", "duration", "summary"];
|
|
642
|
+
function shapeRouteOutput(data, fields) {
|
|
643
|
+
if (!data.routes?.length) return data;
|
|
644
|
+
const wanted = fields?.length ? fields : DEFAULT_ROUTE_FIELDS;
|
|
645
|
+
const includePolyline = wanted.includes("polyline");
|
|
646
|
+
const routes = data.routes.map(
|
|
647
|
+
(route) => projectRoute(route, wanted, includePolyline)
|
|
648
|
+
);
|
|
649
|
+
return { ...data, routes };
|
|
650
|
+
}
|
|
651
|
+
function projectRoute(route, fields, includePolyline) {
|
|
652
|
+
const out = {};
|
|
653
|
+
if (fields.includes("summary") || fields.includes("distance") || fields.includes("duration")) {
|
|
654
|
+
const summary = {};
|
|
655
|
+
if (fields.includes("distance")) {
|
|
656
|
+
summary.distanceMeters = route.summary.distanceMeters;
|
|
657
|
+
}
|
|
658
|
+
if (fields.includes("duration")) {
|
|
659
|
+
summary.durationSeconds = route.summary.durationSeconds;
|
|
660
|
+
}
|
|
661
|
+
if (fields.includes("summary")) {
|
|
662
|
+
summary.trafficDurationSeconds = route.summary.trafficDurationSeconds;
|
|
663
|
+
}
|
|
664
|
+
out.summary = summary;
|
|
665
|
+
}
|
|
666
|
+
if (fields.includes("warnings") && route.warnings) {
|
|
667
|
+
out.warnings = route.warnings;
|
|
668
|
+
}
|
|
669
|
+
if (includePolyline) {
|
|
670
|
+
const polyline = route.overviewPolyline;
|
|
671
|
+
if (polyline) out.polyline = polyline;
|
|
672
|
+
if (route.path) out.path = route.path;
|
|
673
|
+
}
|
|
674
|
+
if (fields.includes("legs") && route.legs) {
|
|
675
|
+
out.legs = route.legs;
|
|
676
|
+
}
|
|
677
|
+
return out;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// src/commands/route.ts
|
|
681
|
+
function resolveEndpoint(text, lat, lng, label) {
|
|
682
|
+
if (lat !== void 0 && lng !== void 0 && Number.isFinite(lat) && Number.isFinite(lng)) {
|
|
683
|
+
return { kind: "coord", lat, lng };
|
|
684
|
+
}
|
|
685
|
+
if (text?.trim()) {
|
|
686
|
+
return { kind: "text", value: text.trim() };
|
|
687
|
+
}
|
|
688
|
+
throw new CliError(
|
|
689
|
+
`\u7F3A\u5C11\u8D77\u70B9/\u7EC8\u70B9 ${label}`,
|
|
690
|
+
ExitCode.USER_ERROR,
|
|
691
|
+
`\u4F7F\u7528 --${label} \u6216 --${label}-lat + --${label}-lng`
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
async function runRoute(opts, outputOpts) {
|
|
695
|
+
const origin = resolveEndpoint(opts.from, opts.fromLat, opts.fromLng, "from");
|
|
696
|
+
const destination = resolveEndpoint(opts.to, opts.toLat, opts.toLng, "to");
|
|
697
|
+
const config = await loadConfig();
|
|
698
|
+
const [originParam, destinationParam] = await Promise.all([
|
|
699
|
+
resolveRouteEndpoint(config, origin),
|
|
700
|
+
resolveRouteEndpoint(config, destination)
|
|
701
|
+
]);
|
|
702
|
+
const result = await getDirectionsWithEndpoints(config, {
|
|
703
|
+
mode: opts.mode,
|
|
704
|
+
origin: originParam,
|
|
705
|
+
destination: destinationParam,
|
|
706
|
+
strategy: opts.strategy,
|
|
707
|
+
language: opts.language,
|
|
708
|
+
vehicleSpec: opts.mode === "truck" ? {
|
|
709
|
+
heightMeters: opts.height,
|
|
710
|
+
weightTons: opts.weight,
|
|
711
|
+
lengthMeters: opts.length
|
|
712
|
+
} : void 0
|
|
713
|
+
});
|
|
714
|
+
if (result.status === "NO_ROUTE_FOUND") {
|
|
715
|
+
throw new CliError(
|
|
716
|
+
"NO_ROUTE_FOUND \u2014 \u65E0\u6CD5\u89C4\u5212\u8DEF\u7EBF",
|
|
717
|
+
ExitCode.API_ERROR,
|
|
718
|
+
"\u68C0\u67E5\u8D77\u7EC8\u70B9\u6216\u6539\u7528 maptec geocode \u786E\u8BA4\u5750\u6807"
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
handleApiBusinessStatus(result, `route.${opts.mode}`);
|
|
722
|
+
const fields = outputOpts.fields ?? opts.fields;
|
|
723
|
+
const shaped = shapeRouteOutput(result, fields);
|
|
724
|
+
await emitSuccess(
|
|
725
|
+
{ command: `route.${opts.mode}`, data: shaped },
|
|
726
|
+
{ ...outputOpts, fields: void 0 }
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// src/cli.ts
|
|
731
|
+
function getVersion() {
|
|
732
|
+
try {
|
|
733
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
734
|
+
const pkgPath = join(dir, "..", "package.json");
|
|
735
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
736
|
+
return pkg.version;
|
|
737
|
+
} catch {
|
|
738
|
+
return "0.0.0";
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function parseFields(value) {
|
|
742
|
+
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
743
|
+
}
|
|
744
|
+
function buildOutputOptions(globalOpts) {
|
|
745
|
+
const format = globalOpts.format ?? "json";
|
|
746
|
+
if (format !== "json" && format !== "table") {
|
|
747
|
+
throw new CliError(`\u65E0\u6548 --format "${globalOpts.format}"`, ExitCode.USER_ERROR);
|
|
748
|
+
}
|
|
749
|
+
return {
|
|
750
|
+
format,
|
|
751
|
+
out: globalOpts.out,
|
|
752
|
+
quiet: globalOpts.quiet,
|
|
753
|
+
fields: globalOpts.fields ? parseFields(globalOpts.fields) : void 0
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
async function main() {
|
|
757
|
+
const program = new Command();
|
|
758
|
+
program.name("maptec").description("Maptec \u5730\u56FE CLI \u2014 \u7ED3\u6784\u5316 JSON \u8F93\u51FA\uFF0C\u4F9B\u5F00\u53D1\u8005\u4E0E AI Agent \u8C03\u7528").version(getVersion(), "-V, --version", "\u663E\u793A\u7248\u672C\u53F7");
|
|
759
|
+
program.option("--format <json|table>", "\u8F93\u51FA\u683C\u5F0F", "json").option("--out <file>", "\u5199\u5165\u6587\u4EF6\u800C\u975E stdout").option("--quiet", "\u51CF\u5C11 stderr \u8FDB\u5EA6\u4FE1\u606F").option("--timeout <ms>", "\u8986\u76D6\u9ED8\u8BA4\u8BF7\u6C42\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09").option("--fields <list>", "\u88C1\u526A\u8F93\u51FA\u5B57\u6BB5\uFF0C\u9017\u53F7\u5206\u9694");
|
|
760
|
+
program.command("init").description("\u4EA4\u4E92\u5F0F\u914D\u7F6E apiKey \u4E0E baseUrl").action(async () => {
|
|
761
|
+
const globalOpts = program.opts();
|
|
762
|
+
if (globalOpts.timeout) {
|
|
763
|
+
const config = await loadConfig();
|
|
764
|
+
config.timeoutMs = Number(globalOpts.timeout);
|
|
765
|
+
}
|
|
766
|
+
await runInit(buildOutputOptions(globalOpts));
|
|
767
|
+
});
|
|
768
|
+
const configCmd = program.command("config").description("\u8BFB\u5199 ~/.maptec/config.json");
|
|
769
|
+
configCmd.command("get").description("\u6253\u5370\u5F53\u524D\u914D\u7F6E\uFF08apiKey \u8131\u654F\uFF09").action(async () => {
|
|
770
|
+
const globalOpts = program.opts();
|
|
771
|
+
await runConfigGet(buildOutputOptions(globalOpts));
|
|
772
|
+
});
|
|
773
|
+
configCmd.command("set <key> <value>").description("\u8BBE\u7F6E\u914D\u7F6E\u9879\uFF1Aapi-key | base-url | default-format | timeout").action(async (key, value) => {
|
|
774
|
+
const globalOpts = program.opts();
|
|
775
|
+
await runConfigSet(key, value, buildOutputOptions(globalOpts));
|
|
776
|
+
});
|
|
777
|
+
program.command("geocode").description("\u6B63\u5411\u5730\u7406\u7F16\u7801\uFF1A\u5730\u5740 \u2192 \u5750\u6807").requiredOption("--address <text>", "\u5730\u5740\u5B57\u7B26\u4E32").option("--language <code>", "\u8FD4\u56DE\u8BED\u8A00\uFF0C\u5982 zh-CN").option("--region <code>", "\u5730\u533A\u504F\u5411\uFF0C\u5982 CN").action(async (opts) => {
|
|
778
|
+
const globalOpts = program.opts();
|
|
779
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
780
|
+
await runGeocode(opts, buildOutputOptions(globalOpts));
|
|
781
|
+
});
|
|
782
|
+
program.command("reverse-geocode").description("\u53CD\u5411\u5730\u7406\u7F16\u7801\uFF1A\u5750\u6807 \u2192 \u5730\u5740").requiredOption("--lat <number>", "\u7EAC\u5EA6", parseFloat).requiredOption("--lng <number>", "\u7ECF\u5EA6", parseFloat).option("--language <code>", "\u8FD4\u56DE\u8BED\u8A00").option("--region <code>", "\u5730\u533A\u504F\u5411").option("--result-type <types>", "\u7ED3\u679C\u7C7B\u578B\u8FC7\u6EE4\uFF0C\u7AD6\u7EBF\u5206\u9694").option("--location-type <types>", "\u7CBE\u5EA6\u7C7B\u578B\u8FC7\u6EE4").action(async (opts) => {
|
|
783
|
+
const globalOpts = program.opts();
|
|
784
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
785
|
+
await runReverseGeocode(
|
|
786
|
+
{
|
|
787
|
+
lat: opts.lat,
|
|
788
|
+
lng: opts.lng,
|
|
789
|
+
language: opts.language,
|
|
790
|
+
region: opts.region,
|
|
791
|
+
resultType: opts.resultType,
|
|
792
|
+
locationType: opts.locationType
|
|
793
|
+
},
|
|
794
|
+
buildOutputOptions(globalOpts)
|
|
795
|
+
);
|
|
796
|
+
});
|
|
797
|
+
const searchCmd = program.command("search").description("\u5730\u70B9\u641C\u7D22");
|
|
798
|
+
searchCmd.command("text").description("\u5173\u952E\u8BCD\u6587\u672C\u641C\u7D22").requiredOption("--query <text>", "\u641C\u7D22\u5173\u952E\u8BCD").option("--location <lng,lat>", "\u4F4D\u7F6E\u504F\u5411\uFF08\u5706\u5FC3\uFF09").option("--language <code>", "\u8BED\u8A00").option("--region <code>", "\u5730\u533A").option("--page-size <n>", "\u6BCF\u9875\u6761\u6570", parseInt).option("--type <category>", "POI \u7C7B\u522B").option("--rank <mode>", "RELEVANCE|DISTANCE|POPULARITY").action(async (opts) => {
|
|
799
|
+
const globalOpts = program.opts();
|
|
800
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
801
|
+
await runSearchText(opts, buildOutputOptions(globalOpts));
|
|
802
|
+
});
|
|
803
|
+
searchCmd.command("nearby").description("\u9644\u8FD1\u641C\u7D22").requiredOption("--lat <number>", "\u7EAC\u5EA6", parseFloat).requiredOption("--lng <number>", "\u7ECF\u5EA6", parseFloat).option("--radius <meters>", "\u534A\u5F84\uFF08\u7C73\uFF09", parseInt).option("--types <list>", "\u7C7B\u578B\uFF0C\u9017\u53F7\u5206\u9694").option("--limit <n>", "\u7ED3\u679C\u4E0A\u9650", parseInt).option("--language <code>", "\u8BED\u8A00").option("--region <code>", "\u5730\u533A").option("--rank <mode>", "\u6392\u5E8F").action(async (opts) => {
|
|
804
|
+
const globalOpts = program.opts();
|
|
805
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
806
|
+
await runSearchNearby(
|
|
807
|
+
{
|
|
808
|
+
lat: opts.lat,
|
|
809
|
+
lng: opts.lng,
|
|
810
|
+
radius: opts.radius,
|
|
811
|
+
types: opts.types,
|
|
812
|
+
limit: opts.limit,
|
|
813
|
+
language: opts.language,
|
|
814
|
+
region: opts.region,
|
|
815
|
+
rank: opts.rank
|
|
816
|
+
},
|
|
817
|
+
buildOutputOptions(globalOpts)
|
|
818
|
+
);
|
|
819
|
+
});
|
|
820
|
+
searchCmd.command("suggest").description("\u8F93\u5165\u63D0\u793A / \u81EA\u52A8\u8865\u5168").requiredOption("--query <text>", "\u8F93\u5165\u5B57\u7B26\u4E32").option("--location <lng,lat>", "\u4F4D\u7F6E\u504F\u5411").option("--language <code>", "\u8BED\u8A00").option("--region <code>", "\u5730\u533A").option("--limit <n>", "\u7ED3\u679C\u4E0A\u9650", parseInt).action(async (opts) => {
|
|
821
|
+
const globalOpts = program.opts();
|
|
822
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
823
|
+
await runSearchSuggest(opts, buildOutputOptions(globalOpts));
|
|
824
|
+
});
|
|
825
|
+
searchCmd.command("place").description("\u5730\u70B9\u8BE6\u60C5").requiredOption("--id <placeId>", "\u5730\u70B9 ID").option("--language <code>", "\u8BED\u8A00").option("--region <code>", "\u5730\u533A").option("--session-token <token>", "\u4F1A\u8BDD\u4EE4\u724C").action(async (opts) => {
|
|
826
|
+
const globalOpts = program.opts();
|
|
827
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
828
|
+
await runSearchPlace(
|
|
829
|
+
{
|
|
830
|
+
id: opts.id,
|
|
831
|
+
language: opts.language,
|
|
832
|
+
region: opts.region,
|
|
833
|
+
sessionToken: opts.sessionToken
|
|
834
|
+
},
|
|
835
|
+
buildOutputOptions(globalOpts)
|
|
836
|
+
);
|
|
837
|
+
});
|
|
838
|
+
const routeCmd = program.command("route").description("\u8DEF\u7EBF\u89C4\u5212");
|
|
839
|
+
const addRouteOptions = (cmd) => {
|
|
840
|
+
cmd.option("--from <text>", "\u8D77\u70B9\u5730\u5740\u6216 lng,lat").option("--to <text>", "\u7EC8\u70B9\u5730\u5740\u6216 lng,lat").option("--from-lat <number>", "\u8D77\u70B9\u7EAC\u5EA6", parseFloat).option("--from-lng <number>", "\u8D77\u70B9\u7ECF\u5EA6", parseFloat).option("--to-lat <number>", "\u7EC8\u70B9\u7EAC\u5EA6", parseFloat).option("--to-lng <number>", "\u7EC8\u70B9\u7ECF\u5EA6", parseFloat).option("--strategy <name>", "fastest|shortest|eco|balanced").option("--language <code>", "\u5BFC\u822A\u8BED\u8A00");
|
|
841
|
+
};
|
|
842
|
+
addRouteOptions(
|
|
843
|
+
routeCmd.command("driving").description("\u9A7E\u8F66\u8DEF\u7EBF").action(async (opts) => {
|
|
844
|
+
const globalOpts = program.opts();
|
|
845
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
846
|
+
await runRoute(
|
|
847
|
+
{
|
|
848
|
+
mode: "driving",
|
|
849
|
+
from: opts.from,
|
|
850
|
+
to: opts.to,
|
|
851
|
+
fromLat: opts.fromLat,
|
|
852
|
+
fromLng: opts.fromLng,
|
|
853
|
+
toLat: opts.toLat,
|
|
854
|
+
toLng: opts.toLng,
|
|
855
|
+
strategy: opts.strategy,
|
|
856
|
+
language: opts.language
|
|
857
|
+
},
|
|
858
|
+
buildOutputOptions(globalOpts)
|
|
859
|
+
);
|
|
860
|
+
})
|
|
861
|
+
);
|
|
862
|
+
addRouteOptions(
|
|
863
|
+
routeCmd.command("truck").description("\u8D27\u8F66\u8DEF\u7EBF").option("--height <meters>", "\u8F66\u9AD8\uFF08\u7C73\uFF09", parseFloat).option("--weight <tons>", "\u603B\u91CD\uFF08\u5428\uFF09", parseFloat).option("--length <meters>", "\u8F66\u957F\uFF08\u7C73\uFF09", parseFloat).action(async (opts) => {
|
|
864
|
+
const globalOpts = program.opts();
|
|
865
|
+
await applyTimeoutOverride(globalOpts.timeout);
|
|
866
|
+
await runRoute(
|
|
867
|
+
{
|
|
868
|
+
mode: "truck",
|
|
869
|
+
from: opts.from,
|
|
870
|
+
to: opts.to,
|
|
871
|
+
fromLat: opts.fromLat,
|
|
872
|
+
fromLng: opts.fromLng,
|
|
873
|
+
toLat: opts.toLat,
|
|
874
|
+
toLng: opts.toLng,
|
|
875
|
+
strategy: opts.strategy,
|
|
876
|
+
language: opts.language,
|
|
877
|
+
height: opts.height,
|
|
878
|
+
weight: opts.weight,
|
|
879
|
+
length: opts.length
|
|
880
|
+
},
|
|
881
|
+
buildOutputOptions(globalOpts)
|
|
882
|
+
);
|
|
883
|
+
})
|
|
884
|
+
);
|
|
885
|
+
await program.parseAsync(process.argv);
|
|
886
|
+
}
|
|
887
|
+
async function applyTimeoutOverride(timeout) {
|
|
888
|
+
if (!timeout) return;
|
|
889
|
+
const ms = Number(timeout);
|
|
890
|
+
if (!Number.isFinite(ms) || ms <= 0) {
|
|
891
|
+
throw new CliError("\u65E0\u6548 --timeout \u503C", ExitCode.USER_ERROR);
|
|
892
|
+
}
|
|
893
|
+
const config = await loadConfig();
|
|
894
|
+
const { saveConfig: saveConfig2 } = await import("./store-ZU7HLXCV.js");
|
|
895
|
+
config.timeoutMs = ms;
|
|
896
|
+
await saveConfig2(config);
|
|
897
|
+
}
|
|
898
|
+
main().catch(exitWithError);
|
|
899
|
+
//# sourceMappingURL=cli.js.map
|