Skip to content

Commit

Permalink
Merge pull request #25 from bidoubiwa/fix_tests
Browse files Browse the repository at this point in the history
Fix tests failing because of not catched wrongly formated files
  • Loading branch information
bidoubiwa authored Aug 19, 2021
2 parents 256e16f + 585f6ac commit 2518f4a
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: ["10", "12", "14"]
node: ["14"]
name: integration-tests (Node.js ${{ matrix.node }})
steps:
- uses: actions/checkout@v2
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,7 @@ combined.json
# Ignore artifacts:
build
coverage

# Misc
combine.json
test-output
18 changes: 11 additions & 7 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


<center>

# turbo-json.js
Expand All @@ -8,10 +6,16 @@

</center>

turbo-json.js is a tool that combines all json files found in a directory into one big json file using streaming to avoid out-of-memory.
turbo-json.js is a tool that combines all json files found in a directory into one big json file using **streaming** to avoid out-of-memory.

Both `read` and `write` actions are done using `streaming`. The maximum data stored in memory is the buffer size.
Example:
```bash
turbo-json data
```

All json files found in `data` directory will be combined into one file that is named `combined.json` par default.

Both `read` and `write` actions are done using `streaming`. The maximum data stored in memory is the buffer size.

## Input/Output

Expand All @@ -37,7 +41,7 @@ Output file:
```

**Array exception**:
There is one exception to this rule. If your JSON file contains an array, it will be deconstructed in the final file (_could become an option please make an issue if you'd like that_).
There is one exception to this rule. If your JSON file contains an array, it will be deconstructed/flattened in the final file (_could become an option please make an issue if you'd like that_).

Input files:

Expand Down Expand Up @@ -94,12 +98,12 @@ It accepts relative path but also fully qualified paths.
### CLI usage:

```bash
turbo-json --input-dir <dir-path> --output-file <file-path> (default: "combined.json")
turbo-json <input-directory> --output-file <file-path> (default: "combined.json")
```

**Example**
```bash
turbo-json /data combined_data.json
turbo-json /data -o combined_data.json
```

### Library usage
Expand Down
1 change: 1 addition & 0 deletions __tests__/assets/combine_all.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[
1,
{
"name": "far away"
}
Expand Down
20 changes: 18 additions & 2 deletions __tests__/basic.tests.js → __tests__/combine.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ beforeAll(() => {
fs.mkdirSync(OUTPUT_DIR);
}
});
// doesnt work with one file

test('Tests on 1 empty file', async () => {
const res = await combineJson({
inputDir: 'misc/one_empty',
Expand Down Expand Up @@ -40,6 +40,22 @@ test('Tests on multiple empty files', async () => {
expect(data).toEqual(expected);
});

test('Tests on some invalid files and some valid', async () => {
const res = await combineJson({
inputDir: 'misc/multiple_empty',
outputFile: 'test-output/combine_multiple_empty.json',
});
const data = JSON.parse(
fs.readFileSync(
`${process.cwd()}/test-output/combine_multiple_empty.json`,
'utf-8'
)
);
const expected = [];
expect(res).toBe(1);
expect(data).toEqual(expected);
});

test('Tests if on 1 file containing one primitive', async () => {
const res = await combineJson({
inputDir: 'misc/one_primitive',
Expand Down Expand Up @@ -97,6 +113,6 @@ test('Tests if on all files', async () => {

afterAll(() => {
if (fs.existsSync(OUTPUT_DIR)) {
rimraf.sync(OUTPUT_DIR);
// rimraf.sync(OUTPUT_DIR);
}
});
Empty file added misc/some_empty/empty.json
Empty file.
25 changes: 25 additions & 0 deletions misc/some_empty/far_away.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@




















[
{
"name": "far away"
}
]
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
"main": "src/index.js",
"scripts": {
"start": "src/cli.js",
"lint": "prettier --write .",
"test": "jest",
"test:watch": "npx jest --watch"
},
"preferGlobal": true,
"bugs": {
"url": "https://github.com/bidoubiwa/turbo-json/issues",
"url": "https://github.com/bidoubiwa/turbo-json.js/issues",
"email": "[email protected]"
},
"repository": {
"type": "git",
"url": "git://github.com/bidoubiwa/turbo-json.git"
"url": "git://github.com/bidoubiwa/turbo-json.js.git"
},
"author": {
"name": "Charlotte Vermandel",
Expand All @@ -29,7 +28,7 @@
"src/"
],
"engines": {
"node": ">=0.10.3 <17"
"node": ">=14 <15"
},
"license": "MIT",
"dependencies": {
Expand Down
4 changes: 4 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const combineJson = require('./combine-json');

const program = new commander.Command()


program
.argument(
'<input-directory>',
Expand All @@ -28,6 +29,9 @@ program

(async () => {
try {
if (process.argv.length < 3) {
console.log( program.helpInformation() );
}
await program.parse()
} catch (e) {
console.error(e);
Expand Down
121 changes: 64 additions & 57 deletions src/combine-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,81 +16,88 @@ const BUFFER_SIZE = 1000;
async function combine({ inputFiles, inputDirPath, outputFilePath }) {
createOutputArrayFile(outputFilePath);
const numberOfFiles = inputFiles.length;

let first = true;
for (let index = 0; index < numberOfFiles; index++) {
let fileName = inputFiles[index];
let inputFile = `${inputDirPath}${fileName}`;

await verifyJson({jsonFile: inputFile})
const inputFileFd = openFile(inputFile);

const { isArray, startPosition, empty } = jsonRootType({
fd: inputFileFd,
bufferSize: BUFFER_SIZE,
});
try {
let fileName = inputFiles[index];
let inputFile = `${inputDirPath}${fileName}`;

let stopPosition = undefined;

if (isArray) {
stopPosition =
closingArrayIndex({
fd: inputFileFd,
position: (fileSize(inputFile) - BUFFER_SIZE > 0) ? fileSize(inputFile) - BUFFER_SIZE : 0,
bufferSize: BUFFER_SIZE
});
}
await verifyJson({jsonFile: inputFile})
const inputFileFd = openFile(inputFile);

// open destination file for appending
var writeStream = fs.createWriteStream(outputFilePath, {
flags: 'a',
});
const { isArray, startPosition, empty } = jsonRootType({
fd: inputFileFd,
bufferSize: BUFFER_SIZE,
});

// open source file for reading
var readStream = fs.createReadStream(inputFile, {
start: startPosition,
end: stopPosition,
});
let stopPosition = undefined;

readStream.pipe(writeStream);
if (isArray) {
stopPosition =
closingArrayIndex({
fd: inputFileFd,
position: (fileSize(inputFile) - BUFFER_SIZE > 0) ? fileSize(inputFile) - BUFFER_SIZE : 0,
bufferSize: BUFFER_SIZE
});
}

await new Promise(function (resolve) {
writeStream.on('close', function () {
resolve();
});
});
if (!empty && !first) {
let comaWrite = fs.createWriteStream(outputFilePath, {
flags: 'a',
});

let last = index === numberOfFiles - 1;
await new Promise(function (resolve) {
comaWrite.write(',', () => {
resolve('');
});
});
} else if (!empty) {
first = false
}

if (!last && !empty) {
let comaWrite = fs.createWriteStream(outputFilePath, {
// open destination file for appending
var writeStream = fs.createWriteStream(outputFilePath, {
flags: 'a',
});

await new Promise(function (resolve) {
comaWrite.write(',', () => {
resolve('');
});
});
} else if (last) {
let closingBracketWrite = fs.createWriteStream(outputFilePath, {
flags: 'a',
// open source file for reading
var readStream = fs.createReadStream(inputFile, {
start: startPosition,
end: stopPosition,
});

readStream.pipe(writeStream);

await new Promise(function (resolve) {
closingBracketWrite.write(']', () => {
resolve('');
writeStream.on('close', function () {
resolve();
});
});
}

console.log(
chalk.green(
'file: ' +
chalk.blue.underline.bold(fileName) +
` has been added! last : ${last}, index: ${index}, numberOfFiles: ${numberOfFiles}`
)
);
console.log(
chalk.green(
'file: ' +
chalk.blue.underline.bold(fileName) +
` has been added! index: ${index}, number of files: ${numberOfFiles}`
)
);
}
catch (e) {
console.log(chalk.yellow(
`Invalid file is ignored: ${chalk.blue.underline.bold(e.file)}: ${e.error}`
))
}
}

let closingBracketWrite = fs.createWriteStream(outputFilePath, {
flags: 'a',
});

await new Promise(function (resolve) {
closingBracketWrite.write(']', () => {
resolve('');
});
});
await verifyJson({jsonFile: outputFilePath})
return 1;
}
Expand Down
10 changes: 4 additions & 6 deletions src/json-validity.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ async function verifyJson({ jsonFile }) {

const verifier = new Verifier();

verifier.on('error', error => {
console.log(error)
throw `Json file is not valid: ${jsonFile}`
});

const verifierStream = fs.createReadStream(jsonFile).pipe(verifier);
await new Promise(function (resolve) {
await new Promise(function (resolve, rejects) {
verifierStream.on('close', function () {
resolve();
});
verifier.on('error', error => {
rejects({message: `Json file is not valid: ${jsonFile}: ${error.message}`, file: jsonFile, error: error.message})
});
});
}

Expand Down

0 comments on commit 2518f4a

Please sign in to comment.