diff --git a/cli/csv-runner.ts b/cli/csv-runner.ts index eabe33f..4f6a07c 100644 --- a/cli/csv-runner.ts +++ b/cli/csv-runner.ts @@ -33,16 +33,18 @@ export async function runCsvPipeline( return runPipeline(pending, { ...opts, - commitSuccess: opts.noSkipMarker ? async ({ lineIndex }) => { - const skip = await markSkipped(doc, lineIndex); - if (skip.ok) { - doc = skip.value; - } else { - console.error( - ` ${symbols.warn} failed to mark line ${dim(`${lineIndex}`)} as skipped: ${dim(describe(skip.error))}`, - ); + commitSuccess: opts.noSkipMarker + ? async ({ lineIndex }) => { + const skip = await markSkipped(doc, lineIndex); + if (skip.ok) { + doc = skip.value; + } else { + console.error( + ` ${symbols.warn} failed to mark line ${dim(`${lineIndex}`)} as skipped: ${dim(describe(skip.error))}`, + ); + } + return skip; } - return skip; - } : void 0, + : void 0, }); } diff --git a/commands/import.ts b/commands/import.ts index b21e8c0..35894fa 100644 --- a/commands/import.ts +++ b/commands/import.ts @@ -27,11 +27,11 @@ export async function executeImportCommand(args: string[] = Deno.args): Promise< alias: { n: "dry-run", h: "help", - s: "no-skip-marker" + s: "no-skip-marker", }, default: { "dry-run": false, - "no-skip-marker": false + "no-skip-marker": false, }, }); @@ -54,7 +54,7 @@ export async function executeImportCommand(args: string[] = Deno.args): Promise< const opts: PipelineOptions = { config: session.value, dryRun: flags["dry-run"], - noSkipMarker: flags["no-skip-marker"] + noSkipMarker: flags["no-skip-marker"], }; try { diff --git a/deno.lock b/deno.lock index 6e4ec77..60d8aa7 100644 --- a/deno.lock +++ b/deno.lock @@ -1,6 +1,7 @@ { "version": "5", "specifiers": { + "jsr:@std/assert@1.0.16": "1.0.16", "jsr:@std/assert@1.0.19": "1.0.19", "jsr:@std/cli@^1.0.29": "1.0.29", "jsr:@std/crypto@^1.1.0": "1.1.0", @@ -11,6 +12,12 @@ "jsr:@std/path@^1.1.4": "1.1.4" }, "jsr": { + "@std/assert@1.0.16": { + "integrity": "6a7272ed1eaa77defe76e5ff63ca705d9c495077e2d5fd0126d2b53fc5bd6532", + "dependencies": [ + "jsr:@std/internal@^1.0.12" + ] + }, "@std/assert@1.0.19": { "integrity": "eaada96ee120cb980bc47e040f82814d786fe8162ecc53c91d8df60b8755991e", "dependencies": [ diff --git a/lib/errors.ts b/lib/errors.ts index 4a047c9..7248add 100644 --- a/lib/errors.ts +++ b/lib/errors.ts @@ -80,7 +80,12 @@ export const Errors = { config: (tag: ConfigErrorReason, message: string): ConfigError => ({ kind: "config", tag, message }), - csv: (tag: CsvErrorReason, message: string, path?: string | undefined): CsvError => ({ kind: "csv", tag, message, path }), + csv: (tag: CsvErrorReason, message: string, path?: string | undefined): CsvError => ({ + kind: "csv", + tag, + message, + path, + }), auth: (message: string): AuthError => ({ kind: "auth", message }), diff --git a/lib/format/csv/codec.ts b/lib/format/csv/codec.ts index 4d57755..e9f3112 100644 --- a/lib/format/csv/codec.ts +++ b/lib/format/csv/codec.ts @@ -1,9 +1,11 @@ import { Errors } from "~/lib/errors.ts"; -import { CSV_HEADER, type DocumentTrack } from "~/lib/format/csv/mod.ts"; +import { columnFields, type DocumentTrack } from "~/lib/format/csv/mod.ts"; import { Fail, Ok, Result } from "~/lib/result.ts"; type ParseError = ReturnType; +type ColumnIndices = Record<(typeof columnFields)[number], number>; + // https://www.rfc-editor.org/rfc/rfc4180.html export function split(line: string): string[] { const fields: string[] = []; @@ -54,7 +56,7 @@ export function parseTrack( line: string, lineIndex: number, path: string, - header?: Record, + header?: ColumnIndices, ): Result { if (line === serializeHeader()) { return Fail(Errors.csv("invalid_columns", "header row", path)); @@ -82,11 +84,11 @@ export function parseTrack( } return Ok({ - artist: unescape(fields[header["artist"]]), - albumArtist: unescape(fields[header["album_artist"]] ?? ""), - album: unescape(fields[header["album"]] ?? ""), - title: unescape(fields[header["title"]]), - date: unescape(fields[header["date"]] ?? ""), + artist: unescape(fields[header.artist]), + albumArtist: unescape(fields[header.album_artist] ?? ""), + album: unescape(fields[header.album] ?? ""), + title: unescape(fields[header.title]), + date: unescape(fields[header.date] ?? ""), }); } @@ -95,20 +97,21 @@ export function serializeTrack(track: DocumentTrack): string { } export function serializeHeader(): string { - return CSV_HEADER.join(","); + return columnFields.join(","); } -export function getColumnIndices(line: string): Result, ParseError> { +export function getColumnIndices(line: string): Result { const fields = split(line); const returns: Record = {}; + const requiredFields = ["artist", "title"]; - CSV_HEADER.forEach((currentValue: string) => { + columnFields.forEach((val) => { for (let i = 0; i < fields.length; i++) { const field = fields[i]; - if (currentValue === field) { - returns[currentValue] = i; + if (val === field) { + returns[val] = i; break; } } @@ -123,5 +126,5 @@ export function getColumnIndices(line: string): Result, P } } - return Ok(returns); + return Ok(returns as ColumnIndices); } diff --git a/lib/format/csv/io.ts b/lib/format/csv/io.ts index ef3cf2b..70d5416 100644 --- a/lib/format/csv/io.ts +++ b/lib/format/csv/io.ts @@ -19,11 +19,11 @@ export async function loadCsvDocument(path: string): Promise