Missing files.
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import yargs from 'yargs';
|
||||||
|
import writeIndex from './../writeIndex';
|
||||||
|
|
||||||
|
let argv;
|
||||||
|
|
||||||
|
argv = yargs
|
||||||
|
.demand(1)
|
||||||
|
.argv;
|
||||||
|
|
||||||
|
writeIndex(argv._);
|
||||||
|
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
console.log('OK!');
|
||||||
|
/* eslint-enable no-console */
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
let buildExportBlock,
|
||||||
|
buildImportBlock,
|
||||||
|
safeVariableName;
|
||||||
|
|
||||||
|
safeVariableName = (fileName) => {
|
||||||
|
let indexOfDot;
|
||||||
|
|
||||||
|
indexOfDot = fileName.indexOf('.');
|
||||||
|
|
||||||
|
if (indexOfDot === -1) {
|
||||||
|
return fileName;
|
||||||
|
} else {
|
||||||
|
return fileName.slice(0, indexOfDot);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
buildImportBlock = (files) => {
|
||||||
|
let importBlock;
|
||||||
|
|
||||||
|
importBlock = _.map(files, (fileName) => {
|
||||||
|
return 'import ' + safeVariableName(fileName) + ' from \'./' + fileName + '\';';
|
||||||
|
});
|
||||||
|
|
||||||
|
importBlock = importBlock.join('\n');
|
||||||
|
|
||||||
|
return importBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
buildExportBlock = (files) => {
|
||||||
|
let exportBlock;
|
||||||
|
|
||||||
|
exportBlock = _.map(files, (fileName) => {
|
||||||
|
return ' ' + safeVariableName(fileName);
|
||||||
|
});
|
||||||
|
|
||||||
|
exportBlock = 'export {\n' + exportBlock.join(',\n') + '\n};';
|
||||||
|
|
||||||
|
return exportBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (filePaths) => {
|
||||||
|
let code,
|
||||||
|
sortedFilePaths;
|
||||||
|
|
||||||
|
code = '\'create index\';\n\n';
|
||||||
|
|
||||||
|
if (filePaths.length) {
|
||||||
|
sortedFilePaths = filePaths.sort();
|
||||||
|
|
||||||
|
code += buildImportBlock(sortedFilePaths) + '\n\n' + buildExportBlock(sortedFilePaths) + '\n\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
};
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import path from 'path';
|
||||||
|
import validateTargetDirectory from './validateTargetDirectory';
|
||||||
|
|
||||||
|
let hasIndex,
|
||||||
|
hasMultipleExtensions,
|
||||||
|
hasNoExtension,
|
||||||
|
isSafeName,
|
||||||
|
removeDuplicates;
|
||||||
|
|
||||||
|
hasIndex = (directoryPath) => {
|
||||||
|
let indexPath;
|
||||||
|
|
||||||
|
indexPath = path.resolve(directoryPath, 'index.js');
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.statSync(indexPath);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
hasNoExtension = (fileName) => {
|
||||||
|
let matches;
|
||||||
|
|
||||||
|
matches = fileName.match(/\./g);
|
||||||
|
|
||||||
|
return !matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
hasMultipleExtensions = (fileName) => {
|
||||||
|
let matches;
|
||||||
|
|
||||||
|
matches = fileName.match(/\./g);
|
||||||
|
|
||||||
|
return matches && matches.length > 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
isSafeName = (fileName) => {
|
||||||
|
return /^[a-z][a-z0-9\.]+$/i.test(fileName);
|
||||||
|
};
|
||||||
|
|
||||||
|
removeDuplicates = (files) => {
|
||||||
|
return _.filter(files, (fileName) => {
|
||||||
|
return !_.includes(files, fileName + '.js');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (directoryPath) => {
|
||||||
|
let children;
|
||||||
|
|
||||||
|
validateTargetDirectory(directoryPath);
|
||||||
|
|
||||||
|
children = fs.readdirSync(directoryPath);
|
||||||
|
|
||||||
|
children = _.filter(children, (fileName) => {
|
||||||
|
let absolutePath,
|
||||||
|
isDirectory;
|
||||||
|
|
||||||
|
absolutePath = path.resolve(directoryPath, fileName);
|
||||||
|
|
||||||
|
isDirectory = fs.statSync(absolutePath).isDirectory();
|
||||||
|
|
||||||
|
if (!isSafeName(fileName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasNoExtension(fileName) && !isDirectory) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMultipleExtensions(fileName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.startsWith(fileName, 'index.js')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDirectory && !_.endsWith(fileName, '.js')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDirectory && !hasIndex(absolutePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
children = removeDuplicates(children);
|
||||||
|
|
||||||
|
return children.sort();
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export default (paths) => {
|
||||||
|
return _.sortBy(paths, (path) => {
|
||||||
|
return -path.split('/').length;
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default (targetDirectory) => {
|
||||||
|
let indexFile,
|
||||||
|
indexFilePath,
|
||||||
|
stats;
|
||||||
|
|
||||||
|
try {
|
||||||
|
stats = fs.statSync(targetDirectory);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('Directory "' + targetDirectory + '" does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stats.isDirectory()) {
|
||||||
|
throw new Error('"' + targetDirectory + '" is not a directory.');
|
||||||
|
}
|
||||||
|
|
||||||
|
indexFilePath = path.resolve(targetDirectory, './index.js');
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.statSync(indexFilePath);
|
||||||
|
} catch (error) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexFile = fs.readFileSync(indexFilePath, 'utf8');
|
||||||
|
|
||||||
|
if (!_.startsWith(indexFile, '\'create index\';\n')) {
|
||||||
|
throw new Error('"' + indexFilePath + '" unsafe index.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import createIndexCode from './createIndexCode';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import validateTargetDirectory from './validateTargetDirectory';
|
||||||
|
import readDirectory from './readDirectory';
|
||||||
|
import sortByDepth from './sortByDepth';
|
||||||
|
|
||||||
|
export default (directoryPaths) => {
|
||||||
|
let sortedDirectoryPaths;
|
||||||
|
|
||||||
|
sortedDirectoryPaths = sortByDepth(directoryPaths);
|
||||||
|
|
||||||
|
_.forEach(sortedDirectoryPaths, (directoryPath) => {
|
||||||
|
validateTargetDirectory(directoryPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
_.forEach(sortedDirectoryPaths, (directoryPath) => {
|
||||||
|
let indexCode,
|
||||||
|
indexFilePath,
|
||||||
|
siblings;
|
||||||
|
|
||||||
|
siblings = readDirectory(directoryPath);
|
||||||
|
|
||||||
|
indexCode = createIndexCode(siblings);
|
||||||
|
|
||||||
|
indexFilePath = path.resolve(directoryPath, 'index.js');
|
||||||
|
|
||||||
|
fs.writeFileSync(indexFilePath, indexCode);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export default (code) => {
|
||||||
|
return _.trim(code) + '\n\n';
|
||||||
|
};
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/* eslint-disable no-restricted-syntax */
|
||||||
|
|
||||||
|
import {
|
||||||
|
expect
|
||||||
|
} from 'chai';
|
||||||
|
|
||||||
|
import createIndexCode from './../src/createIndexCode';
|
||||||
|
|
||||||
|
import codeExample from './codeExample';
|
||||||
|
|
||||||
|
describe('createIndexCode()', () => {
|
||||||
|
it('describes no children', () => {
|
||||||
|
let indexCode;
|
||||||
|
|
||||||
|
indexCode = createIndexCode([]);
|
||||||
|
|
||||||
|
expect(indexCode).to.equal(codeExample(`
|
||||||
|
'create index';
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
it('describes a single child', () => {
|
||||||
|
let indexCode;
|
||||||
|
|
||||||
|
indexCode = createIndexCode(['foo']);
|
||||||
|
|
||||||
|
expect(indexCode).to.equal(codeExample(`
|
||||||
|
'create index';
|
||||||
|
|
||||||
|
import foo from './foo';
|
||||||
|
|
||||||
|
export {
|
||||||
|
foo
|
||||||
|
};
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
it('describes multiple children', () => {
|
||||||
|
let indexCode;
|
||||||
|
|
||||||
|
indexCode = createIndexCode(['bar', 'foo']);
|
||||||
|
|
||||||
|
expect(indexCode).to.equal(codeExample(`
|
||||||
|
'create index';
|
||||||
|
|
||||||
|
import bar from './bar';
|
||||||
|
import foo from './foo';
|
||||||
|
|
||||||
|
export {
|
||||||
|
bar,
|
||||||
|
foo
|
||||||
|
};
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
context('file with extension', () => {
|
||||||
|
it('removes the extension from the export statement', () => {
|
||||||
|
let indexCode;
|
||||||
|
|
||||||
|
indexCode = createIndexCode(['foo.js']);
|
||||||
|
|
||||||
|
expect(indexCode).to.equal(codeExample(`
|
||||||
|
'create index';
|
||||||
|
|
||||||
|
import foo from './foo.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
foo
|
||||||
|
};
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('multiple, unsorted', () => {
|
||||||
|
it('sorts the files', () => {
|
||||||
|
let indexCode;
|
||||||
|
|
||||||
|
indexCode = createIndexCode(['foo', 'bar']);
|
||||||
|
|
||||||
|
expect(indexCode).to.equal(codeExample(`
|
||||||
|
'create index';
|
||||||
|
|
||||||
|
import bar from './bar';
|
||||||
|
import foo from './foo';
|
||||||
|
|
||||||
|
export {
|
||||||
|
bar,
|
||||||
|
foo
|
||||||
|
};
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'create index';
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import {
|
||||||
|
expect
|
||||||
|
} from 'chai';
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import readDirectory from './../src/readDirectory';
|
||||||
|
|
||||||
|
const fixturesPath = path.resolve(__dirname, './fixtures/read-directory');
|
||||||
|
|
||||||
|
describe('readDirectory()', () => {
|
||||||
|
context('target directory contains child directories', () => {
|
||||||
|
it('gets names of the children directories', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-directories'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['bar', 'foo']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains child directories that do not contain index', () => {
|
||||||
|
it('gets names of the children directories', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-directories-without-index'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['present.js']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains child directories (unsafe name)', () => {
|
||||||
|
it('gets names of the children directories', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-directories-unsafe-name'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['present']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context.skip('target directory contains ./index.js', () => {
|
||||||
|
it('does not include ./index.js', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-index'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['bar', 'foo']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains files', () => {
|
||||||
|
it('refers to the files (with extension)', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-files'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['bar.js', 'foo.js']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains dot files', () => {
|
||||||
|
it('ignores files', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-dot-files'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['present.js']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains files with no extension', () => {
|
||||||
|
it('ignores files', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-files-no-extension'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['present.js']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains files with multiple extensions', () => {
|
||||||
|
it('ignores files', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-files-multiple-extensions'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['present.js']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('target directory contains directories and files with the same name', () => {
|
||||||
|
it('prefers file', () => {
|
||||||
|
let names;
|
||||||
|
|
||||||
|
names = readDirectory(path.resolve(fixturesPath, 'children-directories-and-files'));
|
||||||
|
|
||||||
|
expect(names).to.deep.equal(['foo.js', 'present.js']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {
|
||||||
|
expect
|
||||||
|
} from 'chai';
|
||||||
|
import sortByDepth from './../src/sortByDepth';
|
||||||
|
|
||||||
|
describe('sortByDepth()', () => {
|
||||||
|
it('sorts from deepest to the most shallow', () => {
|
||||||
|
let paths,
|
||||||
|
sortedPaths;
|
||||||
|
|
||||||
|
paths = [
|
||||||
|
'/b',
|
||||||
|
'/a',
|
||||||
|
'/a/b/c',
|
||||||
|
'/a/b'
|
||||||
|
];
|
||||||
|
|
||||||
|
sortedPaths = sortByDepth(paths);
|
||||||
|
|
||||||
|
expect(sortedPaths).to.deep.equal(['/a/b/c', '/a/b', '/b', '/a']);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/* eslint-disable max-nested-callbacks */
|
||||||
|
|
||||||
|
import {
|
||||||
|
expect
|
||||||
|
} from 'chai';
|
||||||
|
import path from 'path';
|
||||||
|
import validateTargetDirectory from './../src/validateTargetDirectory';
|
||||||
|
|
||||||
|
const fixturesPath = path.resolve(__dirname, './fixtures/validate-target-directory');
|
||||||
|
|
||||||
|
describe('validateTargetDirectory()', () => {
|
||||||
|
describe('directory path', () => {
|
||||||
|
context('refers to a directory that does not exist', () => {
|
||||||
|
it('throws an error', () => {
|
||||||
|
expect(() => {
|
||||||
|
validateTargetDirectory(path.resolve(fixturesPath, 'does-not-exist'));
|
||||||
|
}).to.throw(Error, 'Directory "' + path.resolve(fixturesPath, 'does-not-exist') + '" does not exist.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('refers to a file', () => {
|
||||||
|
it('throws an error', () => {
|
||||||
|
expect(() => {
|
||||||
|
validateTargetDirectory(path.resolve(fixturesPath, 'not-a-directory.js'));
|
||||||
|
}).to.throw(Error, '"' + path.resolve(fixturesPath, 'not-a-directory.js') + '" is not a directory.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('target index', () => {
|
||||||
|
context('no index', () => {
|
||||||
|
it('returns true', () => {
|
||||||
|
expect(validateTargetDirectory(path.resolve(fixturesPath, 'no-index'))).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context.skip('safe', () => {
|
||||||
|
it('returns true', () => {
|
||||||
|
expect(validateTargetDirectory(path.resolve(fixturesPath, 'safe-index'))).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
context('unsafe', () => {
|
||||||
|
it('throws an error', () => {
|
||||||
|
expect(() => {
|
||||||
|
validateTargetDirectory(path.resolve(fixturesPath, 'unsafe-index'));
|
||||||
|
}).to.throw(Error, '"' + path.resolve(fixturesPath, 'unsafe-index/index.js') + '" unsafe index.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/* eslint-disable no-restricted-syntax */
|
||||||
|
|
||||||
|
import {
|
||||||
|
expect
|
||||||
|
} from 'chai';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import codeExample from './codeExample';
|
||||||
|
import writeIndex from './../src/writeIndex';
|
||||||
|
|
||||||
|
const fixturesPath = path.resolve(__dirname, './fixtures/write-index');
|
||||||
|
|
||||||
|
describe('writeIndex()', () => {
|
||||||
|
it('creates index in target directory', () => {
|
||||||
|
let indexCode,
|
||||||
|
indexFilePath;
|
||||||
|
|
||||||
|
indexFilePath = path.resolve(fixturesPath, './mixed/index.js');
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(indexFilePath);
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
writeIndex([path.resolve(fixturesPath, './mixed')]);
|
||||||
|
|
||||||
|
indexCode = fs.readFileSync(indexFilePath, 'utf8');
|
||||||
|
|
||||||
|
expect(indexCode).to.equal(codeExample(`
|
||||||
|
'create index';
|
||||||
|
|
||||||
|
import bar from './bar';
|
||||||
|
import foo from './foo.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
bar,
|
||||||
|
foo
|
||||||
|
};
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user