Skip to content

Commit

Permalink
Fixes and adding examples
Browse files Browse the repository at this point in the history
  • Loading branch information
davetaz committed Nov 7, 2024
1 parent 903d3cb commit 6e695a1
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 55 deletions.
29 changes: 17 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ app.set('view engine', 'ejs');
app.use(cors());
app.use(express.static(__dirname + '/public')); // Public directory

app.use((req, res, next) => {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); // HTTP 1.1.
res.setHeader('Pragma', 'no-cache'); // HTTP 1.0.
res.setHeader('Expires', '0'); // Proxies.
next();
});

app.use((req, res, next) => {
// Read package.json file
fs.readFile(path.join(__dirname, 'package.json'), 'utf8', (err, data) => {
Expand Down Expand Up @@ -151,17 +158,16 @@ app.get('/validate', async (req, res) => {
}

// Collect dialect options from the query params
const dialect = {
delimiter: req.query.delimiter,
doubleQuote: req.query.doubleQuote === 'true',
lineTerminator: req.query.lineTerminator,
nullSequence: req.query.nullSequence,
quoteChar: req.query.quoteChar,
escapeChar: req.query.escapeChar,
skipInitialSpace: req.query.skipInitialSpace === 'true',
header: req.query.header === 'true',
caseSensitiveHeader: req.query.caseSensitiveHeader === 'true',
};
const dialect = {};
if (req.query.delimiter) dialect.delimiter = req.query.delimiter;
if (req.query.doubleQuote) dialect.doubleQuote = req.query.doubleQuote === 'true';
if (req.query.lineTerminator) dialect.lineTerminator = req.query.lineTerminator;
if (req.query.nullSequence) dialect.nullSequence = req.query.nullSequence;
if (req.query.quoteChar) dialect.quoteChar = req.query.quoteChar;
if (req.query.escapeChar) dialect.escapeChar = req.query.escapeChar;
if (req.query.skipInitialSpace) dialect.skipInitialSpace = req.query.skipInitialSpace === 'true';
if (req.query.header) dialect.header = req.query.header === 'true';
if (req.query.caseSensitiveHeader) dialect.caseSensitiveHeader = req.query.caseSensitiveHeader === 'true';

if (Object.keys(dialect).length > 0) {
form.append('dialect', JSON.stringify(dialect));
Expand Down Expand Up @@ -301,7 +307,6 @@ app.post('/validate', upload.fields([{ name: 'file' }, { name: 'schema' }]), asy
if (Object.keys(dialect).length > 0) {
form.append('dialect', JSON.stringify(dialect));
}

// Send the form data to the Ruby server
const response = await axios.post(CSVLINT_API, form, {
headers: form.getHeaders(),
Expand Down
34 changes: 34 additions & 0 deletions public/examples/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"title": "Student List",
"description": "A simple CSV file containing a list of students with their names and ages.",
"expectedResult": "This CSV should validate successfully without errors or warnings.",
"csvUrl": "https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students_perfect.csv",
"dialect": "",
"schemaUrl": ""
},
{
"title": "Mixed types",
"description": "A simple CSV file containing a list of students with their names and ages.",
"expectedResult": "This CSV should produce warnings due to data inconsistencies in the age column.",
"csvUrl": "https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students_warnings.csv",
"dialect": "",
"schemaUrl": ""
},
{
"title": "Pipe Separator",
"description": "A simple CSV file containing a list of students with their names and ages.",
"expectedResult": "This CSV is valid but the separator is a pipe character.",
"csvUrl": "https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students_pipe.txt",
"dialect": "delimiter=|",
"schemaUrl": ""
},
{
"title": "Schema validation",
"description": "Same file as in the first example, but this time the schema will throw errors.",
"expectedResult": "This CSV should be invalid based upon the schema.",
"csvUrl": "https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students_perfect.csv",
"dialect": "",
"schemaUrl": "https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/studentsSchema.json"
}
]
16 changes: 2 additions & 14 deletions views/about.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,11 @@

<p><img alt=":csv%20 %20warnings yellow" src="https://img.shields.io/badge/CSV-warnings-yellow.svg"></p>

<p>If you click on that you'll get a pop-up that gives you some code for embedding the badge in your page. You can put that next to some CSV and it means you and other people will be able to see whether the CSV is valid or not.</p>

<p>Wear your valid CSV badge with pride!</p>

<h3>Fix that CSV</h3>

<p>We can fix some of the errors that we find in CSV files, such as bad encodings. At the bottom of the page that shows you how to improve the file, you'll see a button that says <strong>Download Standardised CSV File</strong>.</p>

<p>That won't fix all the problems: we won't delete empty lines or try to fix up values that are in the wrong format. We can't change the way your server provides CSV either, so you'll still be warned if it's not using the right <code>Content-Type</code> header.</p>

<h3>Find a Schema</h3>

<p>The <a href="/schemas">Recent schemas</a> page gives a list of schemas that people have been using to validate their CSV files. See if there's a schema that you could use!</p>
<p>You can also see the embed code to allow you to embed the badge on your own website.</p>

<h3>Dialects</h3>

<img src="/assets/dialect-508ec8b540c5ceed651af6016387e83be3915281b14d7c2f7239f37e227f5ff2.png" alt="Dialect">
<img src="/images/dialect.png" alt="Dialect">

<br><br>

Expand Down
138 changes: 109 additions & 29 deletions views/examples.ejs
Original file line number Diff line number Diff line change
@@ -1,44 +1,124 @@
<%- include('./partials/header') %>

<section class="examples">
<style>
td {
vertical-align: middle;
}
td.result {
text-align: center;
}
.validationImg {
width: 150px;
}
.file-content {
margin-bottom: 1em;
}
</style>
<h1>CSV Validation Examples</h1>
<p>Below are some example CSV files demonstrating different validation scenarios. Each example shows the contents of the CSV file, the expected validation result, and a link to validate it. Click on the badge to view the validation results for each example.</p>

<h2>Example: Student List</h2>
<p>This example demonstrates a simple CSV file containing a list of students with their names and ages. The CSV file is expected to pass validation without errors.</p>

<!-- CSV File Preview -->
<h3>Contents of <code>students.csv</code></h3>
<pre id="file-content"><code>Loading file content...</code></pre>

<!-- Expected Result -->
<h3>Expected Result</h3>
<p>This CSV should validate successfully, as it is well-formed and contains consistent data types in each column. No errors or warnings are expected.</p>

<!-- Validation Badge Link -->
<h3>Validation Badge</h3>
<p>Click the badge below to view the validation results for this example:</p>
<a href="http://localhost:3080/validate?csvUrl=https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students.csv" target="_blank">
<img src="http://localhost:3080/validate?csvUrl=https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students.csv&format=svg" alt="Validation Badge for students.csv">
</a>
<!-- Table Structure for Examples -->
<table class="examples-table">
<thead>
<tr>
<th>Example</th>
<th>Contents</th>
<th>Expected Result</th>
<th>Actual Result</th>
</tr>
</thead>
<tbody id="examples-table-body">
<!-- JavaScript will populate this section -->
</tbody>
</table>
</section>

<script>
// JavaScript to fetch and display the file content
document.addEventListener("DOMContentLoaded", function () {
fetch('https://raw.githubusercontent.com/theodi/csvlint.io/refs/heads/main/public/examples/students.csv')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(data => {
document.getElementById('file-content').textContent = data;
// Fetch the examples.json file from the server
fetch('/examples/examples.json')
.then(response => response.json())
.then(examples => {
const tableBody = document.getElementById('examples-table-body');
examples.forEach((example, index) => {
// Build the validation URL with dialect options if provided
const dialectParams = example.dialect ? `&${example.dialect}` : '';
const schemaParam = example.schemaUrl ? `&schemaUrl=${encodeURIComponent(example.schemaUrl)}` : '';
const validationUrl = `/validate?csvUrl=${encodeURIComponent(example.csvUrl)}${schemaParam}${dialectParams}`;
// Create table row
const row = document.createElement('tr');
// Example title and description
const exampleCell = document.createElement('td');
exampleCell.innerHTML = `<h3>${example.title}</h3><p>${example.description}</p>`;
row.appendChild(exampleCell);
// CSV and schema contents in the same cell
const contentCell = document.createElement('td');
contentCell.innerHTML = `
<div class="file-content">
<strong>CSV Content:</strong>
<pre id="file-content-${index}"><code>Loading CSV content...</code></pre>
</div>
`;
if (example.schemaUrl) {
/*contentCell.innerHTML += `
<div class="file-content">
<strong>Schema Content:</strong>
<pre id="schema-content-${index}"><code>Loading schema content...</code></pre>
</div>
`;*/
}
row.appendChild(contentCell);
// Expected result
const expectedResultCell = document.createElement('td');
expectedResultCell.textContent = example.expectedResult;
row.appendChild(expectedResultCell);
// Validation badge link
const actualResultCell = document.createElement('td');
actualResultCell.classList.add('result');
actualResultCell.innerHTML = `
<a href="${validationUrl}" target="_blank">
<img class="validationImg" src="${validationUrl}&format=svg" alt="Validation Badge for ${example.title}">
</a>
`;
row.appendChild(actualResultCell);
// Add the row to the table body
tableBody.appendChild(row);
// Fetch the CSV file content and display it
fetch(example.csvUrl)
.then(response => response.text())
.then(data => {
document.getElementById(`file-content-${index}`).textContent = data;
})
.catch(error => {
console.error('Error loading CSV content:', error);
document.getElementById(`file-content-${index}`).textContent = 'Error loading CSV content.';
});
// Fetch the schema file content if schemaUrl is defined
if (example.schemaUrl) {
fetch(example.schemaUrl)
.then(response => response.text())
.then(data => {
document.getElementById(`schema-content-${index}`).textContent = data;
})
.catch(error => {
console.error('Error loading schema content:', error);
document.getElementById(`schema-content-${index}`).textContent = 'Error loading schema content.';
});
}
});
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
document.getElementById('file-content').textContent = 'Error loading file content.';
console.error('Error loading examples:', error);
});
});
</script>
Expand Down

0 comments on commit 6e695a1

Please sign in to comment.