Skip to content

Commit 73fa07c

Browse files
committed
chore: bootstrap initial implementation
0 parents  commit 73fa07c

12 files changed

+306
-0
lines changed

.editorconfig

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
charset = utf-8
6+
end_of_line = lf
7+
indent_size = 2
8+
indent_style = space
9+
insert_final_newline = true
10+
max_line_length = 80
11+
trim_trailing_whitespace = true
12+
13+
[*.md]
14+
max_line_length = 0
15+
trim_trailing_whitespace = false
16+
17+
[COMMIT_EDITMSG]
18+
max_line_length = 0

.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
dist

.gitignore

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# node
2+
node_modules
3+
4+
# logs
5+
*.log
6+
7+
# files and IDE
8+
.DS_STORE
9+
*~
10+
*.swp
11+
*.swo
12+
13+
# project
14+
package-lock.json
15+
dist

babel.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: ['@babel/preset-env'],
3+
};

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './lib/from-csv';

lib/from-csv.js

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import td from 'tdastscript';
2+
3+
// special characters as defined in RFC-4180
4+
const CR = '\r';
5+
const LF = '\n';
6+
const CRLF = '\r\n';
7+
const COMMA = ',';
8+
const DQUOTE = '"';
9+
10+
// reset values
11+
const RESET_COLUMN = 1;
12+
const RESET_OFFSET = 0;
13+
const RESET_LINE = 1;
14+
const RESET_TEXT = '';
15+
16+
// states
17+
const START_TEXT = 0;
18+
const START_QUOTE = 1;
19+
const END_QUOTE = 3;
20+
const END_TEXT = 4;
21+
const END_LINE = 5;
22+
23+
function getPoint(line, column, offset) {
24+
return {
25+
line,
26+
column,
27+
offset,
28+
};
29+
}
30+
31+
function testComma(char) {
32+
return char === COMMA;
33+
}
34+
35+
function testDquote(char) {
36+
return char === DQUOTE;
37+
}
38+
39+
function testNewline(char) {
40+
return CRLF.includes(char);
41+
}
42+
43+
/**
44+
* RFC 4180 compliant CSV parser
45+
* O(n) complexity
46+
*
47+
* Pseudocode:
48+
* - keep track of Point-related data at all times (line/offset/column)
49+
* - manage parser based on the state of parsing.
50+
* - At a particular parsing state, we update and persist relevant information (e.g. line/offset/column/text/rows), and update the state based on nextChar.
51+
* - Each loop increments the csv string offset by +1, so the algorithm complexity is O(n).
52+
* - Convert all rows into equivalent tdast.
53+
*/
54+
export default function fromCsv(csv = '', options = {}) {
55+
let column = RESET_COLUMN;
56+
let line = RESET_LINE;
57+
let offset = RESET_OFFSET;
58+
let text = RESET_TEXT;
59+
let state = START_TEXT;
60+
let quoted = false;
61+
62+
const rows = [[]];
63+
64+
while (offset < csv.length + 1) {
65+
const char = csv[offset];
66+
const nextChar = csv[offset + 1];
67+
switch (state) {
68+
case START_TEXT: {
69+
text += char;
70+
if (testComma(nextChar) || testNewline(nextChar) || offset === csv.length - 1) {
71+
state = END_TEXT;
72+
}
73+
break;
74+
}
75+
case END_TEXT: {
76+
rows[line - 1].push(text);
77+
text = RESET_TEXT;
78+
if (testComma(char)) {
79+
state = START_TEXT;
80+
} else if (testNewline(char)) {
81+
state = END_LINE;
82+
}
83+
break;
84+
}
85+
case END_LINE: {
86+
line++;
87+
rows[line - 1] = [];
88+
column = RESET_COLUMN;
89+
if (!testNewline(char)) {
90+
state = START_TEXT;
91+
offset--;
92+
}
93+
break;
94+
}
95+
}
96+
offset++;
97+
column++;
98+
}
99+
100+
console.log(rows);
101+
102+
let tdast = td('table');
103+
104+
return rows;
105+
}

license

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2020 Chris Zhou <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

