I've been thinking about and working on this project for weeks and am growing a passion towards it.
Thank you for all being so accepting, patient and prompt in your responses.
I'd like to voice some ideas and possible solutions. There's a lot here, so take your time to read and respond if you choose to do so.
Quality of life
Refactor
A great idea, but some of the code is messy, hard to interpret and difficult to test. I've posted a few pulls to refactor code. I will keep doing this, taking anything from this discussion into account.
Config File
I personally would prefer a configuration that supports destiny.config.(ts|js)
, with the default export as what will be read.
If typescript, the user should have ts-node
installed . This way we can assign an interface to the object. I'm pretty sure webpack and/or rollup have this feature built in.
Architecture
I think we can start researching how we may implement an architecture that can support other file extensions via middleware. Prettier has something similar for each language they support, which include parsers and formatting rules.
The way this program could be laid out:
- Create graph representing current structure
a. Find a file
b. Add import path to graph
- Create graph representing new structure
a. ...details
- Move files and folder structure
There are some details that I've overlooked, but it's general.
Graphs
Currently we're managing our own graphs. It is simple with object-index pattern:
{ [index: string]: string }
.
It works with strings as the nodes, but what if we ever needed to use an instance on each end? We'd have to rewrite it.
I believe we should go down the OOP route for our graph generation and management. It would make extensibility and management easier. I love functional programming, but well managed mutability is where the power is in graphs!
We could use a library for manipulating graphs called cytoscape.js, which comes with some fantastic abstractions.
On first glance it looks like it's built to support the DOM. However, it can run in headless mode, meaning all the rendering capabilities are disabled and it can be used to strictly manipulate data. Score!
CLI API
I wrote a cli in yargs
and came up with this:
Usage: index.ts [options] [files / regex]
Dry run and preview directory structure:
index.ts src/**/*.*
Write the changes:
index.ts -w src/**/*.*
Options:
--help Show help [boolean]
--version Show version number [boolean]
--config, -c path to your config file.
Can be in any language supported by destiny.
--dir, -d Sets the root directory
--init Creates a `destiny.config.*`, defaulting to `.ts`
file extension [choices: "ts", "js"]
--interactive, -I Prompts user to process directory structure
when a dry run is complete
--ignore, -i Locations to be ignored whilst processing [array]
--subfolder, -s Operates on each folder in the directory,
instead of on the directory itself [count]
--test, -t A regex to match test files against [string]
--write, -w Writes the changes to the directory [boolean]
Supported formats:
.js, .jsx, .ts, .tsx
Generated by this:
import * as yargs from "yargs";
const argv = yargs
.usage(
`
Usage: $0 [options] [files / regex]
Dry run and preview directory structure:
$0 src/**/*.*
Write the changes:
$0 -w src/**/*.*
`
)
.epilogue("Supported formats:")
.epilogue(" .js, .jsx, .ts, .tsx")
.demandCommand(1)
.option("config", {
alias: "c",
description: `path to your config file.
Can be in any language supported by destiny.`
})
.option("dir", {
alias: "d",
description: `Sets the root directory`
})
.option("init", {
description: `Creates a \`destiny.config.*\`, defaulting to \`.ts\`
file extension`,
choices: ["ts", "js"]
})
.option("interactive", {
alias: "I",
description: `Prompts user to process directory structure
when a dry run is complete`
})
.option("ignore", {
alias: "i",
array: true,
description: `Locations to be ignored whilst processing`
})
.option("subfolder", {
alias: "s",
count: true,
description: `Operates on each folder in the directory,
instead of on the directory itself`
})
.option("test", {
alias: "t",
string: true,
boolean: true,
description: `A regex to match test files against`
})
.option("write", {
alias: "w",
boolean: true,
description: `Writes the changes to the directory`
}).argv;