Skip to content

Commit 1c230e0

Browse files
committed
See details:
* Refactoring * Adding preferences * Fixing interactive interface * Starting unit tests * and more...
1 parent 1b0cf59 commit 1c230e0

17 files changed

+586
-135
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
coverage/
3+
lib/vendor/

.eslintrc.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
module.exports = {
2+
"env": {
3+
"es6": true,
4+
"node": true,
5+
"mocha": true
6+
},
7+
"plugins": [
8+
"chai-expect",
9+
"mocha",
10+
"promise"
11+
],
12+
"extends": "eslint:recommended",
13+
"parserOptions": { "sourceType": "module" },
14+
"rules": {
15+
"indent": ["error", 4, { "SwitchCase": 1 }],
16+
"linebreak-style": ["error", "unix"],
17+
"semi": ["error", "always"],
18+
"block-scoped-var": ["error"],
19+
"class-methods-use-this": ["error"],
20+
"curly": ["error", "all"],
21+
"dot-location": ["error", "object"],
22+
"dot-notation": ["error", { "allowKeywords": false }],
23+
"eqeqeq": ["error", "always"],
24+
"no-else-return": ["error"],
25+
"no-eval": ["error"],
26+
"no-extra-bind": ["error"],
27+
"no-floating-decimal": ["error"], // 0.7, not .7
28+
"no-global-assign": ["error"],
29+
"no-implied-eval": ["error"],
30+
"no-invalid-this": ["error"],
31+
"no-labels": ["error"],
32+
"no-lone-blocks": ["error"],
33+
"no-loop-func": ["error"],
34+
"no-multi-spaces": ["error"],
35+
"no-multi-str": ["error"], // use template literals https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
36+
"no-new-func": ["error"],
37+
"no-return-assign": ["error", "always"],
38+
"no-proto": ["error"], // use getPrototypeOf()
39+
"no-script-url": ["error"], // http://stackoverflow.com/questions/13497971/what-is-the-matter-with-script-targeted-urls
40+
"no-sequences": ["error"],
41+
"no-throw-literal": ["error"], // use throw new Error('message')
42+
"no-useless-call": ["error"],
43+
"no-useless-concat": ["error"],
44+
"no-useless-escape": ["error"],
45+
"no-useless-return": ["error"],
46+
"no-shadow": ["error"],
47+
"no-new-require": ["error"],
48+
"no-use-before-define": ["error"],
49+
"array-bracket-spacing": ["error", "never"],
50+
"block-spacing": ["error", "always"],
51+
"brace-style": ["error", "1tbs"],
52+
"comma-dangle": ["error", "never"],
53+
"comma-spacing": ["error", {
54+
"before": false,
55+
"after": true
56+
}],
57+
"no-case-declarations": 0,
58+
"consistent-this": ["error", "self"],
59+
"eol-last": ["error", "always"],
60+
"func-call-spacing": ["error", "never"],
61+
"key-spacing": ["error", {
62+
"beforeColon": false,
63+
"afterColon": true
64+
}],
65+
"keyword-spacing": ["error", {
66+
"before": true,
67+
"after": true
68+
}],
69+
"new-parens": ["error"],
70+
"newline-before-return": ["error"],
71+
"no-array-constructor": ["error"],
72+
"no-lonely-if": ["error"],
73+
"no-multiple-empty-lines": ["error", { "max": 2, "maxBOF": 0, "maxEOF": 1 }],
74+
"no-nested-ternary": ["error"],
75+
"no-new-object": ["error"],
76+
"no-trailing-spaces": ["error"],
77+
"no-unneeded-ternary": ["error"],
78+
"no-whitespace-before-property": ["error"],
79+
"operator-assignment": ["error", "always"],
80+
"padded-blocks": ["error", {
81+
"classes": "always",
82+
"blocks": "never",
83+
"switches": "never"
84+
}],
85+
"quotes": ["error", "single"],
86+
"space-before-blocks": ["error", "always"],
87+
"space-before-function-paren": ["error", {
88+
"anonymous": "always",
89+
"named": "never",
90+
"asyncArrow": "ignore"
91+
}],
92+
"space-infix-ops": ["error", { "int32Hint": false }],
93+
"space-unary-ops": [1, {
94+
"words": true,
95+
"nonwords": false
96+
}],
97+
"unicode-bom": ["error", "never"],
98+
"arrow-body-style": ["error", "as-needed"],
99+
"arrow-parens": ["error", "as-needed"],
100+
"arrow-spacing": ["error", {
101+
"before": true,
102+
"after": true
103+
}],
104+
"generator-star-spacing": ["error", {
105+
"before": true,
106+
"after": false
107+
}],
108+
"no-class-assign": ["error"],
109+
"no-console": ["off"],
110+
"no-useless-computed-key": ["error"],
111+
"no-useless-rename": ["error"],
112+
"no-var": ["error"]
113+
}
114+
};

