Socket
Socket
Sign inDemoInstall

destiny

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

destiny - npm Package Compare versions

Comparing version 0.3.1 to 0.4.0

codecov.yml

98

.eslintrc.js

@@ -1,61 +0,55 @@

module.exports = {
root: true,
const defaultSettings = {
env: { es6: true, node: true },
extends: ["standard", "prettier"],
parser: "babel-eslint",
rules: {
indent: "off",
"no-unused-vars": "off",
semi: [2, "always"],
"keyword-spacing": [2, { before: true, after: true }],
"space-before-blocks": [2, "always"],
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
"no-cond-assign": 0,
"no-empty": 0,
"object-shorthand": [2, "always"],
"no-const-assign": 2,
"no-class-assign": 2,
"no-this-before-super": 2,
"no-var": 2,
"no-unreachable": 2,
"valid-typeof": 2,
"quote-props": [2, "as-needed"],
"one-var": [2, "never"],
"prefer-arrow-callback": 2,
"prefer-const": [2, { destructuring: "all" }],
"arrow-spacing": 2,
"no-inner-declarations": 0,
"require-atomic-updates": "off",
quotes: "off",
"@typescript-eslint/quotes": ["error", "double"],
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/no-object-literal-type-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/prefer-interface": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"no-unused-vars": [
"error",
{
args: "none",
ignoreRestSiblings: true,
vars: "all",
varsIgnorePattern: "^_+$",
},
],
},
env: {
es6: true,
browser: true,
node: true,
jest: true,
},
};
const testSettings = {
env: { ...defaultSettings.env, jest: true },
files: ["tests/**/*.{js,jsx,mjs,ts,tsx}", "**/*.test.{js,jsx,mjs,ts,tsx}"],
rules: { ...defaultSettings.rules, "import/first": "off" },
};
const typescriptSettings = {
files: ["src/**/*.{ts,tsx}"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
// keep at the end
"plugin:prettier/recommended",
"prettier/@typescript-eslint",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 9,
sourceType: "module",
ecmaFeatures: { jsx: true },
ecmaVersion: 2020,
project: "./tsconfig.json",
warnOnUnsupportedTypeScriptVersion: false,
},
overrides: [
{
files: ["*.js"],
rules: {
"@typescript-eslint/no-var-requires": "off",
plugins: ["@typescript-eslint"],
rules: {
...defaultSettings.rules,
"@typescript-eslint/member-delimiter-style": [
"error",
{
multiline: { delimiter: "comma", requireLast: true },
singleline: { delimiter: "comma", requireLast: false },
},
},
],
],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-unused-vars": "error",
},
};
module.exports = {
...defaultSettings,
overrides: [testSettings, typescriptSettings],
};

@@ -0,1 +1,16 @@

# [0.4.0](https://github.com/benawad/destiny/compare/v0.3.1...v0.4.0) (2020-03-04)
### Bug Fixes
- ensure path correctness ([f22f07f](https://github.com/benawad/destiny/commit/f22f07f962c130a821009b43c0e568d819533b96)), closes [#81](https://github.com/benawad/destiny/issues/81)
- extend linting ([039cadf](https://github.com/benawad/destiny/commit/039cadf98fb5e08fcf469faa95154b763b64c3bd))
- fix new linting issues ([c19f2e5](https://github.com/benawad/destiny/commit/c19f2e53a93c3859c7c02fd206c87c2b367efe36))
- Fix time complexity when searching for common parent dir ([ce9915e](https://github.com/benawad/destiny/commit/ce9915eac72870135e30b9b895a4ad265a004266))
- improve regex path matching ([ff9b19b](https://github.com/benawad/destiny/commit/ff9b19b43870a6fd0d43364ce9e342c4f2c6b30c)), closes [#87](https://github.com/benawad/destiny/issues/87)
- support paths in config via include ([c049ceb](https://github.com/benawad/destiny/commit/c049cebf336da6a01f3b931a2ce0b62d0f482b06))
### Features
- Add CLI flag to rename single files ([2de9ff1](https://github.com/benawad/destiny/commit/2de9ff1acde8c040fe324b8d9a5fc37b6413e935))
## [0.3.1](https://github.com/benawad/destiny/compare/v0.3.0...v0.3.1) (2020-02-26)

@@ -2,0 +17,0 @@

module.exports = {
testPathIgnorePatterns: ["/tests/fixtures/", "/test/tmp/"],
testPathIgnorePatterns: ["<rootDir>/tests/fixtures/", "<rootDir>/tests/tmp/"],
coveragePathIgnorePatterns: ["/tests/tmp/"],
};

@@ -13,10 +13,10 @@ #!/usr/bin/env node

var chalk = _interopDefault(require('chalk'));
var fs = _interopDefault(require('fs'));
var glob = _interopDefault(require('glob'));
var cosmiconfig = require('cosmiconfig');
var fs = require('fs-extra');
var fs__default = _interopDefault(fs);
var path = _interopDefault(require('path'));
var fs$1 = require('fs-extra');
var fs$1__default = _interopDefault(fs$1);
var Git = _interopDefault(require('simple-git/promise'));
var fs$1 = _interopDefault(require('fs'));
var resolve = _interopDefault(require('resolve'));
var glob = _interopDefault(require('glob'));

@@ -50,79 +50,119 @@ const error = (err, code = 0) => {

const moveFiles = async (newStructure, parentFolder) => {
const git = Git(parentFolder);
let isRepo = false;
const isDirectory = filePath => fs$1.lstatSync(filePath).isDirectory();
try {
isRepo = await git.checkIsRepo();
} catch {}
const isFile = filePath => fs$1.lstatSync(filePath).isFile();
for (const [k, newLocation] of Object.entries(newStructure)) {
// skip globals
if (k.includes("..")) {
continue;
}
const globSearch = pattern => {
const matches = glob.sync(pattern);
const files = matches.filter(match => isFile(match));
const oldAbsLocation = path.resolve(path.join(parentFolder, k));
const newAbsLocation = path.resolve(path.join(parentFolder, newLocation));
if (files.length === 0) {
logger.error("Could not find any files for: " + pattern, 1);
}
if (oldAbsLocation !== newAbsLocation) {
// make folders
fs__default.ensureDirSync(path.dirname(newAbsLocation));
let shouldGitMv = false;
return files;
};
/** Recursively get all file paths. */
if (isRepo) {
// check if file is tracked in git
try {
await git.silent(true).raw(["ls-files", "--error-unmatch", oldAbsLocation]);
shouldGitMv = true;
} catch {}
}
if (shouldGitMv) {
await git.mv(oldAbsLocation, newAbsLocation);
} else {
// move
fs__default.renameSync(oldAbsLocation, newAbsLocation);
const getFilePaths = rootPath => {
const filePaths = [];
const paths = [rootPath];
while (paths.length > 0) {
const filePath = paths.shift();
if (filePath == null || filePath.length === 0) continue;
const isGlobPattern = glob.hasMagic(filePath);
if (isGlobPattern) {
filePaths.push(...globSearch(filePath));
continue;
}
if (fs$1.existsSync(filePath)) {
if (isFile(filePath)) {
filePaths.push(filePath);
} else if (isDirectory(filePath)) {
paths.push(path.join(filePath, "/**/*.*"));
}
} else {
logger.error(`Unable to resolve the path: ${filePath}`);
}
}
return filePaths;
};
/** Get a restructure map with rootPath keys and filePaths values. */
const getRestructureMap = rootPaths => rootPaths.reduce((acc, rootPath) => ({ ...acc,
[rootPath]: getFilePaths(rootPath)
}), {});
async function isFileGitTracked(git, location) {
return git.silent(true).raw(["ls-files", "--error-unmatch", location]).then(() => true).catch(() => false);
}
/** Moves each file in the tree from old path to new path. */
async function moveFiles(tree, parentFolder) {
const git = Git(parentFolder);
const isFolderGitTracked = await git.checkIsRepo();
for (const [oldPath, newPath] of Object.entries(tree)) {
// skip globals
if (oldPath.includes("..")) continue;
const oldAbsolutePath = path.resolve(parentFolder, oldPath);
const newAbsolutePath = path.resolve(parentFolder, newPath);
if (oldAbsolutePath === newAbsolutePath) continue; // Create folder for files
const newDirname = path.dirname(newAbsolutePath);
fs$1__default.ensureDirSync(newDirname);
const shouldGitMv = isFolderGitTracked && (await isFileGitTracked(git, oldAbsolutePath));
if (shouldGitMv) {
await git.mv(oldAbsolutePath, newAbsolutePath);
} else {
fs$1__default.renameSync(oldAbsolutePath, newAbsolutePath);
}
}
}
/** Recursively removes all empty folders. */
function removeEmptyFolders(directory) {
const files = fs$1.readdirSync(directory);
if (!files) return fs$1.rmdirSync(directory);
const files = fs.readdirSync(directory);
if (!files) return fs.rmdirSync(directory);
for (const filePath of files) {
const fullPath = path.resolve(directory, filePath);
const isDirectory = fs$1.lstatSync(fullPath).isDirectory();
const isDirectory = fs.lstatSync(fullPath).isDirectory();
if (!isDirectory) continue;
removeEmptyFolders(fullPath);
const isEmpty = fs$1.readdirSync(fullPath).length === 0;
if (isEmpty) fs$1.rmdirSync(fullPath);
const isEmpty = fs.readdirSync(fullPath).length === 0;
if (isEmpty) fs.rmdirSync(fullPath);
}
}
function findEdges(filePath) {
const importRegex = /(?:(?:from|import)\s+["'](\.[^'"]*)["'])|(?:(?:require|import)\s*\(["'](\.[^'"]*)["']\))/gm;
const commentRegex = /\/\*[^]*?\*\/|^.*\/\/.*$/gm;
const edges = [];
const fileContent = fs$1.readFileSync(filePath, {
/** Find all imports for file path. */
function findImports(filePath) {
const reImport = /(?:(?:import|from)\s+|(?:import|require)\s*\()['"]((?:\.{1,2})(?:\/.+)?)['"]/gm;
const reComment = /\/\*[^]*?\*\/|^.*\/\/.*$/gm;
const importPaths = [];
const fileContent = fs.readFileSync(filePath, {
encoding: "utf8"
}).toString().replace(commentRegex, "");
}).replace(reComment, "");
let matches;
while ((matches = importRegex.exec(fileContent)) !== null) {
var _matches$;
while ((matches = reImport.exec(fileContent)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches.
if (matches.index === importRegex.lastIndex) {
importRegex.lastIndex++;
if (matches.index === reImport.lastIndex) {
reImport.lastIndex++;
}
edges.push([filePath, (_matches$ = matches[1]) != null ? _matches$ : matches[2]]);
importPaths.push(matches[1]);
}
return edges;
return importPaths;
}

@@ -211,21 +251,21 @@

for (const filePath of filePaths) {
const imports = findEdges(filePath);
if (!imports.length) continue;
const importPaths = findImports(filePath);
if (!importPaths.length) continue;
const basedir = path.dirname(filePath);
const newFilePath = getNewFilePath(filePath, rootOptions);
const ogText = fs.readFileSync(filePath).toString();
const ogText = fs$1.readFileSync(filePath).toString();
let newText = ogText.repeat(1);
for (const imp of imports) {
const absPath = customResolve(imp[1], basedir);
for (const importPath of importPaths) {
const absPath = customResolve(importPath, basedir);
if (absPath == null) {
logger.error(`Cannot find import ${imp[1]}`);
logger.error(`Cannot find import ${importPath}`);
continue;
}
const newImportText = getNewImportPath(absPath, newFilePath, rootOptions);
const newImportPath = getNewImportPath(absPath, newFilePath, rootOptions);
if (newImportText) {
newText = newText.replace(`'${imp[1]}'`, `'${newImportText}'`).replace(`"${imp[1]}"`, `"${newImportText}"`);
if (newImportPath != null) {
newText = newText.replace(`'${importPath}'`, `'${newImportPath}'`).replace(`"${importPath}"`, `"${newImportPath}"`);
}

@@ -235,3 +275,3 @@ }

if (newText !== ogText) {
fs.writeFileSync(filePath, newText);
fs$1.writeFileSync(filePath, newText);
}

@@ -257,3 +297,3 @@ }

const createBranchFromParts = (parts, count) => parts.slice(0, count).join("/");
const createBranchFromParts = (parts, count) => path.join(...parts.slice(0, count));
/** Remove path that matches `match` but save '/' to calculate position. */

@@ -355,59 +395,29 @@

if (paths.length === 1) return path.dirname(paths[0]);
const parentPaths = [];
const parts = paths.map(x => x.split("/"));
const firstParts = parts[0];
firstParts.forEach((part, idx) => {
const allPartsMatch = parts.every(p => p[idx] === part);
const [shortest, secondShortest] = paths.length > 2 ? paths.sort((a, b) => a.length - b.length) : paths;
const secondShortestParts = secondShortest.split(path.sep);
return shortest.split(path.sep).filter((part, idx) => part === secondShortestParts[idx]).join(path.sep);
};
if (allPartsMatch) {
parentPaths.push(part);
}
});
return parentPaths.join("/");
const isFilePathIgnored = filePath => {
const ignoreList = [/^\.git/];
return ignoreList.some(re => re.test(filePath));
};
/** Build graph of all file paths and their own imports. */
function addEdgeToGraph([start, end], graph) {
if (!(start in graph)) {
graph[start] = [];
}
if (graph[start].includes(end)) return;
graph[start].push(end);
}
function buildGraph(files) {
const parentFolder = findSharedParent(files);
function buildGraph(filePaths) {
const parentFolder = findSharedParent(filePaths);
const graph = {};
const oldGraph = {};
const totalFiles = [];
let numForwardSlashes = 0;
let numBackSlashes = 0;
for (let file of files) {
if (file === ".git") {
continue;
}
file = path.resolve(file);
const start = path.relative(parentFolder, file);
if (!(start in oldGraph)) {
oldGraph[start] = {
oldLocation: file,
imports: []
};
}
for (let filePath of filePaths) {
if (isFilePathIgnored(filePath)) continue;
filePath = path.resolve(filePath);
const start = path.relative(parentFolder, filePath);
totalFiles.push(start);
findEdges(file).forEach(edge => {
if (edge[1].includes("/")) {
numForwardSlashes++;
} else if (edge[1].includes("\\")) {
numBackSlashes++;
}
findImports(filePath).forEach(importPath => {
const pathWithExtension = customResolve(importPath, path.dirname(filePath));
const pathWithExtension = customResolve(edge[1], path.dirname(edge[0]));
if (pathWithExtension == null) {
logger.error(`Cannot find import ${edge[1]}`);
logger.error(`Cannot find import ${importPath}`);
return;

@@ -417,7 +427,10 @@ }

const end = path.relative(parentFolder, pathWithExtension);
addEdgeToGraph([start, end], graph);
oldGraph[start].imports.push({
text: edge[1],
resolved: end
});
if (!Array.isArray(graph[start])) {
graph[start] = [];
}
if (!graph[start].includes(end)) {
graph[start].push(end);
}
});

@@ -427,7 +440,6 @@ }

return {
files: totalFiles,
graph,
parentFolder,
graph,
files: totalFiles,
oldGraph,
useForwardSlash: numForwardSlashes >= numBackSlashes
useForwardSlash: path.sep === "/"
};

@@ -508,3 +520,4 @@ }

function toFractalTree(graph, entryPoints) {
const res = {};
const tree = {};
const treeSet = new Set();
const dependencies = {};

@@ -523,18 +536,17 @@ const testFiles = new Set();

const checkDuplicates = (location, dirname, filePath) => {
var _newLocation;
const hasLocation = treeSet.has(location);
let newLocation;
if (Object.values(res).includes(location)) {
newLocation = path.join(dirname, filePath.replace(/\//g, "-"));
if (hasLocation) {
const newLocation = path.join(dirname, filePath.replace(/\//g, "-"));
logger.info(`File renamed: ${filePath} -> ${newLocation}`);
return newLocation;
}
return (_newLocation = newLocation) != null ? _newLocation : location;
return location;
};
const fn = (filePath, folderPath, graph) => {
const basenameWithExt = path.basename(filePath);
const basename = path.basename(filePath);
if (isTestFile(basenameWithExt)) {
if (isTestFile(basename)) {
testFiles.add(filePath);

@@ -544,11 +556,12 @@ return;

let folderName = path.basename(filePath, path.extname(filePath));
const upperFolder = path.basename(path.dirname(filePath));
let directoryName = path.basename(filePath, path.extname(filePath));
const currentFolder = path.basename(path.dirname(filePath));
const isGlobal = filePath.includes("..");
let location = isGlobal ? filePath : path.join(folderPath, folderName === "index" && upperFolder && upperFolder !== "." ? upperFolder + path.extname(filePath) : basenameWithExt);
location = checkDuplicates(location, folderPath, filePath);
folderName = path.basename(location, path.extname(location));
const tempLocation = isGlobal ? filePath : path.join(folderPath, directoryName === "index" && currentFolder && currentFolder !== "." ? currentFolder + path.extname(filePath) : basename);
const location = checkDuplicates(tempLocation, folderPath, filePath);
directoryName = path.basename(location, path.extname(location));
if (!isGlobal) {
res[filePath] = location;
tree[filePath] = location;
treeSet.add(location);
}

@@ -559,6 +572,6 @@

if ((imports == null ? void 0 : imports.length) > 0) {
const newDestination = path.join(folderPath, folderName);
const newDestination = path.join(folderPath, directoryName);
for (const importFilePath of imports) {
if (importFilePath in res) {
if (importFilePath in tree) {
const cycle = hasCycle(importFilePath, graph, new Set());

@@ -587,9 +600,13 @@

if (!containsCycle) {
Object.entries(dependencies).forEach(([k, v]) => {
if (v.length > 1 && !k.includes("..")) {
const parent = findSharedParent(v);
const filename = path.basename(k);
const upperFolder = path.basename(path.dirname(k));
res[k] = path.join(parent, "shared", path.basename(filename, path.extname(filename)) === "index" && upperFolder && upperFolder !== "." ? upperFolder + path.extname(filename) : filename);
Object.entries(dependencies).forEach(([currentPath, dependencies]) => {
if (dependencies.length <= 1 || currentPath.includes("..")) {
return;
}
const parent = findSharedParent(dependencies);
const filename = path.basename(currentPath);
const currentDir = path.dirname(currentPath);
const newFilePath = path.join(parent, "shared", path.basename(filename, path.extname(filename)) === "index" && currentDir && currentDir !== "." ? path.join(currentDir + path.extname(filename)) : filename);
tree[currentPath] = newFilePath;
treeSet.add(newFilePath);
});

@@ -607,16 +624,102 @@ }

const testFilePath = res[firstRelativeImport];
const testFilePath = tree[firstRelativeImport];
if (!testFilePath) continue;
const location = checkDuplicates(path.join(path.dirname(testFilePath), path.basename(testFile)), path.dirname(testFilePath), testFile);
tree[testFile] = location;
treeSet.add(location);
}
}
if (testFilePath) {
let location = path.join(path.dirname(testFilePath), path.basename(testFile));
location = checkDuplicates(location, path.dirname(testFilePath), testFile);
res[testFile] = location;
return tree;
}
const extractParentDirectory = destination => {
const parts = destination.split(path.sep);
if (parts.length === 1) {
return;
}
parts.pop();
return parts.join(path.sep);
};
const moveUp = destinationPath => {
const parts = destinationPath.split(path.sep);
return [...parts.slice(0, parts.length - 2), parts[parts.length - 1]].join(path.sep);
};
const detectLonelyFiles = tree => {
const fractalTree = { ...tree
}; // Reverse lookup destination -> current location
const reversedFractalTree = {};
for (const [currentFilePath, destinationFilePath] of Object.entries(fractalTree)) {
reversedFractalTree[destinationFilePath] = currentFilePath;
}
const dirCounter = {}; // Sort is important here since we want to go from deep in the file structure to top
const currentDestinations = Object.values(fractalTree).sort((a, b) => b.length - a.length); // Count all occurencies of the parent dirs of the current destinations
for (const currentDestination of currentDestinations) {
const parentDir = extractParentDirectory(currentDestination);
if (!parentDir) {
continue;
}
if (parentDir in dirCounter) {
dirCounter[parentDir] = dirCounter[parentDir] + 1;
continue;
}
dirCounter[parentDir] = 1;
}
/**
* Loop over all the destinations again and move them up if they are lonely files
*/
for (const currentDestination of currentDestinations) {
const startParentDir = extractParentDirectory(currentDestination);
if (!startParentDir) {
continue;
}
let counter = dirCounter[startParentDir];
let newDestination = currentDestination;
let parentDir = startParentDir;
while (counter === 1) {
parentDir = extractParentDirectory(newDestination);
if (!parentDir) {
break;
}
if (startParentDir === parentDir) {
counter = 1;
} else if (parentDir in dirCounter) {
counter = dirCounter[parentDir] + 1;
}
dirCounter[parentDir] = counter;
if (counter === 1) {
newDestination = moveUp(newDestination);
}
}
fractalTree[reversedFractalTree[currentDestination]] = newDestination;
}
return res;
}
return fractalTree;
};
function generateTrees(restructureMap) {
function generateTrees(restructureMap, {
avoidSingleFile
}) {
return Object.entries(restructureMap).reduce((rootOptions, [rootPath, filePaths]) => {

@@ -631,3 +734,8 @@ if (filePaths.length <= 1) return rootOptions;

} = buildGraph(filePaths);
const tree = toFractalTree(graph, findEntryPoints(graph));
let tree = toFractalTree(graph, findEntryPoints(graph));
if (avoidSingleFile) {
tree = detectLonelyFiles(tree);
}
const usedFilePaths = new Set(Object.entries(graph).flat(2));

@@ -651,62 +759,13 @@ const unusedFiles = files.filter(filePath => !usedFilePaths.has(filePath));

var version = "0.3.1";
var version = "0.4.0";
const isDirectory = filePath => fs.lstatSync(filePath).isDirectory();
const isFile = filePath => fs.lstatSync(filePath).isFile();
const globSearch = pattern => {
const matches = glob.sync(pattern);
const files = matches.filter(match => isFile(match));
if (files.length === 0) {
logger.error("Could not find any files for: " + pattern, 1);
}
return files;
};
/** Recursively get all file paths. */
const getFilePaths = rootPath => {
const filePaths = [];
const paths = [rootPath];
while (paths.length > 0) {
const filePath = paths.shift();
if (filePath == null || filePath.length === 0) continue;
const isGlobPattern = glob.hasMagic(filePath);
if (isGlobPattern) {
filePaths.push(...globSearch(filePath));
continue;
}
if (fs.existsSync(filePath)) {
if (isFile(filePath)) {
filePaths.push(filePath);
} else if (isDirectory(filePath)) {
paths.push(path.join(filePath, "/**/*.*"));
}
} else {
logger.error(`Unable to resolve the path: ${filePath}`);
}
}
return filePaths;
};
/** Get a restructure map with rootPath keys and filePaths values. */
const getRestructureMap = rootPaths => rootPaths.reduce((acc, rootPath) => ({ ...acc,
[rootPath]: getFilePaths(rootPath)
}), {});
const {
argv
} = process;
const defaultOptions = {
const defaultConfig = {
help: false,
include: [],
version: false,
write: false
write: false,
avoidSingleFile: false
};

@@ -727,5 +786,6 @@

-V, --version output version number
-h, --help output usage information
-w, --write restructure and edit folders and files
-V, --version Output version number
-h, --help Output usage information
-w, --write Restructure and edit folders and files
-S, --avoid-single-file Flag to indicate if single files in folders should be avoided
`);

@@ -735,46 +795,61 @@ return process.exit(exitCode);

const parseArgs = args => args.reduce((acc, arg) => {
switch (arg) {
case "-h":
case "--help":
acc.options.help = true;
break;
const parseArgs = args => {
const cliConfig = {};
case "-V":
case "--version":
acc.options.version = true;
break;
while (args.length > 0) {
const arg = args.shift();
if (arg == null) break;
case "-w":
case "--write":
acc.options.write = true;
break;
switch (arg) {
case "-h":
case "--help":
cliConfig.help = true;
break;
default:
acc.rootPaths.push(arg);
case "-V":
case "--version":
cliConfig.version = true;
break;
case "-w":
case "--write":
cliConfig.write = true;
break;
case "-S":
case "--avoid-single-file":
cliConfig.avoidSingleFile = true;
case "-G":
default:
{
if (fs.existsSync(arg) || glob.hasMagic(arg)) {
var _cliConfig$include;
cliConfig.include = [...((_cliConfig$include = cliConfig.include) != null ? _cliConfig$include : []), arg];
}
}
}
}
return acc;
}, {
options: {},
rootPaths: []
});
return cliConfig;
};
const run = async args => {
const getMergedConfig = cliConfig => {
var _ref, _cosmiconfigSync$sear;
const config = (_ref = (_cosmiconfigSync$sear = cosmiconfig.cosmiconfigSync("destiny").search()) == null ? void 0 : _cosmiconfigSync$sear.config) != null ? _ref : {};
const {
options,
rootPaths
} = parseArgs(args);
const mergedOptions = { ...defaultOptions,
...config,
...options
const externalConfig = (_ref = (_cosmiconfigSync$sear = cosmiconfig.cosmiconfigSync("destiny").search()) == null ? void 0 : _cosmiconfigSync$sear.config) != null ? _ref : {};
return { ...defaultConfig,
...externalConfig,
...cliConfig
};
if (mergedOptions.help) return printHelp(0);
if (mergedOptions.version) return printVersion();
if (rootPaths.length === 0) return printHelp(1);
logger.info("Resolving files.");
const restructureMap = getRestructureMap(rootPaths);
};
const run = async args => {
const cliConfig = parseArgs(args);
const mergedConfig = getMergedConfig(cliConfig);
if (mergedConfig.help) return printHelp(0);
if (mergedConfig.version) return printVersion();
if (mergedConfig.include.length === 0) return printHelp(1);
const restructureMap = getRestructureMap(mergedConfig.include);
const filesToEdit = Object.values(restructureMap).flat();

@@ -787,5 +862,5 @@

const rootOptions = generateTrees(restructureMap);
const rootOptions = generateTrees(restructureMap, mergedConfig);
if (mergedOptions.write) {
if (mergedConfig.write) {
await formatFileStructure(filesToEdit, rootOptions);

@@ -792,0 +867,0 @@ }

#!/usr/bin/env node
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0}),require("core-js/modules/es.array.flat"),require("core-js/modules/es.array.unscopables.flat"),require("core-js/modules/es.promise");var n=e(require("chalk")),t=require("cosmiconfig"),r=require("fs-extra"),o=e(r),s=e(require("path")),i=e(require("simple-git/promise")),l=e(require("fs")),c=e(require("resolve")),a=e(require("glob"));var u=(e,t=0)=>{e instanceof Error?console.error(e):console.error(n`{red.bold ERROR:} ${e}`),console.log("If you think this is a bug, you can report it: https://github.com/benawad/destiny/issues"),process.exit(t)},f=e=>{console.info(n`{green.bold INFO:} ${e}`)},d=e=>{console.log(e)},p=e=>{console.warn(n`{yellow.bold WARN:} ${e}`)};const h=async(e,n)=>{const t=i(n);let r=!1;try{r=await t.checkIsRepo()}catch{}for(const[i,l]of Object.entries(e)){if(i.includes(".."))continue;const e=s.resolve(s.join(n,i)),c=s.resolve(s.join(n,l));if(e!==c){o.ensureDirSync(s.dirname(c));let n=!1;if(r)try{await t.silent(!0).raw(["ls-files","--error-unmatch",e]),n=!0}catch{}n?await t.mv(e,c):o.renameSync(e,c)}}};function m(e){const n=l.readdirSync(e);if(!n)return l.rmdirSync(e);for(const t of n){const n=s.resolve(e,t);l.lstatSync(n).isDirectory()&&(m(n),0===l.readdirSync(n).length&&l.rmdirSync(n))}}function g(e){const n=/(?:(?:from|import)\s+["'](\.[^'"]*)["'])|(?:(?:require|import)\s*\(["'](\.[^'"]*)["']\))/gm,t=[],r=l.readFileSync(e,{encoding:"utf8"}).toString().replace(/\/\*[^]*?\*\/|^.*\/\/.*$/gm,"");let o;for(;null!==(o=n.exec(r));){var s;o.index===n.lastIndex&&n.lastIndex++,t.push([e,null!=(s=o[1])?s:o[2]])}return t}const b=(e,n,t)=>{const r=s.dirname(e),o=s.relative(r,n),i=s.dirname(o),l=function(e){const n=s.extname(e);return[".js",".jsx",".ts",".tsx"].includes(n)?n:void 0}(o),c=s.basename(o,l);let a=s.join(i,c);return!a.startsWith(".")&&(a="./"+a),a=t?a.replace(/\\/g,"/"):a.replace(/\/|\\+/g,"\\\\"),a},y=[".js",".json",".jsx",".sass",".scss",".svg",".ts",".tsx"],v=(e,n)=>{try{return c.sync(e,{basedir:n,extensions:y})}catch(e){return null}},j=(e,n)=>{for(const{tree:t,parentFolder:r}of n){const n=s.relative(r,e);if(n in t)return s.resolve(s.join(r,t[n]))}return e},w=(e,n,t)=>{let r=!0;for(const{tree:o,parentFolder:i,useForwardSlash:l}of t){r=l;const t=s.relative(i,e);if(t in o)return b(n,s.resolve(s.join(i,o[t])),l)}return b(n,e,r)},x=async(e,n)=>{f("Fixing imports."),((e,n)=>{for(const t of e){const e=g(t);if(!e.length)continue;const o=s.dirname(t),i=j(t,n),l=r.readFileSync(t).toString();let c=l.repeat(1);for(const t of e){const e=v(t[1],o);if(null==e){u(`Cannot find import ${t[1]}`);continue}const r=w(e,i,n);r&&(c=c.replace(`'${t[1]}'`,`'${r}'`).replace(`"${t[1]}"`,`"${r}"`))}c!==l&&r.writeFileSync(t,c)}})(e,n);for(const{tree:e,parentFolder:t}of n)f("Moving files."),await h(e,t),m(t);f("Restructure was successful!")},S=e=>e.replace(/([^/]+)(?=\.)/g,String.fromCharCode(Number.MAX_SAFE_INTEGER)+"$1"),$=(e,n)=>S(e).localeCompare(S(n)),F=e=>{const t=(e=>{const n=[];let t=[...e];for(;t.length>0;){const e=t.shift();if(null==e)break;t=t.map(n=>{return t=e,n.replace(new RegExp(`^(/*)${t.replace(/\//g,"")}(/+)`),"$1$2");var t}),n.push(e)}return n.map(e=>{var n;const t=e.split("/");return{text:null!=(n=t.pop())?n:"",position:t.length}})})((e=>{const n=e.reduce((e,n)=>{const t=n.split("/");return t.forEach((n,r)=>e.add(((e,n)=>e.slice(0,n).join("/"))(t,r+1))),e},new Set);return Array.from(n).sort($)})(e)),r=t.reduce((e,r,o)=>{var s;const i=null!=(s=e[o-1])?s:"",l=t.slice(o+1),c=l.length>0&&l[0].position>r.position,a=(r.position>0?"│ ".repeat(r.position):"")+(((e,n)=>{for(const t of n)if(!(t.position>e.position))return t.position<e.position;return!0})(r,l)?"└──":"├──")+(c?n.bold.blue(r.text):r.text);return e.push(((e,n)=>Array.from(e).map((e,t)=>"│"===e&&(e=>"└"===e||" "===e)(n[t])?" ":e).join(""))(a,i)),e},[]).join("\n");return d(r),r},E=e=>{if(1===e.length)return s.dirname(e[0]);const n=[],t=e.map(e=>e.split("/"));return t[0].forEach((e,r)=>{t.every(n=>n[r]===e)&&n.push(e)}),n.join("/")};function O([e,n],t){e in t||(t[e]=[]),t[e].includes(n)||t[e].push(n)}const q=e=>/\.test\.|\.spec\.|\.stories\./.test(e);function k(e){const n=(e=>{const n={};return Object.keys(e).forEach(t=>{e[t].forEach(e=>{e in n||(n[e]=[]),n[e].push(t)})}),n})(e),t=Object.keys(e),r=t.filter(e=>{const t=n[e];return!t||!t.length||t.every(e=>q(e))});if(r.length)return r;const o={};t.forEach(e=>{const n=e.split("/").length;n in o||(o[n]=[]),o[n].push(e)});for(let e=1;e<10;e++)if(e in o)return o[e];return[]}const R=(e,n,t)=>{const r=n[e];if(t.has(e))return[...t,e];if(t.add(e),null==r||0===r.length)return null;for(const e of r){const r=R(e,n,new Set(t));if(r)return r}return null};function A(e){return Object.entries(e).reduce((e,[t,r])=>{if(r.length<=1)return e;f(`Generating tree for: ${t}`);const{graph:o,files:i,useForwardSlash:l,parentFolder:c}=function(e){const n=E(e),t={},r={},o=[];let i=0,l=0;for(let c of e){if(".git"===c)continue;c=s.resolve(c);const e=s.relative(n,c);e in r||(r[e]={oldLocation:c,imports:[]}),o.push(e),g(c).forEach(o=>{o[1].includes("/")?i++:o[1].includes("\\")&&l++;const c=v(o[1],s.dirname(o[0]));if(null==c)return void u(`Cannot find import ${o[1]}`);const a=s.relative(n,c);O([e,a],t),r[e].imports.push({text:o[1],resolved:a})})}return{parentFolder:n,graph:t,files:o,oldGraph:r,useForwardSlash:i>=l}}(r),a=function(e,n){const t={},r={},o=new Set;let i=!1;const l=(e,n)=>{Array.isArray(r[e])||(r[e]=[]),r[e].push(n)},c=(e,n,r)=>{var o;let i;return Object.values(t).includes(e)&&(i=s.join(n,r.replace(/\//g,"-")),f(`File renamed: ${r} -> ${i}`)),null!=(o=i)?o:e},a=(e,n,r)=>{const u=s.basename(e);if(q(u))return void o.add(e);let f=s.basename(e,s.extname(e));const d=s.basename(s.dirname(e)),h=e.includes("..");let m=h?e:s.join(n,"index"===f&&d&&"."!==d?d+s.extname(e):u);m=c(m,n,e),f=s.basename(m,s.extname(m)),h||(t[e]=m);const g=r[e];if((null==g?void 0:g.length)>0){const e=s.join(n,f);for(const n of g)if(n in t){const e=R(n,r,new Set);e?(i=!0,p(`Dependency cycle detected: ${e.join(" -> ")}`)):l(n,m)}else l(n,m),a(n,e,r)}};for(const t of n)a(t,"",e);if(i||Object.entries(r).forEach(([e,n])=>{if(n.length>1&&!e.includes("..")){const r=E(n),o=s.basename(e),i=s.basename(s.dirname(e));t[e]=s.join(r,"shared","index"===s.basename(o,s.extname(o))&&i&&"."!==i?i+s.extname(o):o)}}),o.size>0)for(const n of o){const[r]=e[n];if(!r)continue;const o=t[r];if(o){let e=s.join(s.dirname(o),s.basename(n));e=c(e,s.dirname(o),n),t[n]=e}}return t}(o,k(o)),h=new Set(Object.entries(o).flat(2)),m=i.filter(e=>!h.has(e));return d(n.bold.blue(t)),F(Object.values(a)),m.length>0&&p(`Found ${m.length} unused files:`+"\n"+m.join("\n")),e.push({parentFolder:c,tree:a,useForwardSlash:l}),e},[])}const C=e=>r.lstatSync(e).isDirectory(),I=e=>r.lstatSync(e).isFile(),P=e=>{const n=a.sync(e).filter(e=>I(e));return 0===n.length&&u("Could not find any files for: "+e,1),n},N=e=>{const n=[],t=[e];for(;t.length>0;){const e=t.shift();null!=e&&0!==e.length&&(a.hasMagic(e)?n.push(...P(e)):r.existsSync(e)?I(e)?n.push(e):C(e)&&t.push(s.join(e,"/**/*.*")):u(`Unable to resolve the path: ${e}`))}return n},{argv:D}=process,G={help:!1,version:!1,write:!1},M=e=>(console.log(n`{blue destiny} - Prettier for file structures.
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0}),require("core-js/modules/es.array.flat"),require("core-js/modules/es.array.unscopables.flat"),require("core-js/modules/es.promise");var n=e(require("chalk")),t=e(require("fs")),r=e(require("glob")),o=require("cosmiconfig"),s=e(require("path")),i=require("fs-extra"),c=e(i),l=e(require("simple-git/promise")),a=e(require("resolve"));var u=(e,t=0)=>{e instanceof Error?console.error(e):console.error(n`{red.bold ERROR:} ${e}`),console.log("If you think this is a bug, you can report it: https://github.com/benawad/destiny/issues"),process.exit(t)},f=e=>{console.info(n`{green.bold INFO:} ${e}`)},d=e=>{console.log(e)},p=e=>{console.warn(n`{yellow.bold WARN:} ${e}`)};const h=e=>i.lstatSync(e).isDirectory(),g=e=>i.lstatSync(e).isFile(),m=e=>{const n=r.sync(e).filter(e=>g(e));return 0===n.length&&u("Could not find any files for: "+e,1),n},b=e=>{const n=[],t=[e];for(;t.length>0;){const e=t.shift();null!=e&&0!==e.length&&(r.hasMagic(e)?n.push(...m(e)):i.existsSync(e)?g(e)?n.push(e):h(e)&&t.push(s.join(e,"/**/*.*")):u(`Unable to resolve the path: ${e}`))}return n};async function v(e,n){return e.silent(!0).raw(["ls-files","--error-unmatch",n]).then(()=>!0).catch(()=>!1)}async function y(e,n){const t=l(n),r=await t.checkIsRepo();for(const[o,i]of Object.entries(e)){if(o.includes(".."))continue;const e=s.resolve(n,o),l=s.resolve(n,i);if(e===l)continue;const a=s.dirname(l);c.ensureDirSync(a),r&&await v(t,e)?await t.mv(e,l):c.renameSync(e,l)}}function j(e){const n=t.readdirSync(e);if(!n)return t.rmdirSync(e);for(const r of n){const n=s.resolve(e,r);t.lstatSync(n).isDirectory()&&(j(n),0===t.readdirSync(n).length&&t.rmdirSync(n))}}function S(e){const n=/(?:(?:import|from)\s+|(?:import|require)\s*\()['"]((?:\.{1,2})(?:\/.+)?)['"]/gm,r=[],o=t.readFileSync(e,{encoding:"utf8"}).replace(/\/\*[^]*?\*\/|^.*\/\/.*$/gm,"");let s;for(;null!==(s=n.exec(o));)s.index===n.lastIndex&&n.lastIndex++,r.push(s[1]);return r}const w=(e,n,t)=>{const r=s.dirname(e),o=s.relative(r,n),i=s.dirname(o),c=function(e){const n=s.extname(e);return[".js",".jsx",".ts",".tsx"].includes(n)?n:void 0}(o),l=s.basename(o,c);let a=s.join(i,l);return!a.startsWith(".")&&(a="./"+a),a=t?a.replace(/\\/g,"/"):a.replace(/\/|\\+/g,"\\\\"),a},x=[".js",".json",".jsx",".sass",".scss",".svg",".ts",".tsx"],F=(e,n)=>{try{return a.sync(e,{basedir:n,extensions:x})}catch(e){return null}},$=(e,n)=>{for(const{tree:t,parentFolder:r}of n){const n=s.relative(r,e);if(n in t)return s.resolve(s.join(r,t[n]))}return e},O=(e,n,t)=>{let r=!0;for(const{tree:o,parentFolder:i,useForwardSlash:c}of t){r=c;const t=s.relative(i,e);if(t in o)return w(n,s.resolve(s.join(i,o[t])),c)}return w(n,e,r)},E=async(e,n)=>{f("Fixing imports."),((e,n)=>{for(const t of e){const e=S(t);if(!e.length)continue;const r=s.dirname(t),o=$(t,n),c=i.readFileSync(t).toString();let l=c.repeat(1);for(const t of e){const e=F(t,r);if(null==e){u(`Cannot find import ${t}`);continue}const s=O(e,o,n);null!=s&&(l=l.replace(`'${t}'`,`'${s}'`).replace(`"${t}"`,`"${s}"`))}l!==c&&i.writeFileSync(t,l)}})(e,n);for(const{tree:e,parentFolder:t}of n)f("Moving files."),await y(e,t),j(t);f("Restructure was successful!")},q=e=>e.replace(/([^/]+)(?=\.)/g,String.fromCharCode(Number.MAX_SAFE_INTEGER)+"$1"),k=(e,n)=>q(e).localeCompare(q(n)),A=e=>{const n=e.reduce((e,n)=>{const t=n.split("/");return t.forEach((n,r)=>e.add(((e,n)=>s.join(...e.slice(0,n)))(t,r+1))),e},new Set);return Array.from(n).sort(k)},R=e=>{const t=(e=>{const n=[];let t=[...e];for(;t.length>0;){const e=t.shift();if(null==e)break;t=t.map(n=>{return t=e,n.replace(new RegExp(`^(/*)${t.replace(/\//g,"")}(/+)`),"$1$2");var t}),n.push(e)}return n.map(e=>{var n;const t=e.split("/");return{text:null!=(n=t.pop())?n:"",position:t.length}})})(A(e)),r=t.reduce((e,r,o)=>{var s;const i=null!=(s=e[o-1])?s:"",c=t.slice(o+1),l=c.length>0&&c[0].position>r.position,a=(r.position>0?"│ ".repeat(r.position):"")+(((e,n)=>{for(const t of n)if(!(t.position>e.position))return t.position<e.position;return!0})(r,c)?"└──":"├──")+(l?n.bold.blue(r.text):r.text);return e.push(((e,n)=>Array.from(e).map((e,t)=>"│"===e&&(e=>"└"===e||" "===e)(n[t])?" ":e).join(""))(a,i)),e},[]).join("\n");return d(r),r},C=e=>{if(1===e.length)return s.dirname(e[0]);const[n,t]=e.length>2?e.sort((e,n)=>e.length-n.length):e,r=t.split(s.sep);return n.split(s.sep).filter((e,n)=>e===r[n]).join(s.sep)},I=e=>[/^\.git/].some(n=>n.test(e));const M=e=>/\.test\.|\.spec\.|\.stories\./.test(e);function N(e){const n=(e=>{const n={};return Object.keys(e).forEach(t=>{e[t].forEach(e=>{e in n||(n[e]=[]),n[e].push(t)})}),n})(e),t=Object.keys(e),r=t.filter(e=>{const t=n[e];return!t||!t.length||t.every(e=>M(e))});if(r.length)return r;const o={};t.forEach(e=>{const n=e.split("/").length;n in o||(o[n]=[]),o[n].push(e)});for(let e=1;e<10;e++)if(e in o)return o[e];return[]}const D=(e,n,t)=>{const r=n[e];if(t.has(e))return[...t,e];if(t.add(e),null==r||0===r.length)return null;for(const e of r){const r=D(e,n,new Set(t));if(r)return r}return null};const G=e=>{const n=e.split(s.sep);if(1!==n.length)return n.pop(),n.join(s.sep)},_=e=>{const n=e.split(s.sep);return[...n.slice(0,n.length-2),n[n.length-1]].join(s.sep)};function P(e,{avoidSingleFile:t}){return Object.entries(e).reduce((e,[r,o])=>{if(o.length<=1)return e;f(`Generating tree for: ${r}`);const{graph:i,files:c,useForwardSlash:l,parentFolder:a}=function(e){const n=C(e),t={},r=[];for(let o of e){if(I(o))continue;o=s.resolve(o);const e=s.relative(n,o);r.push(e),S(o).forEach(r=>{const i=F(r,s.dirname(o));if(null==i)return void u(`Cannot find import ${r}`);const c=s.relative(n,i);Array.isArray(t[e])||(t[e]=[]),t[e].includes(c)||t[e].push(c)})}return{files:r,graph:t,parentFolder:n,useForwardSlash:"/"===s.sep}}(o);let h=function(e,n){const t={},r=new Set,o={},i=new Set;let c=!1;const l=(e,n)=>{Array.isArray(o[e])||(o[e]=[]),o[e].push(n)},a=(e,n,t)=>{if(r.has(e)){const e=s.join(n,t.replace(/\//g,"-"));return f(`File renamed: ${t} -> ${e}`),e}return e},u=(e,n,o)=>{const f=s.basename(e);if(M(f))return void i.add(e);let d=s.basename(e,s.extname(e));const h=s.basename(s.dirname(e)),g=e.includes(".."),m=g?e:s.join(n,"index"===d&&h&&"."!==h?h+s.extname(e):f),b=a(m,n,e);d=s.basename(b,s.extname(b)),g||(t[e]=b,r.add(b));const v=o[e];if((null==v?void 0:v.length)>0){const e=s.join(n,d);for(const n of v)if(n in t){const e=D(n,o,new Set);e?(c=!0,p(`Dependency cycle detected: ${e.join(" -> ")}`)):l(n,b)}else l(n,b),u(n,e,o)}};for(const t of n)u(t,"",e);if(c||Object.entries(o).forEach(([e,n])=>{if(n.length<=1||e.includes(".."))return;const o=C(n),i=s.basename(e),c=s.dirname(e),l=s.join(o,"shared","index"===s.basename(i,s.extname(i))&&c&&"."!==c?s.join(c+s.extname(i)):i);t[e]=l,r.add(l)}),i.size>0)for(const n of i){const[o]=e[n];if(!o)continue;const i=t[o];if(!i)continue;const c=a(s.join(s.dirname(i),s.basename(n)),s.dirname(i),n);t[n]=c,r.add(c)}return t}(i,N(i));t&&(h=(e=>{const n={...e},t={};for(const[e,r]of Object.entries(n))t[r]=e;const r={},o=Object.values(n).sort((e,n)=>n.length-e.length);for(const e of o){const n=G(e);n&&(r[n]=n in r?r[n]+1:1)}for(const e of o){const o=G(e);if(!o)continue;let s=r[o],i=e,c=o;for(;1===s&&(c=G(i),c);)o===c?s=1:c in r&&(s=r[c]+1),r[c]=s,1===s&&(i=_(i));n[t[e]]=i}return n})(h));const g=new Set(Object.entries(i).flat(2)),m=c.filter(e=>!g.has(e));return d(n.bold.blue(r)),R(Object.values(h)),m.length>0&&p(`Found ${m.length} unused files:`+"\n"+m.join("\n")),e.push({parentFolder:a,tree:h,useForwardSlash:l}),e},[])}const{argv:T}=process,U={help:!1,include:[],version:!1,write:!1,avoidSingleFile:!1},V=e=>(console.log(n`{blue destiny} - Prettier for file structures.

@@ -12,5 +12,6 @@ {bold USAGE}

-V, --version output version number
-h, --help output usage information
-w, --write restructure and edit folders and files
`),process.exit(e)),_=async e=>{var n,r;const o=null!=(n=null==(r=t.cosmiconfigSync("destiny").search())?void 0:r.config)?n:{},{options:s,rootPaths:i}=(e=>e.reduce((e,n)=>{switch(n){case"-h":case"--help":e.options.help=!0;break;case"-V":case"--version":e.options.version=!0;break;case"-w":case"--write":e.options.write=!0;break;default:e.rootPaths.push(n)}return e},{options:{},rootPaths:[]}))(e),l={...G,...o,...s};if(l.help)return M(0);if(l.version)return console.log("v0.3.1");if(0===i.length)return M(1);f("Resolving files.");const c=(e=>e.reduce((e,n)=>({...e,[n]:N(n)}),{}))(i),a=Object.values(c).flat();if(0===a.length)return void u("Could not find any files to restructure",1);const d=A(c);l.write&&await x(a,d)};_(D.slice(2,D.length)),exports.run=_;
-V, --version Output version number
-h, --help Output usage information
-w, --write Restructure and edit folders and files
-S, --avoid-single-file Flag to indicate if single files in folders should be avoided
`),process.exit(e)),W=async e=>{const n=(e=>{var n,t;const r=null!=(n=null==(t=o.cosmiconfigSync("destiny").search())?void 0:t.config)?n:{};return{...U,...r,...e}})((e=>{const n={};for(;e.length>0;){const s=e.shift();if(null==s)break;switch(s){case"-h":case"--help":n.help=!0;break;case"-V":case"--version":n.version=!0;break;case"-w":case"--write":n.write=!0;break;case"-S":case"--avoid-single-file":n.avoidSingleFile=!0;case"-G":default:var o;if(t.existsSync(s)||r.hasMagic(s))n.include=[...null!=(o=n.include)?o:[],s]}}return n})(e));if(n.help)return V(0);if(n.version)return console.log("v0.4.0");if(0===n.include.length)return V(1);const s=n.include.reduce((e,n)=>({...e,[n]:b(n)}),{});const i=Object.values(s).flat();if(0===i.length)return void u("Could not find any files to restructure",1);const c=P(s,n);n.write&&await E(i,c)};W(T.slice(2,T.length)),exports.run=W;
{
"name": "destiny",
"version": "0.3.1",
"version": "0.4.0",
"description": "Prettier for file structures",

@@ -21,3 +21,3 @@ "license": "MIT",

"check": "tsc",
"clean": "rimraf lib",
"clean": "rimraf coverage lib",
"format": "run-s format:*",

@@ -31,2 +31,3 @@ "format:eslint": "npm run lint -- --fix",

"test": "jest --colors",
"test:coverage": "npm run test -- --coverage",
"watch": "npm run build -- --watch"

@@ -61,6 +62,12 @@ },

"@typescript-eslint/parser": "^2.19.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^25.1.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-config-standard": "^14.1.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"husky": ">=4",

@@ -67,0 +74,0 @@ "jest": "^25.1.0",

@@ -1,9 +0,29 @@

# destiny
# Destiny
Prettier for File Structures
<img align="center" alt="example transformation" src="https://raw.githubusercontent.com/benawad/destiny/master/assets/example.png" />
[![npm version](https://badge.fury.io/js/destiny.svg)](https://badge.fury.io/js/destiny)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/benawad/destiny/issues)
[![](https://github.com/benawad/destiny/workflows/ci/badge.svg)](https://github.com/benawad/destiny/actions?query=workflow%3Aci) [![Join the chat at https://gitter.im/destiny-dev/community](https://badges.gitter.im/destiny-dev/community.svg)](https://gitter.im/destiny-dev/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<h2 align="center">Prettier for File Structures</h2>
<p align="center">
<a href="https://www.npmjs.com/package/destiny">
<img alt="npm version" src="https://badge.fury.io/js/destiny.svg">
</a>
<a href="https://github.com/benawad/destiny/issues">
<img alt="contributions welcome" src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat">
</a>
<a href="https://github.com/benawad/destiny/actions?query=workflow%3Aci">
<img alt="ci workflow" src="https://github.com/benawad/destiny/workflows/ci/badge.svg">
</a>
<a href="https://gitter.im/destiny-dev/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge">
<img alt="Join the chat at https://gitter.im/destiny-dev/community" src="https://badges.gitter.im/destiny-dev/community.svg">
</a>
<a href="https://github.com/benawad/destiny">
<img alt="file structure: destiny" src="https://img.shields.io/badge/file%20structure-destiny-7a49ff?style=flat">
</a>
</p>
---

@@ -13,4 +33,2 @@

![example transformation](https://github.com/benawad/destiny/blob/master/assets/example.png)
## What does this do?

@@ -38,5 +56,10 @@

Dry run which will output what the resulting file structure will look like:
```
npx destiny "src/**/*.*"
```
This will actually move files around and fix imports:
```
npx destiny -w "src/**/*.*"
```

@@ -53,2 +76,10 @@ ## This tool might be useless

pull requests are welcome :)
Pull requests are welcome :)
## Badge
[![file structure: destiny](https://img.shields.io/badge/file%20structure-destiny-7a49ff?style=flat)](https://github.com/benawad/destiny)
```
[![file structure: destiny](https://img.shields.io/badge/file%20structure-destiny-7a49ff?style=flat)](https://github.com/benawad/destiny)
```

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc