conartist v0.29.1
Conartist
Scaffold out and keep all your files in sync over time. Code-shifts for your file system.
Conartist is a tool that allows you to scaffold out and maintain your project configurations over time.
- ā Keeping separate repos in sync.
- š¦ Keeping monorepo packages in sync.
- š Scaffolding out new projects.
- š Works well with
workspaces.
Install
npm i -D conartistConartist can be configured by any one of the following:
conartistfield in thepackage.json.conartistrc.conartistrc.json.conartistrc.yaml.conartistrc.yml.conartistrc.js.conartist.config.js
If you use a .js file, you will be able to have finer-grained control over
your configuration. More on this later.
CLI
$ conartist --help
Description
Declarative project scaffolding and synchronisation.
Usage
$ conartist <command> [options]
Available Commands
default Run the default configuration.
init Creates a basic configuration file.
For more info, run any command with the `--help` flag
$ conartist default --help
$ conartist init --help
Options
-v, --version Displays current version
-d, --dry Perform a dry run.
-h, --help Displays this messageGetting started
You can run:
$ conartist init .It will output:
/path/to/cwd
A conartist.config.jsWhich tells you that it added a conartist.config.js file to your current
working directory.
If you open the new conartist.config.js you should see something like:
module.exports = { files: [] };Simple example
If you put the following in a package.json.
{
"conartist": {
"files": {
".gitignore": "node_modules",
".nvmrc": "10.16.0",
".travis.yml": "language: node_js",
"src/index.js": "module.exports = {};"
}
}
}Now run conartist on the current working directory:
$ conartist .
/path/to/cwd
A .gitignore
A .nvmrc
A .travis.yml
A src/index.jsResulting in the following file structure:
āā src
ā āā index.js
āā .gitignore
āā .nvmrc
āā .travis.ymlThe key from each entry is the file path relative to the cwd and the value
becomes the file contents.
Configuration
The conartist configuration is a config object or a function that returns
a config object.
All options are optional.
A files object is the simpler form of configuration when you don't need to
specify any other options.
module.exports = {
files: {
"src/index.js": "module.exports = {};"
}
};A files array allows you to specify more options.
module.exports = {
// The these are merged with each entry in `files` but do not
// override them.
fileDefaults: {
merge: false,
overwrite: false,
remove: false
},
files: [
{
// The name of the file relative to the directory it is run in.
// In the `files` object, this is the key.
name: "src/index.js",
// The contents of the file. In the `files` object this is the
// value.
data: "module.exports = {};",
// Whether or not to attempt merging with any existing file if
// supported by the data type.
merge: false,
// Whether or not to override the existing file.
overwrite: false,
// Whether or not the file should be removed. This superseces
// any other option because the file is deleted.
remove: false,
// The data type to handle the file as. Built-in data types are
// listed below. By default this is inferred from the file
// extension. If a data type for the file extension cannot be
// found, the typeof the value is used. If it still can't find
// a data type, it coerces it to a string. To specify your own
// data type, use a function.
type: "js"
}
]
};Includes is just an array of configurations that also allow you to use module-specifier strings for loading external configurations.
module.exports = {
// These only act as defaults for `files` in the config in which they
// are specified and do not affect anything in `includes`.
fileDefaults: {},
includes: [
[
// This is just a standard config as specified for module.exports.
{
files: [
{
name: "src/index.js",
data: "module.exports = {};"
}
]
}
]
]
};As noted above, you can also specify includes using module-specifiers.
module.exports = {
includes: [
// Loaded via node_modules.
"some-module-config",
// Loaded relative to the CWD.
"./path/to/config",
// Use this form if your config will be used as an include because
// paths are resolved relative to where the config is run from.
require("some-module-config"),
require("./path/to/config")
]
};Making includes just standard configurations means that an include can just be
any old configuration and they're resolved recursively down the tree. The outer
configurations are applied after the inner configurations, but they do not
override them, allowing them to be composed.
Built-in data types
These types correspond to the extname of the name option, or can be
explicitly specified as a type.
jstakesdataas astringand formats it usingprettier.overwrite: falseExisting file is preserved.overwrite: trueNew data overwrites existing file.
jsxalias forjs.jsontakesdataas JSON and stringifies it.merge: false, overwrite: falseprefers existing values.merge: false, overwrite: trueprefers new values.merge: true, overwrite: falsemerges values, preferring existing values.merge: true, overwrite: truemerge values, preferring new values.
mdtakesdataas a string and formats it usingprettier.overwrite: falseExisting file is preserved.overwrite: trueNew data overwrites existing file.
mdxalais formd.
API
All exported API points are documented below.
async bin(opt) - automated CLI
The bin function automates a lot of the boilerplate in creating a CLI tool.
It's intended to jump-start your ability for you to create a Conartist config
that can be run by simply typing npx your-command. This idea was borrowed from
https://www.npmjs.com/package/travis.yml.
A big bonus of doing things this way is that your consumers don't need
conartist to be installed and serveral commands can work in harmony even if
they depend on different versions of conartist.
The available options are:
namethe name of your CLI. Defaults to"".descriptionthe description of your CLI. Defaults to"".versionthe version of your CLI. Defaults to"0.0.0".conartisttheconartistconfiguration as normally specified in a config file. Defaults to{}.optionscustom CLI options. Each key is the option name and each value can either be astringand will be the description, or it allows an object that may contain:aliasthe option alias (i.e.-a).defaultthe default value.descriptionthe option description.questionaninquirerquestion object.
commandscustom CLI sub-commands. Each key is the command name and each value can either be astringand will be the description, or it allows:descriptionthe command description.optionsan object of options as described above for global options.
The following example creates a npx license-mit command.
package.json
{
"name": "license-mit",
"description": "Creates and maintains an MIT license in your projects.",
"author": "Your Name <you@yourdomain.com>",
"version": "1.0.0",
"bin": "."
}bin.js
The following bin.js uses information from your package.json to define
metadata, and then specifies the conartist option to specify the conartist
configuration. You could have specified conartist in your package.json, but
we wanted the ability to use template literals, thus opted to specify it as a
JavaScript object instead.
#! /usr/bin/env node
const { bin } = require("conartist");
const pkg = require("./package.json");
bin({
...pkg,
conartist: {
files: {
LICENSE: `
Copyright 2019 ${pkg.author}
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`
}
}
});Resulting LICENSE
Copyright 2019 Your Name <you@yourdomain.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.Testing
You can now test to see if your command works by running npx .:
$ npx . .
/path/to/cwd
A LICENSECustomize using CLI arguments
In the above example, the configuration is specified using an object. However,
you could also specify a function returning an object that gets the following
options passed in:
clithe arguments parsed from the CLI. This allows you to add custom options and use them to generate your config.cmdthe sub-command that was run. Defaults to"default".cwdthe current working directory that the config is running in.optthe options that you originally passed in tobin(opt).
If you wanted to accept a custom author, you could set it up as an option and
default it to what's in the package.json.
#! /usr/bin/env node
const { bin } = require("conartist");
const pkg = require("./package.json");
bin({
...pkg,
options: {
author: {
alias: "a",
default: pkg.author,
description: "The package author."
}
},
conartist: ({ cli }) => ({
files: {
LICENSE: `
Copyright 2019 ${cli.author}
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`
}
})
});Now you can run:
$ npx . . -a "Custom Author"
/path/to/cwd
A LICENSEAccepting input via prompts
You could take this a step further and prompt the user for input if an option
isn't provided. It won't prompt the user for input if a default is provided,
so you must remove the default from the option. If you want to provide a
default for the question, then just add it as the default for the question, as
seen below.
#! /usr/bin/env node
const { bin } = require("conartist");
const pkg = require("./package.json");
bin({
...pkg,
options: {
author: {
alias: "a",
description: "The package author.",
question: {
default: pkg.author,
message: "What author should we use?"
}
}
},
conartist: ({ cli }) => ({
files: {
LICENSE: `
Copyright 2019 ${cli.author}
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`
}
})
});Now when you run the command without the --author option, it will prompt you
to fill it in.
$ npx . .
? What author should we use? Your Name <you@yourdomain.com>
/path/to/cwd
O LICENSEBuilt-in features
The bin function automates quite a bit for you.
Running in specific directories:
$ npx . path/to/new path/to/existing
A path/to/new/LICENSE
U path/to/existing/LICENSEHelp:
$ npx . --help
Description
Creates and maintains an MIT license in your projects.
Usage
$ mit-license <command> [options]
Available Commands
default Run the default configuration.
For more info, run any command with the `--help` flag
$ mit-license default --help
Options
-v, --version Displays current version
-h, --help Displays this messageVersion:
$ npx . --version
1.0.0Publishing and running
You can now run np and your command is
runnable via npx license-mit anywhere.
async sync(cfg, opt) - programmatic config application
The sync function takes a configuration as cfg, normalizes it with opt and
applies it to your cwd.
The available options are:
cwda custom current working directory to apply the configuration to. Defaults to".".dryperform a dry run (does not modify any files, just outputs what would happen to them).eventsan instance of anEventEmitter(use via the built-in module:require("events")). Supported events are:file, { action, file }when a file is affected. Thefileargument is the file, relative to thecwdandactionis the action that was taken on the file.info, messagewheninfois logged. Themessageargument is the info message.warn, messagewhenwarnis logged. Themessageis the warning.
const { sync } = require("conartist");
sync(
{
files: {
".travis.yml": "language: node_js"
}
},
{
cwd: "packages/sub-package"
}
);Just like with bin, if you specify a function as cfg, the options you pass
in are passed to it:
const { sync } = require("conartist");
sync(
({ language }) => ({
files: {
".travis.yml": "language: node_js"
}
}),
{
language: "node_js"
}
);6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago