-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(create-abell): migrate create-abell to monorepo and TS (#136)
* feat: initiate basic create-abell code * feat: add install dependecies step * feat: add deleteDir step * docs: elaborate comment * feat: add default template * feat: add logs * fix: missing projectname error * fix error format * 0.0.15
- Loading branch information
1 parent
387cf15
commit cfe8f93
Showing
22 changed files
with
1,254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
# Logs | ||
.DS_Store | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
scaffold-dir/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
node_modules | ||
dist | ||
scaffold-dir | ||
src | ||
templates/**/dist/ | ||
templates/**/node_modules/ | ||
templates/**/yarn.lock | ||
scripts | ||
tsconfig.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "create-abell", | ||
"version": "0.0.15", | ||
"description": "Boilerplate for abell. npx create-abell my-blog", | ||
"main": "dist/create.js", | ||
"types": "dist/create.d.ts", | ||
"bin": { | ||
"create-abell": "dist/bin.js" | ||
}, | ||
"scripts": { | ||
"build": "tsc && node scripts/post-build.js", | ||
"dev": "nodemon --exec \"yarn build\" --watch src --watch templates -e js,ts,abell,css", | ||
"clean-scaffolds": "node scripts/clean-scaffolds.js", | ||
"scaffold": "npm run clean-scaffolds && cd scaffold-dir && node ../dist/bin.js", | ||
"prepublishOnly": "yarn build" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/abelljs/abell.git" | ||
}, | ||
"keywords": [ | ||
"abell" | ||
], | ||
"author": "saurabhdaware", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/abelljs/abell/issues" | ||
}, | ||
"homepage": "https://github.com/abelljs/abell#readme", | ||
"dependencies": { | ||
"commander": "^9.2.0", | ||
"prompts": "^2.4.2" | ||
}, | ||
"devDependencies": { | ||
"@types/prompts": "^2.0.14" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { deleteDir } = require('../dist/utils'); | ||
|
||
function clean() { | ||
const scaffoldDir = path.join(__dirname, '..', 'scaffold-dir'); | ||
deleteDir(scaffoldDir); | ||
fs.mkdirSync(scaffoldDir); | ||
} | ||
|
||
clean(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
const DIST = path.join(__dirname, '..', 'dist'); | ||
|
||
try { | ||
const fd = fs.openSync(path.join(DIST, 'bin.js'), 'r'); | ||
fs.fchmodSync(fd, 511); | ||
console.log('> Changed bin.js file persmission to executable'); | ||
} catch (error) { | ||
console.log(error); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#!/usr/bin/env node | ||
import { createCommand } from 'commander'; | ||
import create, { CreateAbellOptions } from './create'; | ||
|
||
const program = createCommand(); | ||
/** | ||
* npx create-abell [projectName] --template <template> --installer <installer> | ||
*/ | ||
program | ||
.option('-t|--template <template>', 'Specify template for abell app') | ||
.option( | ||
'-i|--installer <installer>', | ||
'Specify package installer. npm or yarn.' | ||
) | ||
.arguments('[projectName]') | ||
.action((projectName: string | undefined, options: CreateAbellOptions) => | ||
create(projectName, { | ||
template: options.template, | ||
installer: options.installer | ||
}) | ||
); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
program.version(require('../package.json').version, '-v|--version'); | ||
program.parse(process.argv); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { | ||
getInstallCommand, | ||
getProjectInfo, | ||
getTemplate, | ||
scaffoldTemplate, | ||
setNameInPackageJSON | ||
} from './steps'; | ||
import { deleteDir, log, relative, run } from './utils'; | ||
|
||
export type CreateAbellOptions = { | ||
installer?: 'npm' | 'yarn'; | ||
template?: string; | ||
}; | ||
|
||
async function create( | ||
projectNameArg: string | undefined, | ||
options: CreateAbellOptions | ||
): Promise<void> { | ||
// 1. Get all the required project information | ||
const { projectDisplayName, projectPath } = await getProjectInfo( | ||
projectNameArg | ||
); | ||
const relProjectPath = relative(projectPath); | ||
const template = getTemplate(options.template); | ||
const installCommand = await getInstallCommand(options.installer); | ||
log.info(`Scaffolding \`${relProjectPath}\` using \`${template}\` template`); | ||
|
||
// 2. Scaffold Project | ||
await scaffoldTemplate({ | ||
projectPath, | ||
template | ||
}); | ||
|
||
log.info(`Running \`${installCommand}\``); | ||
// 3. Install Dependencies | ||
try { | ||
await run(installCommand, { | ||
cwd: projectPath | ||
}); | ||
} catch (err) { | ||
log.failure(`Could not install dependencies. Skipping ${installCommand}`); | ||
} | ||
|
||
// 4. Set name in project's package.json | ||
setNameInPackageJSON(`${projectPath}/package.json`, projectDisplayName); | ||
|
||
// 5. Delete `.git` (For projects scaffolded from github) | ||
deleteDir(`${projectPath}/.git`); | ||
|
||
// 6. Log Success @todo | ||
log.success(`${projectDisplayName} scaffolded successfully`); | ||
const runCommand = installCommand === 'yarn' ? 'yarn dev' : 'npm run dev'; | ||
log.info( | ||
`cd ${relProjectPath} and run \`${runCommand}\` to run the dev-server` | ||
); | ||
} | ||
|
||
export default create; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import prompts from 'prompts'; | ||
import { colors, copyFolderSync, log, normalizePath, run } from './utils'; | ||
|
||
/** | ||
* Prompts user for projectName if not defined, returns the information required related to project | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | ||
export const getProjectInfo = async (projectNameArg: string | undefined) => { | ||
let projectName = ''; | ||
if (!projectNameArg) { | ||
projectName = ( | ||
await prompts({ | ||
type: 'text', | ||
message: 'Enter Name of your project', | ||
name: 'projectName', | ||
initial: 'hello-abell' | ||
}) | ||
).projectName; | ||
} else { | ||
projectName = projectNameArg; | ||
} | ||
|
||
if (!projectName) { | ||
throw new Error(log.failure('Project name is required', false)); | ||
} | ||
|
||
const projectSlugName = projectName.toLowerCase().replace(/ |_/g, '-'); | ||
const projectPath = path.join(process.cwd(), projectSlugName); | ||
const projectDisplayName = path.basename(projectPath); | ||
|
||
if (fs.existsSync(projectPath)) { | ||
// oops. Can be an issue | ||
if (fs.readdirSync(projectPath).length !== 0) { | ||
// Not an empty directory so break! | ||
console.error( | ||
`${colors.red( | ||
'>> ' | ||
)} The directory already exists and is not an empty directory` | ||
); | ||
process.exit(0); | ||
} | ||
} | ||
|
||
return { projectDisplayName, projectPath }; | ||
}; | ||
|
||
/** | ||
* Prompts user to choose package installer if not defined | ||
*/ | ||
export const getInstallCommand = async ( | ||
installerVal: 'npm' | 'yarn' | undefined | ||
): Promise<'npm install' | 'yarn'> => { | ||
if (!installerVal) { | ||
// if installer flag is undefined, ask user. | ||
const answers = await prompts({ | ||
type: 'select', | ||
message: 'Select Installer', | ||
name: 'installer', | ||
choices: [ | ||
{ | ||
title: 'npm', | ||
value: 'npm install' | ||
}, | ||
{ | ||
title: 'yarn', | ||
value: 'yarn' | ||
} | ||
] | ||
}); | ||
|
||
installerVal = answers.installer; | ||
} | ||
|
||
if (installerVal === 'yarn') { | ||
return 'yarn'; | ||
} else { | ||
return 'npm install'; | ||
} | ||
}; | ||
|
||
/** | ||
* Some validations on top of template names | ||
*/ | ||
export const getTemplate = (templateVal: string | undefined): string => { | ||
// return default when value is not defined | ||
if (!templateVal) return 'default'; | ||
|
||
if (templateVal === 'default' || templateVal === 'minimal') { | ||
// 'default' and 'minimal' are valid templates. Return them as it is | ||
return templateVal; | ||
} | ||
|
||
// when `--template abelljs/abell-starter-portfolio` | ||
if (!templateVal.startsWith('https://github.com/')) { | ||
// If template value is `abelljs/abell-starter-portfolio`, add https://github.com before it. | ||
return 'https://github.com/' + templateVal; | ||
} | ||
|
||
// when `--template https://github.com/abelljs/abell-starter-portfolio` | ||
return templateVal; | ||
}; | ||
|
||
export const scaffoldTemplate = async ({ | ||
projectPath, | ||
template | ||
}: { | ||
projectPath: string; | ||
template: string; | ||
}): Promise<void> => { | ||
if (template === 'default' || template === 'minimal') { | ||
// copy default template from templates directory | ||
const templatesDir = path.join(__dirname, '..', 'templates'); | ||
const templatePath = path.join(templatesDir, template); | ||
copyFolderSync(templatePath, projectPath, [ | ||
path.join(templatePath, 'node_modules'), | ||
path.join(templatePath, 'yarn.lock'), | ||
path.join(templatePath, 'dist') | ||
]); | ||
} else { | ||
// Execute git clone | ||
try { | ||
const errorCode = await run(`git clone ${template} ${projectPath}`); | ||
if (errorCode === 1) { | ||
throw new Error(log.failure('Git clone failed', false)); | ||
} | ||
} catch (err) { | ||
throw err; | ||
} | ||
} | ||
}; | ||
|
||
export const setNameInPackageJSON = ( | ||
packagePath: string, | ||
appName: string | ||
): void => { | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const packageJSON = require(normalizePath(packagePath)); | ||
packageJSON.name = appName; | ||
fs.writeFileSync(packagePath, JSON.stringify(packageJSON, null, 2)); | ||
} catch (err) { | ||
// Do nothing. Skip the step if error. | ||
} | ||
}; |
Oops, something went wrong.