package.json

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"name": "tdast-util-from-csv",
3+
"version": "0.1.0",
4+
"description": "tdast utility to parse csv into tdast",
5+
"license": "MIT",
6+
"homepage": "https://github.com/tdast/tdast-util-from-csv",
7+
"repository": "https://github.com/tdast/tdast-util-from-csv",
8+
"bugs": "https://github.com/tdast/tdast-util-from-csv/issues",
9+
"author": "Chris Zhou <[email protected]> (https://chrisrzhou.io)",
10+
"keywords": [
11+
"tdast",
12+
"util",
13+
"csv",
14+
"tabular",
15+
"data",
16+
"ast",
17+
"unist"
18+
],
19+
"scripts": {
20+
"bootstrap": "npm install",
21+
"build": "microbundle",
22+
"clean": "rm -rf dist",
23+
"dev": "microbundle watch",
24+
"lint": "xo --fix; tsc",
25+
"prepare": "npm run clean; npm run build",
26+
"release": "standard-version -s --infile changelog.md",
27+
"test": "jest --watch packages",
28+
"test:run": "jest"
29+
},
30+
"typings": "types/index.d.ts",
31+
"files": [
32+
"dist",
33+
"types"
34+
],
35+
"dependencies": {
36+
"tdast-types": "^0.1.2",
37+
"tdastscript": "^0.1.2"
38+
},
39+
"devDependencies": {
40+
"@babel/preset-env": "^7.11.5",
41+
"@types/jest": "^26.0.9",
42+
"babel-jest": "^26.2.2",
43+
"dedent": "^0.7.0",
44+
"husky": "^4.3.0",
45+
"jest": "^26.4.2",
46+
"microbundle": "^0.12.3",
47+
"standard-version": "^9.0.0",
48+
"typescript": "^4.0.2",
49+
"xo": "^0.33.1"
50+
},
51+
"husky": {
52+
"hooks": {
53+
"pre-push": "npm prepare; npm run lint; npm run test:run"
54+
}
55+
},
56+
"prettier": {
57+
"bracketSpacing": true,
58+
"jsxBracketSameLine": true,
59+
"trailingComma": "all",
60+
"useTabs": false
61+
},
62+
"xo": {
63+
"env": [
64+
"jest"
65+
],
66+
"prettier": true
67+
}
68+
}

readme.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# tdast-util-from-csv
2+
3+
[**tdast**][tdast] utility to parse csv into tdast.
4+
5+
---
6+
7+
## Install
8+
9+
```sh
10+
npm install tdast-util-from-csv
11+
```
12+
13+
## Use
14+
15+
```ts
16+
```
17+
18+
<!-- Definitions -->
19+
[tdast]: https://github.com/tdast/tdast

tests/from-csv.test.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import dedent from 'dedent';
2+
3+
import fromCsv from '../lib/from-csv';
4+
5+
describe(fromCsv, () => {
6+
it('should transform empty array to empty tree', () => {
7+
const csv = dedent`
8+
col1,col2,col3
9+
row1col1,row1col2,row1col3
10+
row2col1,row2col2,row2col3
11+
`;
12+
expect(fromCsv(csv)).toEqual([
13+
['col1', 'col2', 'col3'],
14+
['row1col1', 'row1col2', 'row1col3'],
15+
['row2col1', 'row2col2', 'row2col3'],
16+
]);
17+
});
18+
19+
it.skip('should transform empty array to empty tree', () => {
20+
const csv = dedent`
21+
"col1","col2","col3"
22+
"row1col1","row1col2","row1col3"
23+
"row2col1","row2col2","row2col3"
24+
`;
25+
expect(fromCsv(csv)).toEqual([
26+
['col1', 'col2', 'col3'],
27+
['row1col1', 'row1col2', 'row1col3'],
28+
['row2col1', 'row2col2', 'row2col3'],
29+
]);
30+
});
31+
32+
it.skip('should transform empty array to empty tree', () => {
33+
const csv = dedent`
34+
"col1","col,2","col3"
35+
row1col1,row1col2,row1col3
36+
row2col1,row2col2,row2col3
37+
`;
38+
expect(fromCsv(csv)).toEqual([
39+
['col1', 'col2', 'col3'],
40+
['row1col1', 'row1col2', 'row1col3'],
41+
['row2col1', 'row2col2', 'row2col3'],
42+
]);
43+
});
44+
});

tsconfig.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true,
4+
"allowSyntheticDefaultImports": true,
5+
"checkJs": true,
6+
"esModuleInterop": true,
7+
"noEmit": true
8+
},
9+
"exclude": ["**/dist", "**/node_modules"]
10+
}

types/index.d.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)