@typescript-calendar-lib/cli 0.3.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,8 @@ Render month, year, or date-range calendars as plain text — with optional ANSI
5
5
  ## Installation
6
6
 
7
7
  ```sh
8
+ pnpm add @typescript-calendar-lib/cli
9
+ # or
8
10
  npm install @typescript-calendar-lib/cli
9
11
  # or
10
12
  bun add @typescript-calendar-lib/cli
@@ -69,6 +71,9 @@ The package ships a `typescript-calendar-lib` binary:
69
71
  typescript-calendar-lib # current month
70
72
  typescript-calendar-lib 2026 # current month of 2026
71
73
  typescript-calendar-lib 2026 9 # September 2026
74
+ typescript-calendar-lib --year # current year as a 4×3 grid
75
+ typescript-calendar-lib 2026 --year # 2026 as a 4×3 grid
76
+ typescript-calendar-lib --range 2026-01-01 2026-03-31 # months in a date range
72
77
  ```
73
78
 
74
79
  ### Options
@@ -76,14 +81,23 @@ typescript-calendar-lib 2026 9 # September 2026
76
81
  ```
77
82
  --theme <name> Look: default | modern (default: default)
78
83
  --color-scheme <name> Colors: default | ocean | forest | sunset | mono
79
- --color Enable ANSI colors
84
+ --color Enable ANSI colors (auto-detected for TTY)
85
+ --no-color Disable ANSI colors
80
86
  --locale <lang> Language: en | ja | es | de | fr | ko | zh (default: en)
81
87
  --week-start <day> First weekday: sunday | monday (default: sunday)
82
88
  --highlight <YYYY-MM-DD> Highlight a date (e.g. 2026-09-08)
83
89
  --highlight-style <style> Highlight style: bracket | reverse (default: bracket)
90
+ --today <YYYY-MM-DD> Override today (marks the date, defaults year/month)
91
+ --year Render the whole year as a 4×3 grid
92
+ --range <FROM> <TO> Render months from FROM to TO (YYYY-MM-DD)
93
+ -v, --version Show version
84
94
  -h, --help Show this help
85
95
  ```
86
96
 
97
+ ### Color detection
98
+
99
+ Colors are enabled automatically when stdout is a TTY, and disabled when piped or redirected. `--color` and `--no-color` override the detection; `NO_COLOR` and `FORCE_COLOR` environment variables are also respected (explicit flags always win).
100
+
87
101
  Example with `modern` theme and `ocean` color scheme:
88
102
 
89
103
  ```sh
@@ -247,6 +261,8 @@ By default (`color: false`) the output contains no ANSI escape codes, so it's sa
247
261
  typescript-calendar-lib 2026 9 > september.txt
248
262
  ```
249
263
 
264
+ Colors are disabled automatically when stdout is not a TTY, so piping works without extra flags.
265
+
250
266
  ## Exports
251
267
 
