itamatrix 0.1.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/DESIGN.md +247 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/browser/batch.d.ts +8 -0
- package/dist/browser/batch.js +87 -0
- package/dist/browser/batch.js.map +1 -0
- package/dist/browser/batch.test.d.ts +1 -0
- package/dist/browser/batch.test.js +38 -0
- package/dist/browser/batch.test.js.map +1 -0
- package/dist/browser/forms.d.ts +26 -0
- package/dist/browser/forms.js +233 -0
- package/dist/browser/forms.js.map +1 -0
- package/dist/browser/session.d.ts +20 -0
- package/dist/browser/session.js +126 -0
- package/dist/browser/session.js.map +1 -0
- package/dist/cache.d.ts +21 -0
- package/dist/cache.js +71 -0
- package/dist/cache.js.map +1 -0
- package/dist/cache.test.d.ts +1 -0
- package/dist/cache.test.js +79 -0
- package/dist/cache.test.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +154 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/calendar.d.ts +19 -0
- package/dist/commands/calendar.js +47 -0
- package/dist/commands/calendar.js.map +1 -0
- package/dist/commands/calendar.test.d.ts +1 -0
- package/dist/commands/calendar.test.js +58 -0
- package/dist/commands/calendar.test.js.map +1 -0
- package/dist/commands/multicity.d.ts +17 -0
- package/dist/commands/multicity.js +50 -0
- package/dist/commands/multicity.js.map +1 -0
- package/dist/commands/multicity.test.d.ts +1 -0
- package/dist/commands/multicity.test.js +54 -0
- package/dist/commands/multicity.test.js.map +1 -0
- package/dist/commands/search.d.ts +20 -0
- package/dist/commands/search.js +43 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/search.test.d.ts +1 -0
- package/dist/commands/search.test.js +124 -0
- package/dist/commands/search.test.js.map +1 -0
- package/dist/commands/shared.d.ts +44 -0
- package/dist/commands/shared.js +77 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/model/spec.d.ts +63 -0
- package/dist/model/spec.js +29 -0
- package/dist/model/spec.js.map +1 -0
- package/dist/model/spec.test.d.ts +1 -0
- package/dist/model/spec.test.js +55 -0
- package/dist/model/spec.test.js.map +1 -0
- package/dist/model/types.d.ts +22080 -0
- package/dist/model/types.js +100 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/types.test.d.ts +1 -0
- package/dist/model/types.test.js +35 -0
- package/dist/model/types.test.js.map +1 -0
- package/dist/render/calendar.d.ts +21 -0
- package/dist/render/calendar.js +89 -0
- package/dist/render/calendar.js.map +1 -0
- package/dist/render/calendar.render.test.d.ts +1 -0
- package/dist/render/calendar.render.test.js +66 -0
- package/dist/render/calendar.render.test.js.map +1 -0
- package/dist/render/json.d.ts +2 -0
- package/dist/render/json.js +4 -0
- package/dist/render/json.js.map +1 -0
- package/dist/render/normalize.d.ts +32 -0
- package/dist/render/normalize.js +44 -0
- package/dist/render/normalize.js.map +1 -0
- package/dist/render/render.test.d.ts +1 -0
- package/dist/render/render.test.js +129 -0
- package/dist/render/render.test.js.map +1 -0
- package/dist/render/table.d.ts +2 -0
- package/dist/render/table.js +49 -0
- package/dist/render/table.js.map +1 -0
- package/docs/ROUTING_CODES.md +137 -0
- package/package.json +68 -0
- package/skills/itamatrix/SKILL.md +173 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { Command, InvalidArgumentError } from "commander";
|
|
4
|
+
import { runSearchCommand, } from "./commands/search.js";
|
|
5
|
+
import { runMultiCityCommand } from "./commands/multicity.js";
|
|
6
|
+
import { runCalendarCommand } from "./commands/calendar.js";
|
|
7
|
+
import { carriersToRouting } from "./commands/shared.js";
|
|
8
|
+
function collect(value, prev) {
|
|
9
|
+
return [...prev, value];
|
|
10
|
+
}
|
|
11
|
+
/** Commander parser that accepts only whole integers (rejects "1.5", "2foo"). */
|
|
12
|
+
function intArg(flag) {
|
|
13
|
+
return (value) => {
|
|
14
|
+
if (!/^-?\d+$/.test(value.trim())) {
|
|
15
|
+
throw new InvalidArgumentError(`${flag} must be an integer, got "${value}"`);
|
|
16
|
+
}
|
|
17
|
+
return parseInt(value, 10);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function run(action) {
|
|
21
|
+
return action()
|
|
22
|
+
.then((out) => {
|
|
23
|
+
process.stdout.write(out + "\n");
|
|
24
|
+
})
|
|
25
|
+
.catch((err) => {
|
|
26
|
+
process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function resolveFormat(json, table) {
|
|
31
|
+
if (json)
|
|
32
|
+
return "json";
|
|
33
|
+
if (table)
|
|
34
|
+
return "table";
|
|
35
|
+
// Auto-detect: TTY → table, piped → json.
|
|
36
|
+
return process.stdout.isTTY ? "table" : "json";
|
|
37
|
+
}
|
|
38
|
+
export const program = new Command();
|
|
39
|
+
program
|
|
40
|
+
.name("itamatrix")
|
|
41
|
+
.description("CLI for ITA Matrix flight search")
|
|
42
|
+
.version("0.1.0")
|
|
43
|
+
.option("--json", "force JSON output")
|
|
44
|
+
.option("--table", "force table output")
|
|
45
|
+
.option("--no-cache", "bypass the result cache (always query live)")
|
|
46
|
+
.option("--cache-ttl <minutes>", "max age of a cached result in minutes (default 60)", intArg("--cache-ttl"));
|
|
47
|
+
program
|
|
48
|
+
.command("search")
|
|
49
|
+
.description("Search one-way or round-trip flights")
|
|
50
|
+
.argument("<origin>", "origin airport/city code")
|
|
51
|
+
.argument("<dest>", "destination airport/city code")
|
|
52
|
+
.requiredOption("--depart <date>", "departure date (YYYY-MM-DD)")
|
|
53
|
+
.option("--return <date>", "return date (YYYY-MM-DD) → round-trip")
|
|
54
|
+
.option("--one-way", "force one-way (ignore --return)")
|
|
55
|
+
.option("--adults <n>", "number of adults", intArg("--adults"), 1)
|
|
56
|
+
.option("--limit <n>", "max results, 1-25 (one Matrix page)", intArg("--limit"), 25)
|
|
57
|
+
.option("--cabin <cabin>", "cheapest | premium-economy | business | first")
|
|
58
|
+
.option("--stops <stops>", "any | none | 1 | 2")
|
|
59
|
+
.option("--extra-stops <stops>", "any | none | 1 | 2")
|
|
60
|
+
.option("--carriers <list>", "comma-separated carriers, e.g. UA,AA (sugar for --routing)")
|
|
61
|
+
.option("--routing <codes>", "ITA routing codes (path) — see docs/ROUTING_CODES.md")
|
|
62
|
+
.option("--ext <codes>", "ITA extension codes (faring/filters) — see docs/ROUTING_CODES.md")
|
|
63
|
+
.option("--headful", "show the browser window (debug)")
|
|
64
|
+
.action(async (origin, dest, cmdOpts, command) => {
|
|
65
|
+
const globals = command.parent.opts();
|
|
66
|
+
const opts = {
|
|
67
|
+
depart: cmdOpts.depart,
|
|
68
|
+
return: cmdOpts.return,
|
|
69
|
+
oneWay: cmdOpts.oneWay,
|
|
70
|
+
adults: cmdOpts.adults,
|
|
71
|
+
limit: cmdOpts.limit,
|
|
72
|
+
cabin: cmdOpts.cabin,
|
|
73
|
+
stops: cmdOpts.stops,
|
|
74
|
+
extraStops: cmdOpts.extraStops,
|
|
75
|
+
carriers: cmdOpts.carriers,
|
|
76
|
+
routing: cmdOpts.routing,
|
|
77
|
+
ext: cmdOpts.ext,
|
|
78
|
+
headful: cmdOpts.headful,
|
|
79
|
+
format: resolveFormat(globals.json, globals.table),
|
|
80
|
+
cache: globals.cache,
|
|
81
|
+
cacheTtlMinutes: globals.cacheTtl,
|
|
82
|
+
};
|
|
83
|
+
await run(() => runSearchCommand(origin, dest, opts));
|
|
84
|
+
});
|
|
85
|
+
program
|
|
86
|
+
.command("multicity")
|
|
87
|
+
.description("Search a multi-city itinerary (N legs)")
|
|
88
|
+
.requiredOption("--leg <ORIGIN:DEST:DATE>", "a leg, e.g. JFK:NRT:2026-08-10 (repeatable, >= 2)", collect, [])
|
|
89
|
+
.option("--adults <n>", "number of adults", intArg("--adults"), 1)
|
|
90
|
+
.option("--limit <n>", "max results, 1-25 (one Matrix page)", intArg("--limit"), 25)
|
|
91
|
+
.option("--cabin <cabin>", "cheapest | premium-economy | business | first")
|
|
92
|
+
.option("--stops <stops>", "any | none | 1 | 2")
|
|
93
|
+
.option("--extra-stops <stops>", "any | none | 1 | 2")
|
|
94
|
+
.option("--carriers <list>", "comma-separated carriers, e.g. UA,AA (sugar for --routing)")
|
|
95
|
+
.option("--routing <codes>", "ITA routing codes applied to every leg")
|
|
96
|
+
.option("--ext <codes>", "ITA extension codes applied to every leg")
|
|
97
|
+
.option("--headful", "show the browser window (debug)")
|
|
98
|
+
.action(async (cmdOpts, command) => {
|
|
99
|
+
const globals = command.parent.opts();
|
|
100
|
+
await run(() => runMultiCityCommand({
|
|
101
|
+
legs: cmdOpts.leg,
|
|
102
|
+
adults: cmdOpts.adults,
|
|
103
|
+
limit: cmdOpts.limit,
|
|
104
|
+
cabin: cmdOpts.cabin,
|
|
105
|
+
stops: cmdOpts.stops,
|
|
106
|
+
extraStops: cmdOpts.extraStops,
|
|
107
|
+
routing: cmdOpts.routing ?? carriersToRouting(cmdOpts.carriers),
|
|
108
|
+
ext: cmdOpts.ext,
|
|
109
|
+
format: resolveFormat(globals.json, globals.table),
|
|
110
|
+
headful: cmdOpts.headful,
|
|
111
|
+
cache: globals.cache,
|
|
112
|
+
cacheTtlMinutes: globals.cacheTtl,
|
|
113
|
+
}));
|
|
114
|
+
});
|
|
115
|
+
program
|
|
116
|
+
.command("calendar")
|
|
117
|
+
.description("Price calendar: lowest fare per departure date over a range")
|
|
118
|
+
.argument("<origin>", "origin airport/city code")
|
|
119
|
+
.argument("<dest>", "destination airport/city code")
|
|
120
|
+
.requiredOption("--depart-range <start:end>", "YYYY-MM-DD:YYYY-MM-DD")
|
|
121
|
+
.option("--trip-length <nights>", "round-trip nights; omit for one-way", intArg("--trip-length"))
|
|
122
|
+
.option("--adults <n>", "number of adults", intArg("--adults"), 1)
|
|
123
|
+
.option("--limit <n>", "show only the N cheapest dates", intArg("--limit"), 25)
|
|
124
|
+
.option("--cabin <cabin>", "cheapest | premium-economy | business | first")
|
|
125
|
+
.option("--stops <stops>", "any | none | 1 | 2")
|
|
126
|
+
.option("--extra-stops <stops>", "any | none | 1 | 2")
|
|
127
|
+
.option("--carriers <list>", "comma-separated carriers, e.g. UA,AA (sugar for --routing)")
|
|
128
|
+
.option("--routing <codes>", "ITA routing codes")
|
|
129
|
+
.option("--ext <codes>", "ITA extension codes")
|
|
130
|
+
.option("--headful", "show the browser window (debug)")
|
|
131
|
+
.action(async (origin, dest, cmdOpts, command) => {
|
|
132
|
+
const globals = command.parent.opts();
|
|
133
|
+
await run(() => runCalendarCommand(origin, dest, {
|
|
134
|
+
departRange: cmdOpts.departRange,
|
|
135
|
+
tripLength: cmdOpts.tripLength,
|
|
136
|
+
adults: cmdOpts.adults,
|
|
137
|
+
limit: cmdOpts.limit,
|
|
138
|
+
cabin: cmdOpts.cabin,
|
|
139
|
+
stops: cmdOpts.stops,
|
|
140
|
+
extraStops: cmdOpts.extraStops,
|
|
141
|
+
routing: cmdOpts.routing ?? carriersToRouting(cmdOpts.carriers),
|
|
142
|
+
ext: cmdOpts.ext,
|
|
143
|
+
format: resolveFormat(globals.json, globals.table),
|
|
144
|
+
headful: cmdOpts.headful,
|
|
145
|
+
cache: globals.cache,
|
|
146
|
+
cacheTtlMinutes: globals.cacheTtl,
|
|
147
|
+
}));
|
|
148
|
+
});
|
|
149
|
+
// Parse only when run as the CLI entrypoint, so tools can import `program` to
|
|
150
|
+
// introspect commands/options (see scripts/gen-skill.ts) without triggering a run.
|
|
151
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
152
|
+
program.parseAsync(process.argv);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type CacheControlOptions, type OutputFormat } from "./shared.js";
|
|
2
|
+
export interface CalendarCommandOptions extends CacheControlOptions {
|
|
3
|
+
departRange: string;
|
|
4
|
+
tripLength?: number;
|
|
5
|
+
adults: number;
|
|
6
|
+
limit: number;
|
|
7
|
+
cabin?: string;
|
|
8
|
+
stops?: string;
|
|
9
|
+
extraStops?: string;
|
|
10
|
+
routing?: string;
|
|
11
|
+
ext?: string;
|
|
12
|
+
format: OutputFormat;
|
|
13
|
+
headful?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function runCalendarCommand(origin: string, dest: string, opts: CalendarCommandOptions): Promise<string>;
|
|
16
|
+
export declare function parseDepartRange(range: string): {
|
|
17
|
+
from: string;
|
|
18
|
+
to: string;
|
|
19
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { runCalendar } from "../browser/session.js";
|
|
2
|
+
import { withCache } from "../cache.js";
|
|
3
|
+
import { normalizeCalendar, renderCalendarJson, renderCalendarTable, } from "../render/calendar.js";
|
|
4
|
+
import { requireIsoDate, resolveCacheOptions, validateTripControls, } from "./shared.js";
|
|
5
|
+
export async function runCalendarCommand(origin, dest, opts) {
|
|
6
|
+
const { from, to } = parseDepartRange(opts.departRange);
|
|
7
|
+
validate(origin, dest, opts, from, to);
|
|
8
|
+
const spec = {
|
|
9
|
+
origin: origin.toUpperCase(),
|
|
10
|
+
dest: dest.toUpperCase(),
|
|
11
|
+
departFrom: from,
|
|
12
|
+
departTo: to,
|
|
13
|
+
tripLength: opts.tripLength,
|
|
14
|
+
adults: opts.adults,
|
|
15
|
+
limit: opts.limit,
|
|
16
|
+
cabin: opts.cabin,
|
|
17
|
+
stops: opts.stops,
|
|
18
|
+
extraStops: opts.extraStops,
|
|
19
|
+
routing: opts.routing,
|
|
20
|
+
ext: opts.ext,
|
|
21
|
+
};
|
|
22
|
+
const response = await withCache("calendar", spec, resolveCacheOptions(opts), () => runCalendar(spec, { headful: opts.headful }));
|
|
23
|
+
const cal = normalizeCalendar(response, opts.limit);
|
|
24
|
+
return opts.format === "json" ? renderCalendarJson(cal) : renderCalendarTable(cal);
|
|
25
|
+
}
|
|
26
|
+
export function parseDepartRange(range) {
|
|
27
|
+
const parts = (range ?? "").split(":");
|
|
28
|
+
if (parts.length !== 2) {
|
|
29
|
+
throw new Error(`--depart-range must be START:END (YYYY-MM-DD:YYYY-MM-DD), got "${range}"`);
|
|
30
|
+
}
|
|
31
|
+
const from = parts[0].trim();
|
|
32
|
+
const to = parts[1].trim();
|
|
33
|
+
requireIsoDate(from, "--depart-range start");
|
|
34
|
+
requireIsoDate(to, "--depart-range end");
|
|
35
|
+
return { from, to };
|
|
36
|
+
}
|
|
37
|
+
function validate(origin, dest, opts, from, to) {
|
|
38
|
+
if (!origin || !dest)
|
|
39
|
+
throw new Error("origin and destination are required");
|
|
40
|
+
if (from > to)
|
|
41
|
+
throw new Error("--depart-range start must be on or before end");
|
|
42
|
+
if (opts.tripLength != null && (!Number.isInteger(opts.tripLength) || opts.tripLength < 0)) {
|
|
43
|
+
throw new Error("--trip-length must be an integer >= 0");
|
|
44
|
+
}
|
|
45
|
+
validateTripControls(opts);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.js","sourceRoot":"","sources":["../../src/commands/calendar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { parseDepartRange, runCalendarCommand, } from "./calendar.js";
|
|
3
|
+
const captured = [];
|
|
4
|
+
vi.mock("../browser/session.js", () => ({
|
|
5
|
+
runCalendar: (spec) => {
|
|
6
|
+
captured.push(spec);
|
|
7
|
+
return Promise.resolve({ calendarSliceList: { days: [] } });
|
|
8
|
+
},
|
|
9
|
+
}));
|
|
10
|
+
const opts = (over = {}) => ({
|
|
11
|
+
departRange: "2026-08-01:2026-08-31",
|
|
12
|
+
tripLength: 7,
|
|
13
|
+
adults: 1,
|
|
14
|
+
limit: 25,
|
|
15
|
+
format: "json",
|
|
16
|
+
cache: false,
|
|
17
|
+
...over,
|
|
18
|
+
});
|
|
19
|
+
describe("parseDepartRange", () => {
|
|
20
|
+
it("splits START:END into trimmed dates", () => {
|
|
21
|
+
expect(parseDepartRange("2026-08-01:2026-08-31")).toEqual({
|
|
22
|
+
from: "2026-08-01",
|
|
23
|
+
to: "2026-08-31",
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
it("rejects a range without exactly two parts", () => {
|
|
27
|
+
expect(() => parseDepartRange("2026-08-01")).toThrow(/START:END/);
|
|
28
|
+
});
|
|
29
|
+
it("rejects a malformed date in the range", () => {
|
|
30
|
+
expect(() => parseDepartRange("2026/08/01:2026-08-31")).toThrow(/must be a valid date/);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("runCalendarCommand validation/wiring", () => {
|
|
34
|
+
it("builds a calendar spec and uppercases airports", async () => {
|
|
35
|
+
captured.length = 0;
|
|
36
|
+
await runCalendarCommand("bos", "lax", opts({ tripLength: 5 }));
|
|
37
|
+
expect(captured[0]).toMatchObject({
|
|
38
|
+
origin: "BOS",
|
|
39
|
+
dest: "LAX",
|
|
40
|
+
departFrom: "2026-08-01",
|
|
41
|
+
departTo: "2026-08-31",
|
|
42
|
+
tripLength: 5,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it("rejects a start after the end", async () => {
|
|
46
|
+
await expect(runCalendarCommand("BOS", "LAX", opts({ departRange: "2026-08-31:2026-08-01" }))).rejects.toThrow(/start must be on or before end/);
|
|
47
|
+
});
|
|
48
|
+
it("rejects a negative --trip-length", async () => {
|
|
49
|
+
await expect(runCalendarCommand("BOS", "LAX", opts({ tripLength: -1 }))).rejects.toThrow(/--trip-length must be an integer >= 0/);
|
|
50
|
+
});
|
|
51
|
+
it("rejects a non-numeric --trip-length (NaN)", async () => {
|
|
52
|
+
await expect(runCalendarCommand("BOS", "LAX", opts({ tripLength: NaN }))).rejects.toThrow(/--trip-length must be an integer >= 0/);
|
|
53
|
+
});
|
|
54
|
+
it("rejects an invalid --limit", async () => {
|
|
55
|
+
await expect(runCalendarCommand("BOS", "LAX", opts({ limit: 0 }))).rejects.toThrow(/--limit must be an integer >= 1/);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=calendar.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.test.js","sourceRoot":"","sources":["../../src/commands/calendar.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Slice } from "../model/spec.js";
|
|
2
|
+
import { type CacheControlOptions, type OutputFormat } from "./shared.js";
|
|
3
|
+
export interface MultiCityCommandOptions extends CacheControlOptions {
|
|
4
|
+
legs: string[];
|
|
5
|
+
adults: number;
|
|
6
|
+
limit: number;
|
|
7
|
+
cabin?: string;
|
|
8
|
+
stops?: string;
|
|
9
|
+
extraStops?: string;
|
|
10
|
+
routing?: string;
|
|
11
|
+
ext?: string;
|
|
12
|
+
format: OutputFormat;
|
|
13
|
+
headful?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function runMultiCityCommand(opts: MultiCityCommandOptions): Promise<string>;
|
|
16
|
+
/** Parses `--leg ORIGIN:DEST:DATE` flags into slices; `--routing`/`--ext` apply to all. */
|
|
17
|
+
export declare function parseLegs(opts: MultiCityCommandOptions): Slice[];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { runMultiCity } from "../browser/session.js";
|
|
2
|
+
import { withCache } from "../cache.js";
|
|
3
|
+
import { normalize } from "../render/normalize.js";
|
|
4
|
+
import { renderJson } from "../render/json.js";
|
|
5
|
+
import { renderTable } from "../render/table.js";
|
|
6
|
+
import { requireIsoDate, requirePageLimit, resolveCacheOptions, validateTripControls, } from "./shared.js";
|
|
7
|
+
export async function runMultiCityCommand(opts) {
|
|
8
|
+
const slices = parseLegs(opts);
|
|
9
|
+
validateTripControls(opts);
|
|
10
|
+
requirePageLimit(opts.limit);
|
|
11
|
+
const spec = {
|
|
12
|
+
slices,
|
|
13
|
+
adults: opts.adults,
|
|
14
|
+
limit: opts.limit,
|
|
15
|
+
cabin: opts.cabin,
|
|
16
|
+
stops: opts.stops,
|
|
17
|
+
extraStops: opts.extraStops,
|
|
18
|
+
};
|
|
19
|
+
const response = await withCache("multicity", spec, resolveCacheOptions(opts), () => runMultiCity(spec, { headful: opts.headful }));
|
|
20
|
+
const result = normalize(response, opts.limit);
|
|
21
|
+
return opts.format === "json" ? renderJson(result) : renderTable(result);
|
|
22
|
+
}
|
|
23
|
+
/** Parses `--leg ORIGIN:DEST:DATE` flags into slices; `--routing`/`--ext` apply to all. */
|
|
24
|
+
export function parseLegs(opts) {
|
|
25
|
+
if (!opts.legs || opts.legs.length < 2) {
|
|
26
|
+
throw new Error("multicity needs at least 2 --leg ORIGIN:DEST:DATE values");
|
|
27
|
+
}
|
|
28
|
+
return opts.legs.map((raw, i) => toSlice(raw, i, opts));
|
|
29
|
+
}
|
|
30
|
+
function toSlice(raw, index, opts) {
|
|
31
|
+
const parts = raw.split(":");
|
|
32
|
+
if (parts.length !== 3) {
|
|
33
|
+
throw new Error(`--leg #${index + 1} must be ORIGIN:DEST:YYYY-MM-DD, got "${raw}"`);
|
|
34
|
+
}
|
|
35
|
+
const origin = parts[0].trim();
|
|
36
|
+
const dest = parts[1].trim();
|
|
37
|
+
const date = parts[2].trim();
|
|
38
|
+
if (!origin || !dest) {
|
|
39
|
+
throw new Error(`--leg #${index + 1} is missing an origin or destination`);
|
|
40
|
+
}
|
|
41
|
+
requireIsoDate(date, `--leg #${index + 1} date`);
|
|
42
|
+
return {
|
|
43
|
+
origin: origin.toUpperCase(),
|
|
44
|
+
dest: dest.toUpperCase(),
|
|
45
|
+
departDate: date,
|
|
46
|
+
routing: opts.routing,
|
|
47
|
+
ext: opts.ext,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=multicity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multicity.js","sourceRoot":"","sources":["../../src/commands/multicity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { parseLegs, runMultiCityCommand, } from "./multicity.js";
|
|
3
|
+
const captured = [];
|
|
4
|
+
vi.mock("../browser/session.js", () => ({
|
|
5
|
+
runMultiCity: (spec) => {
|
|
6
|
+
captured.push(spec);
|
|
7
|
+
return Promise.resolve({ solutionList: { solutions: [] } });
|
|
8
|
+
},
|
|
9
|
+
}));
|
|
10
|
+
const opts = (over = {}) => ({
|
|
11
|
+
legs: ["JFK:NRT:2026-08-10", "NRT:SIN:2026-08-15"],
|
|
12
|
+
adults: 1,
|
|
13
|
+
limit: 25,
|
|
14
|
+
format: "json",
|
|
15
|
+
cache: false,
|
|
16
|
+
...over,
|
|
17
|
+
});
|
|
18
|
+
describe("parseLegs", () => {
|
|
19
|
+
it("parses and uppercases ORIGIN:DEST:DATE legs", () => {
|
|
20
|
+
const slices = parseLegs(opts({ legs: ["jfk:nrt:2026-08-10", "nrt:sin:2026-08-15"] }));
|
|
21
|
+
expect(slices).toEqual([
|
|
22
|
+
{ origin: "JFK", dest: "NRT", departDate: "2026-08-10", routing: undefined, ext: undefined },
|
|
23
|
+
{ origin: "NRT", dest: "SIN", departDate: "2026-08-15", routing: undefined, ext: undefined },
|
|
24
|
+
]);
|
|
25
|
+
});
|
|
26
|
+
it("applies global --routing/--ext to every leg", () => {
|
|
27
|
+
const slices = parseLegs(opts({ routing: "UA+", ext: "-REDEYES" }));
|
|
28
|
+
expect(slices.every((s) => s.routing === "UA+" && s.ext === "-REDEYES")).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it("rejects fewer than 2 legs", () => {
|
|
31
|
+
expect(() => parseLegs(opts({ legs: ["JFK:NRT:2026-08-10"] }))).toThrow(/at least 2/);
|
|
32
|
+
});
|
|
33
|
+
it("rejects a leg without three colon-separated parts", () => {
|
|
34
|
+
expect(() => parseLegs(opts({ legs: ["JFK-NRT", "NRT:SIN:2026-08-15"] }))).toThrow(/ORIGIN:DEST/);
|
|
35
|
+
});
|
|
36
|
+
it("rejects a leg with a malformed date", () => {
|
|
37
|
+
expect(() => parseLegs(opts({ legs: ["JFK:NRT:08/10", "NRT:SIN:2026-08-15"] }))).toThrow(/must be a valid date/);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("runMultiCityCommand spec wiring", () => {
|
|
41
|
+
it("builds an N-slice spec with shared controls", async () => {
|
|
42
|
+
captured.length = 0;
|
|
43
|
+
await runMultiCityCommand(opts({ cabin: "business", stops: "1" }));
|
|
44
|
+
expect(captured[0]).toMatchObject({
|
|
45
|
+
cabin: "business",
|
|
46
|
+
stops: "1",
|
|
47
|
+
slices: [{ origin: "JFK" }, { origin: "NRT" }],
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it("rejects an unknown --cabin before launching the browser", async () => {
|
|
51
|
+
await expect(runMultiCityCommand(opts({ cabin: "economy" }))).rejects.toThrow(/--cabin must be one of/);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=multicity.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multicity.test.js","sourceRoot":"","sources":["../../src/commands/multicity.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CacheControlOptions, type OutputFormat } from "./shared.js";
|
|
2
|
+
export type { OutputFormat };
|
|
3
|
+
export interface SearchCommandOptions extends CacheControlOptions {
|
|
4
|
+
depart: string;
|
|
5
|
+
return?: string;
|
|
6
|
+
oneWay?: boolean;
|
|
7
|
+
adults: number;
|
|
8
|
+
limit: number;
|
|
9
|
+
cabin?: string;
|
|
10
|
+
stops?: string;
|
|
11
|
+
extraStops?: string;
|
|
12
|
+
carriers?: string;
|
|
13
|
+
routing?: string;
|
|
14
|
+
ext?: string;
|
|
15
|
+
format: OutputFormat;
|
|
16
|
+
headful?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function runSearchCommand(origin: string, dest: string, opts: SearchCommandOptions): Promise<string>;
|
|
19
|
+
/** `--routing` wins; otherwise `--carriers UA,AA` becomes the routing `UA,AA+`. */
|
|
20
|
+
export declare function resolveRouting(opts: SearchCommandOptions): string | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { runSearch } from "../browser/session.js";
|
|
2
|
+
import { withCache } from "../cache.js";
|
|
3
|
+
import { normalize } from "../render/normalize.js";
|
|
4
|
+
import { renderJson } from "../render/json.js";
|
|
5
|
+
import { renderTable } from "../render/table.js";
|
|
6
|
+
import { carriersToRouting, requireIsoDate, requirePageLimit, resolveCacheOptions, validateTripControls, } from "./shared.js";
|
|
7
|
+
export async function runSearchCommand(origin, dest, opts) {
|
|
8
|
+
validate(origin, dest, opts);
|
|
9
|
+
const spec = {
|
|
10
|
+
origin: origin.toUpperCase(),
|
|
11
|
+
dest: dest.toUpperCase(),
|
|
12
|
+
departDate: opts.depart,
|
|
13
|
+
returnDate: opts.oneWay ? undefined : opts.return,
|
|
14
|
+
adults: opts.adults,
|
|
15
|
+
limit: opts.limit,
|
|
16
|
+
cabin: opts.cabin,
|
|
17
|
+
stops: opts.stops,
|
|
18
|
+
extraStops: opts.extraStops,
|
|
19
|
+
routing: resolveRouting(opts),
|
|
20
|
+
ext: opts.ext,
|
|
21
|
+
};
|
|
22
|
+
const response = await withCache("search", spec, resolveCacheOptions(opts), () => runSearch(spec, { headful: opts.headful }));
|
|
23
|
+
const result = normalize(response, opts.limit);
|
|
24
|
+
return opts.format === "json" ? renderJson(result) : renderTable(result);
|
|
25
|
+
}
|
|
26
|
+
/** `--routing` wins; otherwise `--carriers UA,AA` becomes the routing `UA,AA+`. */
|
|
27
|
+
export function resolveRouting(opts) {
|
|
28
|
+
return opts.routing ?? carriersToRouting(opts.carriers);
|
|
29
|
+
}
|
|
30
|
+
function validate(origin, dest, opts) {
|
|
31
|
+
if (!origin || !dest)
|
|
32
|
+
throw new Error("origin and destination are required");
|
|
33
|
+
requireIsoDate(opts.depart, "--depart");
|
|
34
|
+
if (opts.return && !opts.oneWay) {
|
|
35
|
+
requireIsoDate(opts.return, "--return");
|
|
36
|
+
if (opts.return < opts.depart) {
|
|
37
|
+
throw new Error("--return must be on or after --depart");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
validateTripControls(opts);
|
|
41
|
+
requirePageLimit(opts.limit);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,aAAa,CAAC;AAoBrB,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,IAAY,EACZ,IAA0B;IAE1B,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAE7B,MAAM,IAAI,GAAe;QACvB,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE;QAC5B,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;QACxB,UAAU,EAAE,IAAI,CAAC,MAAM;QACvB,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;QACjD,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK,EAAE,IAAI,CAAC,KAA0B;QACtC,KAAK,EAAE,IAAI,CAAC,KAA8B;QAC1C,UAAU,EAAE,IAAI,CAAC,UAAmC;QACpD,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;QAC7B,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAC/E,SAAS,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAC3C,CAAC;IACF,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,IAA0B;IACvD,OAAO,IAAI,CAAC,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE,IAAY,EAAE,IAA0B;IACxE,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC7E,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAC3B,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|