mnp
v1.2.1
Published
Create Packages From GitHub Templates. My New Package is an installer of new packages via GitHub templates: create a template and add an automated script to CLI questions, update files, access GitHub API and spawn commands during generation.
Downloads
62
Maintainers
Readme
mnp
mnp
aka My New Package is a Node.JS CLI binary that allows to quickly create new Node.js (or any other language) packages from GitHub templates and with a GitHub repository.
MNP provides a number of modern essential templates for package and web development with default structures (src
, test
, package.json
, etc).
- 📦 Package Template: the most essential Node.JS package structure with automated documentation and wiki pages, context and mask testing, 0-dependency import/export transpiler and Closure Compiler integration to properly compile Node.JS packages.
- 🥝 Splendid Template: vital static website generator that utilises Closure Stylesheets to minify CSS, supports JSX syntax for Preact components and statically rendered HTML.
But in addition to the provided templates, you can point to your own GitHub template, which will contain the installation script. The installation script receives access to the API and allows to ask additional questions, e.g.,
// mnp/index.js
export default {
questions: {
website: {
text: 'Website',
getDefault({ org, name }) {
return `https://${org}.github.io/${name}`
},
async afterQuestions({ github }, answer, { org, name }) {
await github.pages.enable(org, name, {
branch: 'master',
path: '/docs',
})
}
}
}
}
Table Of Contents
CLI: mnp my-new-package
The default mode is to start creating a package. If package-name
is not passed, the program will run in interactive mode and ask to enter details.
To use the binary, enter mnp cool-package-name
, or just mnp
to be asked for the name. mnp
will check if the directory name is not taken and that the current working directory ins not in a git path, generate a new Github
repository from the template, star it and clone it to the local filesystem.
The default template used is mnpjs/package
however it can be either overridden in settings during initialisation, or via the -t org/template
flat.
-I
, --init
: Configure
When launched for the first time, mnp
will ask to complete the set-up process and create a .mnprc
file in the directory from which it was called. It is possible to create a default .mnprc
in the HOME
directory to remember the token and other standard settings, and then initialise mnp
in other directories, then MNP will reuse the settings from the HOME
config, but ask for more details for the current folder. This way, it is easy to manage different organisations and scopes, while reusing the access token.
Settings
-h
, --help
: Show Help
MNP: create My New Package.
If no package name is given as the first argument, the program will ask
for it in the CLI. A GitHub repository for each new package will be
created automatically, and a GitHub token can be generated at:
https://github.com/settings/tokens for the use in this application.
The token is saved in the CWD/.mnprc file along with other configuration,
including organisation name etc. Different types of packages, with a
modern Node.JS library by default are available, including:
package: a modern Node.JS package to publish on npm (default)
https://github.com/mnpjs/package
splendid: a static website using Splendid
https://github.com/mnpjs/splendid
mnp [name] [-t template] [-D description] [-@ scope|-n] [-pcId] [-hv]
name The name of the new package.
--template, -t The template to generate from.
--private, -p Create a private repository.
--desc, -D The description to add.
--check, -c Just query NPM registry to see if the package exists.
--delete, -d Remove the repository from GitHub.
--init, -I Initialise MNP config in this directory, creating `.mnprc`.
--no-scope, -n Don't use a scope for this package.
--scope, -@ Use this specific scope for the package.
--repo, -r The name of the repository. By default, the package
name is used, but can be overridden.
--help, -h Print the help information and exit.
--version, -v Show the version's number and exit.
Example:
mnp my-new-package -t org/template
-c
, --check
: Check Exists
Check if the package name is already taken or not.
| Command | Output |
| --------------- | ------------------------------ |
| mnp taken -c
| |
| mnp isfree -c
| |
-d
, --delete
: Delete Repository
Delete specified repository from GitHub
. Useful when a package was created for testing. The organisation name will be read from the configuration.
mnp package -d
-@
, --scope
: Set Scope
When a particular scope needs to be specified for the package, the -@
option can be used.
mnp package -@ superscope
-n
, --no-scope
: Disable Scope
If the settings read from .mnprc
contained an NPM scope, but it is not needed for the particular package, it can be disabled with this option.
mnp package -n
Templates
When the structure is passed as org/name
, MNP will use that template to create a new package. This means you can use your own templates and exploit the functionality of MNP. Everything that is published on GitHub, will be present in the new repository.
Writing Scripts
The installation scripts are essential to update the newly created structure to the correct values. Upon installation, mnp
will create a list of all files in the project directory, so that any transformations will be run on them. A braces {{ repo }}
templating notation is used in files for the replacement of settings. By default, the following files are added:
- files:
['LICENSE', '.gitignore', '.eslintrc']
- extensions:
['js', 'jsx', 'md', 'html', 'json', 'css', 'xml']
But this can be overriden by scripts:
// mnp.js
export default {
files: {
extensions: ['txt'], // override
extensions(ext) {
return [...ext, 'txt']
}, // extend
filenames: ['COPYING'], // override
filenames(fn) {
return [...fn, 'COPYING']
}, // extend
},
}
script structure
The script should be placed in the mnp/index.js
or mnp.js
file in the template. It should export default object, and can use Node.JS API:
export default {
// add some MNP questions
mnpQuestions: ['wiki', 'license', 'homepage', 'keywords'],
questions: {
binary: {
confirm: true,
text: 'With binary',
async afterQuestions({ rm, removeFile, updateFiles, packageJson, updatePackageJson }, withBinary) {
if (withBinary) return
delete packageJson.bin
updatePackageJson(packageJson)
await updateFiles({
re: /\nlet BIN[\s\S]+/,
replacement: '',
}, { file: 'test/context/index.js' })
},
},
},
async preUpdate({ repo: { owner: { avatar_url } } }, { updateFiles }) {
await updateFiles({
re: 'https://avatars3.githubusercontent.com/u/38815725?v=4',
replacement: avatar_url,
}, { file: '.documentary/index.jsx' })
},
async afterInit({ name }, { renameFile, initManager }) {
renameFile('compile/bin/mnp.js', `compile/bin/${name}.js`)
renameFile('compile/mnp.js', `compile/${name}.js`)
renameFile('compile/mnp.js.map', `compile/${name}.js.map`)
renameFile('src/bin/mnp.js', `src/bin/${name}.js`)
renameFile('build/bin/mnp.js', `build/bin/${name}.js`)
await initManager()
},
}
questions
The questions are specified as a hash map, and the logic should be handled in the afterQuestions
function. These functions receive the MNP API as the first argument, then the answer, then all settings. We're working on making autocompletions available.
mnpQuestions
These are standard questions that can benefit any new package.
wiki
: if set, will initialise the wiki submodule in the project dir.license
: allows to pick a license, updatepackage.json
with its SPDX and add the license file into the project.homepage
: asks for the homepage to add topackage.json
and sets theGitHub
URL if given.keywords
: creates an array of keywords to add topackage.json
and setsGitHub
topics.
hooks
There are a number of hooks executed at different stages:
preUpdate
: just before all files are updated.afterInit
: after the files are updated, before the installer commit.afterCommit
: after the initial commit, right before push.
existing scripts
You can study some of the existing scripts to get the idea:
file templates
When using variables in files, they are written as {{ var }}
or {{ var.inner }}
. The root variable is called Settings and contains the basic replacements:
{
"scope": "artdeco",
"org": "art-deco",
"name": "test3",
"email": "[email protected]",
"website": "https://www.artd.eco",
"trademark": "Art Deco™",
"legalName": "Art Deco Code Limited",
"manager": "yarn",
"packageName": "@artdeco/test3",
"author_name": "Anton",
"author_email": "[email protected]",
"repo": { "SEE REPO" },
"description": "Testing new package.",
"binary": true,
"compile": "compile",
"license": "agpl-3.0",
"wiki": false,
"homepage": "https://github.com/art-deco/test3#readme",
"keywords": ["topic1", "topic2"],
"license_spdx": "AGPL-3.0",
"license_name": "GNU Affero General Public License v3.0",
"package-name": "@artdeco/test3",
"full-name": "@artdeco/test3",
"legal-name": "Art Deco Code Limited",
"legal_name": "Art Deco Code Limited",
"create_date": "3 December 2019",
"create-date": "3 December 2019",
"year": "2019"
}
The repo
object has the following structure:
"repo" {
"id": 225554291,
"node_id": "MDEwOlJlcG9zaXRvcnkyMjU1NTQyOTE=",
"name": "test3",
"full_name": "art-deco/test3",
"owner": {
"login": "art-deco",
"id": 57873407,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjU3ODczNDA3",
"avatar_url": "https://avatars2.githubusercontent.com/u/57873407?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/art-deco",
"html_url": "https://github.com/art-deco",
"followers_url": "https://api.github.com/users/art-deco/followers",
"following_url": "https://api.github.com/users/art-deco/following{/other_user}",
"gists_url": "https://api.github.com/users/art-deco/gists{/gist_id}",
"starred_url": "https://api.github.com/users/art-deco/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/art-deco/subscriptions",
"organizations_url": "https://api.github.com/users/art-deco/orgs",
"repos_url": "https://api.github.com/users/art-deco/repos",
"events_url": "https://api.github.com/users/art-deco/events{/privacy}",
"received_events_url": "https://api.github.com/users/art-deco/received_events",
"type": "Organization",
"site_admin": false
},
"private": false,
"html_url": "https://github.com/art-deco/test3",
"description": "Testing new package.",
"fork": false,
"url": "https://api.github.com/repos/art-deco/test3",
"forks_url": "https://api.github.com/repos/art-deco/test3/forks",
"keys_url": "https://api.github.com/repos/art-deco/test3/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/art-deco/test3/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/art-deco/test3/teams",
"hooks_url": "https://api.github.com/repos/art-deco/test3/hooks",
"issue_events_url": "https://api.github.com/repos/art-deco/test3/issues/events{/number}",
"events_url": "https://api.github.com/repos/art-deco/test3/events",
"assignees_url": "https://api.github.com/repos/art-deco/test3/assignees{/user}",
"branches_url": "https://api.github.com/repos/art-deco/test3/branches{/branch}",
"tags_url": "https://api.github.com/repos/art-deco/test3/tags",
"blobs_url": "https://api.github.com/repos/art-deco/test3/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/art-deco/test3/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/art-deco/test3/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/art-deco/test3/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/art-deco/test3/statuses/{sha}",
"languages_url": "https://api.github.com/repos/art-deco/test3/languages",
"stargazers_url": "https://api.github.com/repos/art-deco/test3/stargazers",
"contributors_url": "https://api.github.com/repos/art-deco/test3/contributors",
"subscribers_url": "https://api.github.com/repos/art-deco/test3/subscribers",
"subscription_url": "https://api.github.com/repos/art-deco/test3/subscription",
"commits_url": "https://api.github.com/repos/art-deco/test3/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/art-deco/test3/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/art-deco/test3/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/art-deco/test3/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/art-deco/test3/contents/{+path}",
"compare_url": "https://api.github.com/repos/art-deco/test3/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/art-deco/test3/merges",
"archive_url": "https://api.github.com/repos/art-deco/test3/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/art-deco/test3/downloads",
"issues_url": "https://api.github.com/repos/art-deco/test3/issues{/number}",
"pulls_url": "https://api.github.com/repos/art-deco/test3/pulls{/number}",
"milestones_url": "https://api.github.com/repos/art-deco/test3/milestones{/number}",
"notifications_url": "https://api.github.com/repos/art-deco/test3/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/art-deco/test3/labels{/name}",
"releases_url": "https://api.github.com/repos/art-deco/test3/releases{/id}",
"deployments_url": "https://api.github.com/repos/art-deco/test3/deployments",
"created_at": "2019-12-03T07:10:49Z",
"updated_at": "2019-12-03T07:10:49Z",
"pushed_at": "2019-12-03T07:10:49Z",
"git_url": "git://github.com/art-deco/test3.git",
"ssh_url": "[email protected]:art-deco/test3.git",
"clone_url": "https://github.com/art-deco/test3.git",
"svn_url": "https://github.com/art-deco/test3",
"homepage": null,
"size": 0,
"stargazers_count": 0,
"watchers_count": 0,
"language": null,
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 0,
"license": null,
"forks": 0,
"open_issues": 0,
"watchers": 0,
"default_branch": "master",
"permissions": {
"pull": true,
"push": true,
"admin": true
},
"is_template": false,
"template_repository": {
"id": 225164794,
"node_id": "MDEwOlJlcG9zaXRvcnkyMjUxNjQ3OTQ=",
"name": "package",
"full_name": "mnpjs/package",
"owner": {
"login": "mnpjs",
"id": 40581896,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjQwNTgxODk2",
"avatar_url": "https://avatars2.githubusercontent.com/u/40581896?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/mnpjs",
"html_url": "https://github.com/mnpjs",
"followers_url": "https://api.github.com/users/mnpjs/followers",
"following_url": "https://api.github.com/users/mnpjs/following{/other_user}",
"gists_url": "https://api.github.com/users/mnpjs/gists{/gist_id}",
"starred_url": "https://api.github.com/users/mnpjs/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/mnpjs/subscriptions",
"organizations_url": "https://api.github.com/users/mnpjs/orgs",
"repos_url": "https://api.github.com/users/mnpjs/repos",
"events_url": "https://api.github.com/users/mnpjs/events{/privacy}",
"received_events_url": "https://api.github.com/users/mnpjs/received_events",
"type": "Organization",
"site_admin": false
},
"private": false,
"html_url": "https://github.com/mnpjs/package",
"description": "A Node.JS package template.",
"fork": false,
"url": "https://api.github.com/repos/mnpjs/package",
"forks_url": "https://api.github.com/repos/mnpjs/package/forks",
"keys_url": "https://api.github.com/repos/mnpjs/package/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/mnpjs/package/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/mnpjs/package/teams",
"hooks_url": "https://api.github.com/repos/mnpjs/package/hooks",
"issue_events_url": "https://api.github.com/repos/mnpjs/package/issues/events{/number}",
"events_url": "https://api.github.com/repos/mnpjs/package/events",
"assignees_url": "https://api.github.com/repos/mnpjs/package/assignees{/user}",
"branches_url": "https://api.github.com/repos/mnpjs/package/branches{/branch}",
"tags_url": "https://api.github.com/repos/mnpjs/package/tags",
"blobs_url": "https://api.github.com/repos/mnpjs/package/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/mnpjs/package/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/mnpjs/package/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/mnpjs/package/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/mnpjs/package/statuses/{sha}",
"languages_url": "https://api.github.com/repos/mnpjs/package/languages",
"stargazers_url": "https://api.github.com/repos/mnpjs/package/stargazers",
"contributors_url": "https://api.github.com/repos/mnpjs/package/contributors",
"subscribers_url": "https://api.github.com/repos/mnpjs/package/subscribers",
"subscription_url": "https://api.github.com/repos/mnpjs/package/subscription",
"commits_url": "https://api.github.com/repos/mnpjs/package/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/mnpjs/package/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/mnpjs/package/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/mnpjs/package/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/mnpjs/package/contents/{+path}",
"compare_url": "https://api.github.com/repos/mnpjs/package/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/mnpjs/package/merges",
"archive_url": "https://api.github.com/repos/mnpjs/package/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/mnpjs/package/downloads",
"issues_url": "https://api.github.com/repos/mnpjs/package/issues{/number}",
"pulls_url": "https://api.github.com/repos/mnpjs/package/pulls{/number}",
"milestones_url": "https://api.github.com/repos/mnpjs/package/milestones{/number}",
"notifications_url": "https://api.github.com/repos/mnpjs/package/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/mnpjs/package/labels{/name}",
"releases_url": "https://api.github.com/repos/mnpjs/package/releases{/id}",
"deployments_url": "https://api.github.com/repos/mnpjs/package/deployments",
"created_at": "2019-12-01T13:19:12Z",
"updated_at": "2019-12-03T06:02:55Z",
"pushed_at": "2019-12-03T06:02:53Z",
"git_url": "git://github.com/mnpjs/package.git",
"ssh_url": "[email protected]:mnpjs/package.git",
"clone_url": "https://github.com/mnpjs/package.git",
"svn_url": "https://github.com/mnpjs/package",
"homepage": null,
"size": 98,
"stargazers_count": 1,
"watchers_count": 1,
"language": "JavaScript",
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 0,
"license": null,
"forks": 0,
"open_issues": 0,
"watchers": 1,
"default_branch": "master",
"permissions": {
"pull": true,
"push": true,
"admin": true
},
"is_template": true
},
"organization": {
"login": "art-deco",
"id": 57873407,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjU3ODczNDA3",
"avatar_url": "https://avatars2.githubusercontent.com/u/57873407?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/art-deco",
"html_url": "https://github.com/art-deco",
"followers_url": "https://api.github.com/users/art-deco/followers",
"following_url": "https://api.github.com/users/art-deco/following{/other_user}",
"gists_url": "https://api.github.com/users/art-deco/gists{/gist_id}",
"starred_url": "https://api.github.com/users/art-deco/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/art-deco/subscriptions",
"organizations_url": "https://api.github.com/users/art-deco/orgs",
"repos_url": "https://api.github.com/users/art-deco/repos",
"events_url": "https://api.github.com/users/art-deco/events{/privacy}",
"received_events_url": "https://api.github.com/users/art-deco/received_events",
"type": "Organization",
"site_admin": false
},
"subscribers_count": 0,
"network_count": 1
}
}
In addition, there are replacements that are used without braces:
mnp
: the name of the package, e.g.,hello-world
.my-new-package
: the full name with the scope, e.g.,@example/hello-world
.myNewPackage
: camel-cased name, no first capital, e.g.,helloWorld
.MyNewPackage
: camel-cased name, starts with capital, e.g.,HelloWorld
.