252
268
  ```ts
package/dist/bin.d.ts CHANGED
@@ -7,16 +7,31 @@ export interface CliArgs {
7
7
  theme?: ThemeName;
8
8
  colorScheme?: ColorSchemeName;
9
9
  color?: boolean;
10
+ noColor?: boolean;
10
11
  locale?: Locale;
11
12
  weekStart?: WeekStart;
12
13
  highlight?: Date;
13
14
  highlightStyle?: HighlightStyle;
15
+ today?: Date;
16
+ yearView?: boolean;
17
+ range?: {
18
+ from: Date;
19
+ to: Date;
20
+ };
14
21
  }
15
22
  export interface ParseResult {
16
23
  args: CliArgs;
17
24
  error?: string;
18
25
  help?: boolean;
26
+ version?: boolean;
19
27
  }
28
+ /** package.json からバージョンを取得する */
29
+ export declare function getVersion(): string;
30
+ /**
31
+ * CLI フラグ・環境変数・TTY 状態から最終的な color フラグを解決する。
32
+ * 優先順位: --no-color > --color > NO_COLOR > FORCE_COLOR > TTY
33
+ */
34
+ export declare function resolveColor(colorFlag: boolean | undefined, noColorFlag: boolean | undefined, env: Record<string, string | undefined>, isTTY: boolean): boolean;
20
35
  /** YYYY-MM-DD 形式の日付文字列をパースする */
21
36
  export declare function parseDate(value: string): Date | null;
22
37
  /**
package/dist/bin.js CHANGED
@@ -1,6 +1,7 @@
1
- #!/usr/bin/env bun
2
- import { t as calendar } from "./calendar-DNDADt5T.js";
3
- import { createDate } from "@typescript-calendar-lib/core";
1
+ #!/usr/bin/env node
2
+ import { n as calendarRange, r as calendarYear, t as calendar } from "./calendar-DNDADt5T.js";
3
+ import { createRequire } from "node:module";
4
+ import { LOCALES, MAX_YEAR, MIN_YEAR, createDate } from "@typescript-calendar-lib/core";
4
5
  //#region src/bin.ts
5
6
  const THEMES = ["default", "modern"];
6
7
  const COLOR_SCHEMES = [
@@ -10,17 +11,25 @@ const COLOR_SCHEMES = [
10
11
  "sunset",
11
12
  "mono"
12
13
  ];
13
- const LOCALES = [
14
- "en",
15
- "ja",
16
- "es",
17
- "de",
18
- "fr",
19
- "ko",
20
- "zh"
21
- ];
14
+ const LOCALE_LIST = Object.keys(LOCALES);
22
15
  const WEEK_STARTS = ["sunday", "monday"];
23
16
  const HIGHLIGHT_STYLES = ["bracket", "reverse"];
17
+ const _require = createRequire(import.meta.url);
18
+ /** package.json からバージョンを取得する */
19
+ function getVersion() {
20
+ return _require("../package.json").version;
21
+ }
22
+ /**
23
+ * CLI フラグ・環境変数・TTY 状態から最終的な color フラグを解決する。
24
+ * 優先順位: --no-color > --color > NO_COLOR > FORCE_COLOR > TTY
25
+ */
26
+ function resolveColor(colorFlag, noColorFlag, env, isTTY) {
27
+ if (noColorFlag) return false;
28
+ if (colorFlag) return true;
29
+ if (env.NO_COLOR) return false;
30
+ if (env.FORCE_COLOR) return true;
31
+ return isTTY;
32
+ }
24
33
  /** 値を一つ取るオプションと、代入先のフィールド名 */
25
34
  const VALUE_OPTIONS = {
26
35
  "--theme": "theme",
@@ -36,7 +45,7 @@ function parseDate(value) {
36
45
  const year = Number(match[1]);
37
46
  const month = Number(match[2]);
38
47
  const day = Number(match[3]);
39
- if (year < 1 || month < 1 || month > 12 || day < 1 || day > 31) return null;
48
+ if (year < MIN_YEAR || year > MAX_YEAR || month < 1 || month > 12 || day < 1 || day > 31) return null;
40
49
  const date = createDate(year, month - 1, day);
41
50
  if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return null;
42
51
  return date;
@@ -56,10 +65,22 @@ function parseArgs(args) {
56
65
  args: result,
57
66
  help: true
58
67
  };
68
+ if (arg === "-v" || arg === "--version") return {
69
+ args: result,
70
+ version: true
71
+ };
59
72
  if (arg === "--color") {
60
73
  result.color = true;
61
74
  continue;
62
75
  }
76
+ if (arg === "--no-color") {
77
+ result.noColor = true;
78
+ continue;
79
+ }
80
+ if (arg === "--year") {
81
+ result.yearView = true;
82
+ continue;
83
+ }
63
84
  if (arg === "--highlight") {
64
85
  const value = args[++i];
65
86
  if (value === void 0) return error("Missing value for option: --highlight");
@@ -68,6 +89,28 @@ function parseArgs(args) {
68
89
  result.highlight = parsed;
69
90
  continue;
70
91
  }
92
+ if (arg === "--today") {
93
+ const value = args[++i];
94
+ if (value === void 0) return error("Missing value for option: --today");
95
+ const parsed = parseDate(value);
96
+ if (parsed === null) return error(`Invalid --today date: "${value}" (expected YYYY-MM-DD, e.g. 2026-09-08)`);
97
+ result.today = parsed;
98
+ continue;
99
+ }
100
+ if (arg === "--range") {
101
+ const fromStr = args[++i];
102
+ const toStr = args[++i];
103
+ if (fromStr === void 0 || toStr === void 0) return error("--range requires two dates (YYYY-MM-DD), e.g. --range 2026-01-01 2026-03-31");
104
+ const from = parseDate(fromStr);
105
+ const to = parseDate(toStr);
106
+ if (from === null || to === null) return error("Invalid --range date (expected YYYY-MM-DD)");
107
+ if (from.getTime() > to.getTime()) return error("--range: from date must not be after to date");
108
+ result.range = {
109
+ from,
110
+ to
111
+ };
112
+ continue;
113
+ }
71
114
  const key = VALUE_OPTIONS[arg];
72
115
  if (key !== void 0) {
73
116
  const value = args[++i];
@@ -82,7 +125,7 @@ function parseArgs(args) {
82
125
  else if (result.month === void 0) result.month = Number(arg);
83
126
  else return error(`Too many arguments: "${arg}"`);
84
127
  }
85
- if (result.year !== void 0 && (result.year < 1 || result.year > 9999)) return error(`Invalid year: ${result.year} (expected 1–9999)`);
128
+ if (result.year !== void 0 && (result.year < MIN_YEAR || result.year > MAX_YEAR)) return error(`Invalid year: ${result.year} (expected ${MIN_YEAR}–${MAX_YEAR})`);
86
129
  if (result.month !== void 0 && (result.month < 1 || result.month > 12)) return error(`Invalid month: ${result.month} (expected 1–12)`);
87
130
  const choiceTable = [
88
131
  [
@@ -97,7 +140,7 @@ function parseArgs(args) {
97
140
  ],
98
141
  [
99
142
  result.locale,
100
- LOCALES,
143
+ LOCALE_LIST,
101
144
  "locale"
102
145
  ],
103
146
  [
@@ -112,6 +155,9 @@ function parseArgs(args) {
112
155
  ]
113
156
  ];
114
157
  for (const [value, choices, name] of choiceTable) if (value !== void 0 && !choices.includes(value)) return error(`Invalid ${name}: "${value}" (expected: ${choices.join(" | ")})`);
158
+ if (result.yearView && result.range) return error("--year and --range cannot be used together");
159
+ if (result.yearView && result.month !== void 0) return error("Month cannot be used with --year (use --year YYYY instead)");
160
+ if (result.range && (result.year !== void 0 || result.month !== void 0)) return error("Positional arguments cannot be used with --range");
115
161
  return { args: result };
116
162
  }
117
163
  function printUsage() {
@@ -120,20 +166,33 @@ function printUsage() {
120
166
  typescript-calendar-lib Render the current month
121
167
  typescript-calendar-lib 2026 Render the current month of 2026
122
168
  typescript-calendar-lib 2026 9 Render September 2026
169
+ typescript-calendar-lib --year Render the current year (4×3 grid)
170
+ typescript-calendar-lib 2026 --year Render 2026 as a year grid
171
+ typescript-calendar-lib --range 2026-01-01 2026-03-31
172
+ Render months from Jan to Mar 2026
123
173
 
124
174
  Options:
125
175
  --theme <name> Look: default | modern (default: default)
126
176
  --color-scheme <name> Colors: default | ocean | forest | sunset | mono
127
- --color Enable ANSI colors
128
- --locale <lang> Language: en | ja | es | de | fr | ko | zh (default: en)
177
+ --color Enable ANSI colors (auto-detected for TTY)
178
+ --no-color Disable ANSI colors
179
+ --locale <lang> Language: ${LOCALE_LIST.join(" | ")} (default: en)
129
180
  --week-start <day> First weekday: sunday | monday (default: sunday)
130
181
  --highlight <YYYY-MM-DD> Highlight a date (e.g. 2026-09-08)
131
182
  --highlight-style <style> Highlight style: bracket | reverse (default: bracket)
183
+ --today <YYYY-MM-DD> Override today (marks the date, defaults year/month)
184
+ --year Render the whole year as a 4×3 grid
185
+ --range <FROM> <TO> Render months from FROM to TO (YYYY-MM-DD)
186
+ -v, --version Show version
132
187
  -h, --help Show this help
133
188
  `;
