| 179 | }; |
| 180 | |
| 181 | const parseCliArgs = (argv: string[]): ParsedOptions | null => { |
| 182 | if (argv.length === 0 || argv.includes('-h') || argv.includes('--help')) { |
| 183 | return null; |
| 184 | } |
| 185 | |
| 186 | let commandArg = argv[0]; |
| 187 | if (commandArg.startsWith('--')) { |
| 188 | commandArg = commandArg.slice(2); |
| 189 | } |
| 190 | if (commandArg !== 'riff' && commandArg !== 'chord' && commandArg !== 'arp') { |
| 191 | throw new TypeError( |
| 192 | `First argument must be riff/chord/arp (or --riff/--chord/--arp), received "${argv[0]}"` |
| 193 | ); |
| 194 | } |
| 195 | |
| 196 | const positionals: string[] = []; |
| 197 | const options: ParsedOptions = { |
| 198 | command: commandArg, |
| 199 | positionals, |
| 200 | outfile: 'music.mid', |
| 201 | fitPattern: true, |
| 202 | }; |
| 203 | |
| 204 | let i = 1; |
| 205 | while (i < argv.length) { |
| 206 | const token = argv[i]; |
| 207 | if (!token.startsWith('--')) { |
| 208 | positionals.push(token); |
| 209 | i++; |
| 210 | continue; |
| 211 | } |
| 212 | |
| 213 | if (token === '--outfile') { |
| 214 | options.outfile = argv[i + 1]; |
| 215 | i += 2; |
| 216 | continue; |
| 217 | } |
| 218 | |
| 219 | if (token === '--bpm') { |
| 220 | options.bpm = Number(argv[i + 1]); |
| 221 | i += 2; |
| 222 | continue; |
| 223 | } |
| 224 | |
| 225 | if (token === '--subdiv') { |
| 226 | options.subdiv = argv[i + 1]; |
| 227 | i += 2; |
| 228 | continue; |
| 229 | } |
| 230 | |
| 231 | if (token === '--sizzle') { |
| 232 | const styleOrNum = argv[i + 1]; |
| 233 | const maybeNum = argv[i + 2]; |
| 234 | if (!styleOrNum || styleOrNum.startsWith('--')) { |
| 235 | options.sizzle = true; |
| 236 | i += 1; |
| 237 | continue; |
| 238 | } |