diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fa4f746 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Beomjin Kim + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index f2e5e94..397c6d6 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,18 @@ Open `http://localhost:8080/experiments/csv-preflight/` when serving from the re ### Free command-line check Node.js 20 or newer can run the same generic structural preflight on one local file without a -browser or dependency install: +browser. The repository copy works without an install: ```sh node cli.mjs input.csv --output normalized.csv --report issues.csv ``` +Version 0.6.0 prepares the same command for npm publication: + +```sh +npx csv-preflight input.csv --output normalized.csv --report issues.csv +``` + The free CLI returns exit 0 for a clean file, 1 for reported issues or rejected input, and 2 for an invocation/runtime error. It accepts UTF-8 input up to 10 MiB and refuses to overwrite the input or an existing output. It does not include the Pro archive's batch, Shopify-profile, ZIP, or JSON diff --git a/a75acc2ed5874b344f9f70acb44713d4.txt b/a75acc2ed5874b344f9f70acb44713d4.txt new file mode 100644 index 0000000..45b5032 --- /dev/null +++ b/a75acc2ed5874b344f9f70acb44713d4.txt @@ -0,0 +1 @@ +a75acc2ed5874b344f9f70acb44713d4 diff --git a/cli.mjs b/cli.mjs index e2a43d1..d3d4ad7 100644 --- a/cli.mjs +++ b/cli.mjs @@ -148,10 +148,11 @@ export function runCli(argv, io = {}) { issues = [{ type: "encoding", row: null, detail: `${detected.encoding} is not supported; export as UTF-8` }]; } else { const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes.slice(detected.offset)); - const result = analyze(text); + const delimiter = guessDelimiter(text); + const result = analyze(text, delimiter); issues = result.issues; if (!issues.some(issue => issue.type === "parse" || issue.type === "empty")) { - normalized = new TextEncoder().encode(`\uFEFF${serializeCsv(result.cleanRows)}`); + normalized = new TextEncoder().encode(`\uFEFF${serializeCsv(result.cleanRows, delimiter)}`); } } const targets = normalized ? [config.output, config.report] : [config.report]; diff --git a/cli.test.mjs b/cli.test.mjs index bea25d2..f93d6c6 100644 --- a/cli.test.mjs +++ b/cli.test.mjs @@ -36,6 +36,19 @@ test("free CLI writes a clean normalized file and report", () => { assert.match(new TextDecoder().decode(writes[1].data), /type,row,detail/); }); +test("free CLI preserves the detected delimiter in normalized output", () => { + const writes = []; + const exit = runCli(["input.csv", "--output", "clean.csv", "--report", "report.csv"], { + readFile: () => bytes("name;price\nMug;12"), + outputExists: () => false, + writeFile: (file, data) => writes.push({ file, data }), + stdout: () => {}, + stderr: () => {}, + }); + assert.equal(exit, 0); + assert.match(new TextDecoder().decode(writes[0].data), /name;price\r\nMug;12/); +}); + test("free CLI reports warnings and withholds rejected output", () => { const warningWrites = []; const common = { outputExists: () => false, stdout: () => {}, stderr: () => {} }; diff --git a/package.json b/package.json index 47dbba9..23742de 100644 --- a/package.json +++ b/package.json @@ -1 +1,39 @@ -{"type":"module","scripts":{"test":"node --test","benchmark":"node benchmark.mjs","benchmark:record":"node benchmark.mjs --write"},"engines":{"node":"22.x"},"private":true} +{ + "name": "csv-preflight", + "version": "0.6.0", + "description": "Check one CSV for structural problems before import", + "type": "module", + "bin": { + "csv-preflight": "cli.mjs" + }, + "files": [ + "cli.mjs", + "LICENSE" + ], + "scripts": { + "test": "node --test", + "benchmark": "node benchmark.mjs", + "benchmark:record": "node benchmark.mjs --write", + "prepack": "npm test" + }, + "engines": { + "node": ">=20" + }, + "keywords": [ + "csv", + "validator", + "cli", + "data-quality", + "preflight" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/softpeanut/csv-preflight.git" + }, + "homepage": "https://softpeanut.github.io/csv-preflight/", + "bugs": "https://github.com/softpeanut/csv-preflight/issues", + "publishConfig": { + "access": "public" + } +}