Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
custom: "https://softpeanut.github.io/csv-preflight/support.html"
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>CSV Preflight — local CSV and Shopify product import checker</title><meta name="description" content="Check CSV structure locally, with an optional Shopify product CSV preset for documented headers and values. No upload or signup."><link rel="canonical" href="https://softpeanut.github.io/csv-preflight/"><meta property="og:title" content="CSV Preflight — local CSV and Shopify product import checker"><meta property="og:description" content="Check generic CSV structure or a bounded set of documented Shopify product CSV rules without uploading your data."><meta property="og:url" content="https://softpeanut.github.io/csv-preflight/"><meta property="og:type" content="website"><meta name="twitter:card" content="summary"><link rel="icon" href="logo.svg" type="image/svg+xml"><link rel="stylesheet" href="styles.css"><script type="application/ld+json">{"@context":"https://schema.org","@type":"SoftwareApplication","name":"CSV Preflight","url":"https://softpeanut.github.io/csv-preflight/","applicationCategory":"DeveloperApplication","operatingSystem":"Any","description":"Check generic CSV structure or a bounded set of documented Shopify product CSV rules locally without uploading files.","isAccessibleForFree":true,"offers":{"@type":"Offer","price":"0","priceCurrency":"USD"}}</script></head>
<body><main><p><a href="article.html">Read: CSV Is a State Machine</a> · <a href="case-study.html">Checkable example</a> · <a href="csv-ci-case-study.html">Public CI case study</a> · <a href="ko.html" lang="ko">한국어 서비스</a></p><header><span class="eyebrow">LOCAL-ONLY CSV CHECK</span><h1>Catch import failures<br>before your importer does.</h1><p>Drop or paste CSV. Nothing leaves your browser.</p></header>
<body><main><p><a href="article.html">Read: CSV Is a State Machine</a> · <a href="case-study.html">Checkable example</a> · <a href="csv-ci-case-study.html">Public CI case study</a> · <a href="support.html">Support the project</a> · <a href="ko.html" lang="ko">한국어 서비스</a></p><header><span class="eyebrow">LOCAL-ONLY CSV CHECK</span><h1>Catch import failures<br>before your importer does.</h1><p>Drop or paste CSV. Nothing leaves your browser.</p></header>
<aside class="tip"><div><strong>Did the free checker save you time?</strong><span>An optional Lightning tip buys no cleanup, support, feature, or import guarantee. It is separate from the fixed-scope service.</span></div><a href="lightning:softpeanut@stacker.news">Tip 2+ sats · softpeanut@stacker.news</a></aside>
<section id="drop" class="card drop"><input id="file" type="file" accept=".csv,text/csv"><label for="file"><strong>Drop a CSV here</strong><span>or choose a file</span></label><div class="or">OR PASTE</div><textarea id="input" placeholder="email,name&#10;ada@example.com,Ada"></textarea><div class="profile"><label for="profile">Validation profile</label><select id="profile"><option value="generic">Generic CSV structure</option><option value="shopify:create">Shopify — new products</option><option value="shopify:update">Shopify — update products</option></select><small>Shopify preset reviewed against the <a href="https://help.shopify.com/en/manual/products/import-export/using-csv" target="_blank" rel="noopener">official product CSV guide</a> on 2026-08-27. It checks a bounded set of documented rules and does not guarantee import success.</small></div><button id="check">Run preflight</button></section>
<section id="results" class="card" hidden><div class="summary"><div><small>ENCODING</small><strong id="encoding">Pasted text</strong></div><div><small>DELIMITER</small><strong id="delimiter">Comma</strong></div><div><small>ROWS</small><strong id="rows">0</strong></div><div><small>ISSUES</small><strong id="count">0</strong></div></div><h2>Preflight report</h2><ul id="issues"></ul><div class="actions"><button id="csvDownload">Download cleaned CSV</button><button id="reportDownload" class="secondary">Download error report</button></div></section>
Expand Down
9 changes: 9 additions & 0 deletions offer.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const githubActionGuide = readFileSync(new URL("./validate-csv-github-actions.ht
const ciSetupTerms = readFileSync(new URL("./ci-setup-terms.html", import.meta.url), "utf8");
const ciSetupTermsZhCn = readFileSync(new URL("./ci-setup-terms-zh-CN.html", import.meta.url), "utf8");
const ciSetupTemplate = readFileSync(new URL("./.github/ISSUE_TEMPLATE/ci-setup.yml", import.meta.url), "utf8");
const supportPage = readFileSync(new URL("./support.html", import.meta.url), "utf8");
const funding = readFileSync(new URL("./.github/FUNDING.yml", import.meta.url), "utf8");
import { analyze, serializeCsv } from "./csv.mjs";

test("presents a bounded service without pretending payment or booking is live", () => {
Expand Down Expand Up @@ -85,6 +87,12 @@ test("optional tips cannot be mistaken for service payment", () => {
assert.match(koreanPage, /2 sats 이상 팁/);
assert.match(koreanPage, /정리 작업·지원·기능·가져오기 성공을 구매하지 않습니다/);
assert.match(koreanPage, /고정 범위 서비스와 별개입니다/);
assert.match(page, /support\.html/);
assert.match(supportPage, /lightning:softpeanut@stacker\.news/);
assert.match(supportPage, /buys no product, cleanup, support, feature, priority, service, guarantee, or tax receipt/);
assert.match(supportPage, /Do not send CSV data, credentials, contact details, or payment proof/);
assert.match(supportPage, /If you intend to buy a product or service, do not use this link/);
assert.equal(funding.trim(), 'custom: "https://softpeanut.github.io/csv-preflight/support.html"');
});

test("offers only the completed bounded offline batch product", () => {
Expand Down Expand Up @@ -214,6 +222,7 @@ test("publishes truthful search metadata for every public page", () => {
"https://softpeanut.github.io/csv-preflight/validate-csv-github-actions.html",
"https://softpeanut.github.io/csv-preflight/ci-setup-terms.html",
"https://softpeanut.github.io/csv-preflight/ci-setup-terms-zh-CN.html",
"https://softpeanut.github.io/csv-preflight/support.html",
]) {
assert.match(sitemap, new RegExp(`<loc>${location.replaceAll(".", "\\.")}</loc>`));
}
Expand Down
4 changes: 4 additions & 0 deletions sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@
<loc>https://softpeanut.github.io/csv-preflight/ci-setup-terms-zh-CN.html</loc>
<lastmod>2026-08-27</lastmod>
</url>
<url>
<loc>https://softpeanut.github.io/csv-preflight/support.html</loc>
<lastmod>2026-08-28</lastmod>
</url>
</urlset>
28 changes: 28 additions & 0 deletions support.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Support CSV Preflight</title>
<meta name="description" content="Voluntarily support the free CSV Preflight project with a Lightning tip.">
<link rel="canonical" href="https://softpeanut.github.io/csv-preflight/support.html">
<link rel="icon" href="logo.svg" type="image/svg+xml">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main>
<p><a href="./">← CSV Preflight</a></p>
<header>
<span class="eyebrow">VOLUNTARY OPEN-SOURCE SUPPORT</span>
<h1>Keep the free checker free.</h1>
<p>CSV Preflight runs without uploads, accounts, analytics, or subscriptions.</p>
</header>
<section class="card">
<h2>Lightning tip</h2>
<p><a href="lightning:softpeanut@stacker.news">softpeanut@stacker.news</a></p>
<p>This is an optional donation to support the open-source project. It buys no product, cleanup, support, feature, priority, service, guarantee, or tax receipt. Do not send CSV data, credentials, contact details, or payment proof.</p>
<p>There is no refund process for voluntary tips. If you intend to buy a product or service, do not use this link.</p>
</section>
</main>
</body>
</html>
Loading