134
189
  }
135
190
  if (import.meta.main) {
136
- const { args, error, help } = parseArgs(process.argv.slice(2));
191
+ const { args, error, help, version } = parseArgs(process.argv.slice(2));
192
+ if (version) {
193
+ console.log(getVersion());
194
+ process.exit(0);
195
+ }
137
196
  if (help) {
138
197
  console.log(printUsage());
139
198
  process.exit(0);
@@ -143,22 +202,38 @@ if (import.meta.main) {
143
202
  console.error(printUsage());
144
203
  process.exit(1);
145
204
  }
146
- const now = /* @__PURE__ */ new Date();
205
+ const color = resolveColor(args.color, args.noColor, process.env, process.stdout.isTTY === true);
206
+ const now = args.today ?? /* @__PURE__ */ new Date();
147
207
  const year = args.year ?? now.getFullYear();
148
208
  const month = args.month ?? now.getMonth() + 1;
149
- console.log(calendar({
150
- year,
151
- month,
209
+ const common = {
152
210
  theme: args.theme,
153
211
  colorScheme: args.colorScheme,
154
- color: args.color,
212
+ color,
155
213
  locale: args.locale,
156
214
  weekStart: args.weekStart,
157
215
  highlight: args.highlight,
158
- highlightStyle: args.highlightStyle
159
- }));
216
+ highlightStyle: args.highlightStyle,
217
+ today: args.today
218
+ };
219
+ let output;
220
+ if (args.range) output = calendarRange({
221
+ ...common,
222
+ from: args.range.from,
223
+ to: args.range.to
224
+ });
225
+ else if (args.yearView) output = calendarYear({
226
+ ...common,
227
+ year
228
+ });
229
+ else output = calendar({
230
+ ...common,
231
+ year,
232
+ month
233
+ });
234
+ console.log(output);
160
235
  }
161
236
  //#endregion
162
- export { parseArgs, parseDate, printUsage };
237
+ export { getVersion, parseArgs, parseDate, printUsage, resolveColor };
163
238
 
164
239
  //# sourceMappingURL=bin.js.map
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env bun\nimport type {\n HighlightStyle,\n Locale,\n WeekStart,\n} from \"@typescript-calendar-lib/core\";\nimport { createDate } from \"@typescript-calendar-lib/core\";\nimport { calendar } from \"./calendar.ts\";\nimport type { ColorSchemeName, ThemeName } from \"./theme.ts\";\n\nexport interface CliArgs {\n year?: number;\n month?: number;\n theme?: ThemeName;\n colorScheme?: ColorSchemeName;\n color?: boolean;\n locale?: Locale;\n weekStart?: WeekStart;\n highlight?: Date;\n highlightStyle?: HighlightStyle;\n}\n\nexport interface ParseResult {\n args: CliArgs;\n error?: string;\n help?: boolean;\n}\n\nconst THEMES: readonly ThemeName[] = [\"default\", \"modern\"];\nconst COLOR_SCHEMES: readonly ColorSchemeName[] = [\n \"default\",\n \"ocean\",\n \"forest\",\n \"sunset\",\n \"mono\",\n];\nconst LOCALES: readonly Locale[] = [\"en\", \"ja\", \"es\", \"de\", \"fr\", \"ko\", \"zh\"];\nconst WEEK_STARTS: readonly WeekStart[] = [\"sunday\", \"monday\"];\nconst HIGHLIGHT_STYLES: readonly HighlightStyle[] = [\"bracket\", \"reverse\"];\n\n/** 値を一つ取るオプションと、代入先のフィールド名 */\nconst VALUE_OPTIONS: Record<string, keyof CliArgs> = {\n \"--theme\": \"theme\",\n \"--color-scheme\": \"colorScheme\",\n \"--locale\": \"locale\",\n \"--week-start\": \"weekStart\",\n \"--highlight-style\": \"highlightStyle\",\n};\n\n/** YYYY-MM-DD 形式の日付文字列をパースする */\nexport function parseDate(value: string): Date | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value);\n if (!match) return null;\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n if (year < 1 || month < 1 || month > 12 || day < 1 || day > 31) {\n return null;\n }\n const date = createDate(year, month - 1, day);\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return null;\n }\n return date;\n}\n\n/**\n * CLI 引数をパースする。テスト可能なように副作用を分離している。\n */\nexport function parseArgs(args: readonly string[]): ParseResult {\n const result: CliArgs = {};\n const error = (message: string): ParseResult => ({\n args: result,\n error: message,\n });\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n\n if (arg === \"-h\" || arg === \"--help\") {\n return { args: result, help: true };\n }\n if (arg === \"--color\") {\n result.color = true;\n continue;\n }\n if (arg === \"--highlight\") {\n const value = args[++i];\n if (value === undefined) {\n return error(\"Missing value for option: --highlight\");\n }\n const parsed = parseDate(value);\n if (parsed === null) {\n return error(\n `Invalid --highlight date: \"${value}\" (expected YYYY-MM-DD, e.g. 2026-09-08)`,\n );\n }\n result.highlight = parsed;\n continue;\n }\n\n const key = VALUE_OPTIONS[arg];\n if (key !== undefined) {\n const value = args[++i];\n if (value === undefined) {\n return error(`Missing value for option: ${arg}`);\n }\n (result as Record<string, unknown>)[key] = value;\n continue;\n }\n\n const numeric = /^-?\\d+$/.test(arg);\n if (arg.startsWith(\"-\") && !numeric) {\n return error(`Unknown option: ${arg}`);\n }\n if (!numeric) {\n return error(\n `Invalid argument: \"${arg}\" (expected a year or month number)`,\n );\n }\n if (result.year === undefined) {\n result.year = Number(arg);\n } else if (result.month === undefined) {\n result.month = Number(arg);\n } else {\n return error(`Too many arguments: \"${arg}\"`);\n }\n }\n\n // 値のバリデーション\n if (result.year !== undefined && (result.year < 1 || result.year > 9999)) {\n return error(`Invalid year: ${result.year} (expected 1–9999)`);\n }\n if (result.month !== undefined && (result.month < 1 || result.month > 12)) {\n return error(`Invalid month: ${result.month} (expected 1–12)`);\n }\n\n const choiceTable: Array<[string | undefined, readonly string[], string]> = [\n [result.theme, THEMES, \"theme\"],\n [result.colorScheme, COLOR_SCHEMES, \"color-scheme\"],\n [result.locale, LOCALES, \"locale\"],\n [result.weekStart, WEEK_STARTS, \"week-start\"],\n [result.highlightStyle, HIGHLIGHT_STYLES, \"highlight-style\"],\n ];\n for (const [value, choices, name] of choiceTable) {\n if (value !== undefined && !choices.includes(value)) {\n return error(\n `Invalid ${name}: \"${value}\" (expected: ${choices.join(\" | \")})`,\n );\n }\n }\n\n return { args: result };\n}\n\nexport function printUsage(): string {\n return `Usage: typescript-calendar-lib [YYYY] [MM] [options]\n\n typescript-calendar-lib Render the current month\n typescript-calendar-lib 2026 Render the current month of 2026\n typescript-calendar-lib 2026 9 Render September 2026\n\nOptions:\n --theme <name> Look: default | modern (default: default)\n --color-scheme <name> Colors: default | ocean | forest | sunset | mono\n --color Enable ANSI colors\n --locale <lang> Language: en | ja | es | de | fr | ko | zh (default: en)\n --week-start <day> First weekday: sunday | monday (default: sunday)\n --highlight <YYYY-MM-DD> Highlight a date (e.g. 2026-09-08)\n --highlight-style <style> Highlight style: bracket | reverse (default: bracket)\n -h, --help Show this help\n`;\n}\n\nif (import.meta.main) {\n const { args, error, help } = parseArgs(process.argv.slice(2));\n\n if (help) {\n console.log(printUsage());\n process.exit(0);\n }\n if (error) {\n console.error(`Error: ${error}`);\n console.error(printUsage());\n process.exit(1);\n }\n\n const now = new Date();\n const year = args.year ?? now.getFullYear();\n const month = args.month ?? now.getMonth() + 1;\n\n console.log(\n calendar({\n year,\n month,\n theme: args.theme,\n colorScheme: args.colorScheme,\n color: args.color,\n locale: args.locale,\n weekStart: args.weekStart,\n highlight: args.highlight,\n highlightStyle: args.highlightStyle,\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createRequire } from \"node:module\";\nimport type {\n HighlightStyle,\n Locale,\n WeekStart,\n} from \"@typescript-calendar-lib/core\";\nimport {\n createDate,\n LOCALES,\n MAX_YEAR,\n MIN_YEAR,\n} from \"@typescript-calendar-lib/core\";\nimport { calendar, calendarRange, calendarYear } from \"./calendar.ts\";\nimport type { ColorSchemeName, ThemeName } from \"./theme.ts\";\n\nexport interface CliArgs {\n year?: number;\n month?: number;\n theme?: ThemeName;\n colorScheme?: ColorSchemeName;\n color?: boolean;\n noColor?: boolean;\n locale?: Locale;\n weekStart?: WeekStart;\n highlight?: Date;\n highlightStyle?: HighlightStyle;\n today?: Date;\n yearView?: boolean;\n range?: { from: Date; to: Date };\n}\n\nexport interface ParseResult {\n args: CliArgs;\n error?: string;\n help?: boolean;\n version?: boolean;\n}\n\nconst THEMES: readonly ThemeName[] = [\"default\", \"modern\"];\nconst COLOR_SCHEMES: readonly ColorSchemeName[] = [\n \"default\",\n \"ocean\",\n \"forest\",\n \"sunset\",\n \"mono\",\n];\nconst LOCALE_LIST: readonly string[] = Object.keys(LOCALES);\nconst WEEK_STARTS: readonly WeekStart[] = [\"sunday\", \"monday\"];\nconst HIGHLIGHT_STYLES: readonly HighlightStyle[] = [\"bracket\", \"reverse\"];\n\nconst _require = createRequire(import.meta.url);\n\n/** package.json からバージョンを取得する */\nexport function getVersion(): string {\n return (_require(\"../package.json\") as { version: string }).version;\n}\n\n/**\n * CLI フラグ・環境変数・TTY 状態から最終的な color フラグを解決する。\n * 優先順位: --no-color > --color > NO_COLOR > FORCE_COLOR > TTY\n */\nexport function resolveColor(\n colorFlag: boolean | undefined,\n noColorFlag: boolean | undefined,\n env: Record<string, string | undefined>,\n isTTY: boolean,\n): boolean {\n if (noColorFlag) return false;\n if (colorFlag) return true;\n if (env.NO_COLOR) return false;\n if (env.FORCE_COLOR) return true;\n return isTTY;\n}\n\n/** 値を一つ取るオプションと、代入先のフィールド名 */\nconst VALUE_OPTIONS: Record<string, keyof CliArgs> = {\n \"--theme\": \"theme\",\n \"--color-scheme\": \"colorScheme\",\n \"--locale\": \"locale\",\n \"--week-start\": \"weekStart\",\n \"--highlight-style\": \"highlightStyle\",\n};\n\n/** YYYY-MM-DD 形式の日付文字列をパースする */\nexport function parseDate(value: string): Date | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value);\n if (!match) return null;\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n if (\n year < MIN_YEAR ||\n year > MAX_YEAR ||\n month < 1 ||\n month > 12 ||\n day < 1 ||\n day > 31\n ) {\n return null;\n }\n const date = createDate(year, month - 1, day);\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return null;\n }\n return date;\n}\n\n/**\n * CLI 引数をパースする。テスト可能なように副作用を分離している。\n */\nexport function parseArgs(args: readonly string[]): ParseResult {\n const result: CliArgs = {};\n const error = (message: string): ParseResult => ({\n args: result,\n error: message,\n });\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n\n if (arg === \"-h\" || arg === \"--help\") {\n return { args: result, help: true };\n }\n if (arg === \"-v\" || arg === \"--version\") {\n return { args: result, version: true };\n }\n if (arg === \"--color\") {\n result.color = true;\n continue;\n }\n if (arg === \"--no-color\") {\n result.noColor = true;\n continue;\n }\n if (arg === \"--year\") {\n result.yearView = true;\n continue;\n }\n if (arg === \"--highlight\") {\n const value = args[++i];\n if (value === undefined) {\n return error(\"Missing value for option: --highlight\");\n }\n const parsed = parseDate(value);\n if (parsed === null) {\n return error(\n `Invalid --highlight date: \"${value}\" (expected YYYY-MM-DD, e.g. 2026-09-08)`,\n );\n }\n result.highlight = parsed;\n continue;\n }\n if (arg === \"--today\") {\n const value = args[++i];\n if (value === undefined) {\n return error(\"Missing value for option: --today\");\n }\n const parsed = parseDate(value);\n if (parsed === null) {\n return error(\n `Invalid --today date: \"${value}\" (expected YYYY-MM-DD, e.g. 2026-09-08)`,\n );\n }\n result.today = parsed;\n continue;\n }\n if (arg === \"--range\") {\n const fromStr = args[++i];\n const toStr = args[++i];\n if (fromStr === undefined || toStr === undefined) {\n return error(\n \"--range requires two dates (YYYY-MM-DD), e.g. --range 2026-01-01 2026-03-31\",\n );\n }\n const from = parseDate(fromStr);\n const to = parseDate(toStr);\n if (from === null || to === null) {\n return error(\"Invalid --range date (expected YYYY-MM-DD)\");\n }\n if (from.getTime() > to.getTime()) {\n return error(\"--range: from date must not be after to date\");\n }\n result.range = { from, to };\n continue;\n }\n\n const key = VALUE_OPTIONS[arg];\n if (key !== undefined) {\n const value = args[++i];\n if (value === undefined) {\n return error(`Missing value for option: ${arg}`);\n }\n (result as Record<string, unknown>)[key] = value;\n continue;\n }\n\n const numeric = /^-?\\d+$/.test(arg);\n if (arg.startsWith(\"-\") && !numeric) {\n return error(`Unknown option: ${arg}`);\n }\n if (!numeric) {\n return error(\n `Invalid argument: \"${arg}\" (expected a year or month number)`,\n );\n }\n if (result.year === undefined) {\n result.year = Number(arg);\n } else if (result.month === undefined) {\n result.month = Number(arg);\n } else {\n return error(`Too many arguments: \"${arg}\"`);\n }\n }\n\n // 値のバリデーション\n if (\n result.year !== undefined &&\n (result.year < MIN_YEAR || result.year > MAX_YEAR)\n ) {\n return error(\n `Invalid year: ${result.year} (expected ${MIN_YEAR}–${MAX_YEAR})`,\n );\n }\n if (result.month !== undefined && (result.month < 1 || result.month > 12)) {\n return error(`Invalid month: ${result.month} (expected 1–12)`);\n }\n\n const choiceTable: Array<[string | undefined, readonly string[], string]> = [\n [result.theme, THEMES, \"theme\"],\n [result.colorScheme, COLOR_SCHEMES, \"color-scheme\"],\n [result.locale, LOCALE_LIST, \"locale\"],\n [result.weekStart, WEEK_STARTS, \"week-start\"],\n [result.highlightStyle, HIGHLIGHT_STYLES, \"highlight-style\"],\n ];\n for (const [value, choices, name] of choiceTable) {\n if (value !== undefined && !choices.includes(value)) {\n return error(\n `Invalid ${name}: \"${value}\" (expected: ${choices.join(\" | \")})`,\n );\n }\n }\n\n // 相互排他チェック\n if (result.yearView && result.range) {\n return error(\"--year and --range cannot be used together\");\n }\n if (result.yearView && result.month !== undefined) {\n return error(\"Month cannot be used with --year (use --year YYYY instead)\");\n }\n if (\n result.range &&\n (result.year !== undefined || result.month !== undefined)\n ) {\n return error(\"Positional arguments cannot be used with --range\");\n }\n\n return { args: result };\n}\n\nexport function printUsage(): string {\n return `Usage: typescript-calendar-lib [YYYY] [MM] [options]\n\n typescript-calendar-lib Render the current month\n typescript-calendar-lib 2026 Render the current month of 2026\n typescript-calendar-lib 2026 9 Render September 2026\n typescript-calendar-lib --year Render the current year (4×3 grid)\n typescript-calendar-lib 2026 --year Render 2026 as a year grid\n typescript-calendar-lib --range 2026-01-01 2026-03-31\n Render months from Jan to Mar 2026\n\nOptions:\n --theme <name> Look: default | modern (default: default)\n --color-scheme <name> Colors: default | ocean | forest | sunset | mono\n --color Enable ANSI colors (auto-detected for TTY)\n --no-color Disable ANSI colors\n --locale <lang> Language: ${LOCALE_LIST.join(\" | \")} (default: en)\n --week-start <day> First weekday: sunday | monday (default: sunday)\n --highlight <YYYY-MM-DD> Highlight a date (e.g. 2026-09-08)\n --highlight-style <style> Highlight style: bracket | reverse (default: bracket)\n --today <YYYY-MM-DD> Override today (marks the date, defaults year/month)\n --year Render the whole year as a 4×3 grid\n --range <FROM> <TO> Render months from FROM to TO (YYYY-MM-DD)\n -v, --version Show version\n -h, --help Show this help\n`;\n}\n\nif (import.meta.main) {\n const { args, error, help, version } = parseArgs(process.argv.slice(2));\n\n if (version) {\n console.log(getVersion());\n process.exit(0);\n }\n if (help) {\n console.log(printUsage());\n process.exit(0);\n }\n if (error) {\n console.error(`Error: ${error}`);\n console.error(printUsage());\n process.exit(1);\n }\n\n const color = resolveColor(\n args.color,\n args.noColor,\n process.env,\n process.stdout.isTTY === true,\n );\n\n const now = args.today ?? new Date();\n const year = args.year ?? now.getFullYear();\n const month = args.month ?? now.getMonth() + 1;\n\n const common = {\n theme: args.theme,\n colorScheme: args.colorScheme,\n color,\n locale: args.locale,\n weekStart: args.weekStart,\n highlight: args.highlight,\n highlightStyle: args.highlightStyle,\n today: args.today,\n };\n\n let output: string;\n if (args.range) {\n output = calendarRange({\n ...common,\n from: args.range.from,\n to: args.range.to,\n });\n } else if (args.yearView) {\n output = calendarYear({ ...common, year });\n } else {\n output = calendar({ ...common, year, month });\n }\n\n console.log(output);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typescript-calendar-lib/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "typescript-calendar-lib": "./dist/bin.js"
@@ -22,7 +22,7 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@typescript-calendar-lib/core": "0.3.0"
25
+ "@typescript-calendar-lib/core": "0.4.2"
26
26
  },
27
27
  "scripts": {
28
28
  "build": "tsdown"