.vscode/launch.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
// Use IntelliSense to learn about possible Node.js debug attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Tests",
11+
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
12+
"stopOnEntry": true,
13+
"args": ["test/*.test.js"],
14+
"cwd": "${workspaceRoot}",
15+
"runtimeExecutable": null
16+
}
17+
]
18+
}

CODE_OF_CONDUCT.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
This code of conduct applies to all spaces of the Skeleton Sass project. This includes the issue tracker, DSF events and any other forums used by the project team which the community uses for communication. In addition, violations of this code outside these spaces may affect a person's ability to participate within them.
2+
3+
If you believe someone is violating the code of conduct, we ask that you report it by emailing [email protected].
4+
5+
* **Be friendly and patient.**
6+
* **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
7+
* **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
8+
* **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the Skeleton Sass community should be respectful when dealing with other members as well as with people outside the Skeleton Sass community.
9+
* **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
10+
* Violent threats or language directed against another person.
11+
* Discriminatory jokes and language.
12+
* Posting sexually explicit or violent material.
13+
* Posting (or threatening to post) other people's personally identifying information ("doxing").
14+
* Personal insults, especially those using racist or sexist terms.
15+
* Unwelcome sexual attention.
16+
* Advocating for, or encouraging, any of the above behavior.
17+
* Repeated harassment of others. In general, if someone asks you to stop, then stop.
18+
* **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of Skeleton Sass comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
19+
20+
Adopted from the [Django Code of Conduct](https://www.djangoproject.com/conduct/).

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
When contributing keep the following in mind:
2+
3+
1. Do a search in issues to ensure as solution isn't already in progress
4+
2. Stick to the author's preferred code style
5+
3. Write unit tests for your feature/bug fix (80% minimum coverage)
6+
4. Write e2e tests
7+
5. Run linting and make sure it passes

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Options:
9595
setting
9696
--always-use-headers Use this flag to persist column headers preferences
9797
--clear-settings, -c Clear always-interactive settings
98+
--quiet, -q Silence console output [boolean] [default: false]
9899
--help Show help [boolean]
99100
--version Show version number [boolean]
100101
```
@@ -148,7 +149,7 @@ We can define our tables two ways:
148149
```
149150

150151
### Performance Notes
151-
By nature, some functions are substantially slower than others, specifically:
152+
By nature, some functions are considerably slower than others, for example:
152153

153154
| Function | Time to Write 10K Rows by 100 Columns |
154155
| :---: | :---: |
@@ -168,7 +169,7 @@ by contrast, these functions are much faster:
168169
| `zip` | 2.579 |
169170
| `yn` | 0.706s |
170171

171-
If you need to generate large amounts of data for _wide_ tables, it's recommended to use small pieces of data to speed up the process.
172+
If you need to generate large amounts of data for _wide_ tables, it's recommended to use fast functions.
172173
173174
#### More Notes
174175
Instead of hundreds of async file writes (i.e. page faults), this generator uses a single stream to write content to the file. The trade-off is normal heap space, less CPU involvement, but more virtual memory used — memory is cheap; transistors aren't.
@@ -177,7 +178,7 @@ Instead of hundreds of async file writes (i.e. page faults), this generator uses
177178
This tool uses some scripts that are copyright of [Data Design Group Inc.](http://www.ddginc-usa.com/) For more information see the README file in `lib/vendor`.
178179

179180
### Developers
180-
Want to add a feature? Need to debug? The `readline` interface makes for cumbersome debugging, but node has our back:
181+
Want to add a feature? Have a useful generator? Need to debug? The `readline` interface makes for cumbersome debugging, but node has our back:
181182

182183
```bash
183184
node --inspect --inspect-brk index.js
@@ -194,3 +195,18 @@ open up Google Chrome and navigate to:
194195
```
195196
chrome://inspect
196197
```
198+
199+
### Running Tests
200+
To run unit tests:
201+
202+
```bash
203+
npm run test # or
204+
yarn test
205+
```
206+
207+
To run e2e tests:
208+
209+
```bash
210+
npm run e2e # or
211+
yarn e2e
212+
```

bin/gencsv

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
const fs = require('fs');
44
const path = require('path');
55
const chalk = require('chalk');
6-
const _ = require('lodash/string')
76

87
const Utils = require('../lib/utils');
8+
const Preferences = require('../lib/preferences');
99
const generator = require('../lib/generator');
1010

1111
const argv = require('yargs')
@@ -48,6 +48,12 @@ const argv = require('yargs')
4848
'clear-settings': {
4949
alias: 'c',
5050
describe: 'Clear always-interactive settings'
51+
},
52+
quiet: {
53+
alias: 'q',
54+
describe: 'Silence console output',
55+
boolean: true,
56+
default: false
5157
}
5258
})
5359
.help()
@@ -63,43 +69,41 @@ if (argv.functions) {
6369
if (argv.c) {
6470
console.log('Removing settings...');
6571

66-
try {
67-
fs.unlinkSync(path.resolve(Utils.home(), '.gencsv'));
68-
console.log(`Successfully removed ${chalk.cyan(path.resolve(Utils.home(), '.gencsv'))}`);
72+
Preferences.truncate(
73+
() => {
74+
console.log(`Successfully removed ${chalk.cyan(Preferences.file())}`);
6975

70-
if (argv._.length <= 1) {
71-
process.exit(0);
76+
if (argv._.length <= 1) {
77+
process.exit(0);
78+
}
79+
},
80+
() => {
81+
console.log(`Error removing ${chalk.redBright(Preferences.file())}`);
82+
console.log('Attempting to run command...\n');
7283
}
73-
} catch (e) {
74-
console.log(`Error removing ${chalk.redBright(path.resolve(Utils.home(), '.gencsv'))}`);
75-
console.log('Attempting to run command...\n');
76-
}
84+
)
7785
}
7886

79-
if (Utils.isInteractive() || argv.i) {
87+
if (Preferences.isInteractive() || argv.i) {
8088
require('../index');
8189
return;
8290
}
8391

8492
if (argv.a) {
85-
fs.writeFile(path.resolve(Utils.home(), '.gencsv'), '{ "interactive": true }', err => {
86-
if (err) {
87-
throw new Error(err);
88-
}
89-
90-
console.log(`Settings written to ${chalk.cyan(path.resolve(Utils.home(), '.gencsv'))}`);
93+
Preferences.save('interactive', true, () => {
94+
console.log(`Settings written to ${chalk.cyan(Preferences.file())}`);
9195
setTimeout(() => require('../index'), 500);
9296
});
9397

9498
return;
9599
}
96100

97101
if (argv._.length <= 1 && process.stdin.isTTY) {
98-
console.log(chalk.redBright('You must define an output file name and at least one column!'));
102+
console.log(chalk.redBright('You must define an output file name and at least one column definition!'));
99103
process.exit(1);
100104
}
101105

102-
if (Utils.alwaysUseHeaders()) {
106+
if (Preferences.alwaysUseHeaders()) {
103107
argv['use-headers'] = true;
104108
}
105109

@@ -108,26 +112,12 @@ let columns = argv._.slice(1);
108112
let rows = 100;
109113

110114
if (argv.r !== 100) {
111-
if (/^\d+(\.\d*)?(K|M|B)$/.test(argv.r)) {
112-
let r = argv.r.toLowerCase().trim();
113-
114-
if (_.endsWith(r, 'k')) {
115-
rows = parseFloat(r) * 1000;
116-
} else if (_.endsWith(r, 'm')) {
117-
rows = parseFloat(r) * 10 ** 6;
118-
} else if (_.endsWith(r, 'b')) {
119-
rows = parseFloat(r) * 10 ** 9;
120-
}
121-
} else {
122-
if (!/[1-9]\d*/.test(argv.r)) {
123-
console.log(chalk.redBright('Invalid row number'));
124-
process.exit(1);
125-
}
126-
127-
rows = parseInt(argv.r);
115+
try {
116+
rows = Utils.convertNumber(argv.r);
117+
} catch (e) {
118+
console.log(chalk.redBright('Invalid row number'));
119+
process.exit(1);
128120
}
129-
130-
rows = Math.ceil(rows); // drop decimals if any
131121
}
132122

133123
if (columns.length === 0) {
@@ -143,7 +133,9 @@ if (columns.length === 0) {
143133
data += line;
144134
data += '\n';
145135
}).on('close', () => {
146-
console.log('Columns definitions received! Validating...');
136+
if (!argv.q) {
137+
console.log('Columns definitions received! Validating...');
138+
}
147139

148140
let lines = data.split('\n');
149141
let headers = '';
@@ -155,22 +147,18 @@ if (columns.length === 0) {
155147
columns = lines[0].split(/\s*,\s*/);
156148
}
157149

158-
generate(outFile, columns, {
150+
Utils.generate(outFile, columns, {
159151
rows: rows,
160152
chunks: argv.chunk,
161-
headers: argv['use-headers'] || headers.length > 0
153+
headers: argv['use-headers'] || headers.length > 0,
154+
quiet: argv.quiet
162155
}, headers.split(/\s*,\s*/));
163156
});
164157
} else {
165-
generate(outFile, columns, {
158+
Utils.generate(outFile, columns, {
166159
rows: rows,
167160
chunks: argv.chunk,
168-
headers: argv['use-headers']
169-
});
170-
}
171-
172-
function generate(file, columns, options, headers) {
173-
generator(file, columns, options, headers).then(() => {
174-
process.exit(0);
161+
headers: argv['use-headers'],
162+
quiet: argv.quiet
175163
});
176164
}

gulpfile.js

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)