-
-
Notifications
You must be signed in to change notification settings - Fork 129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: better frameworks like cli #115
Merged
Merged
Changes from 7 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
a78b815
better cli
vasucp1207 abc2096
playground
vasucp1207 04cdc5c
build project
vasucp1207 c81c506
build project
vasucp1207 78551d2
remove esbuild templates
vasucp1207 51df8a4
remove esbuild templates
vasucp1207 1bdaba8
update test
vasucp1207 1d36e1e
trying building the package
vasucp1207 c387dcd
trying building the package
vasucp1207 82cd7ac
move files to scr/ folder
vasucp1207 5459f1b
move files to scr/ folder
vasucp1207 0499830
deepMerge fix
vasucp1207 2884f69
adding file to package.json
vasucp1207 26cb8db
adding template/ to package
vasucp1207 a0e0890
build change
vasucp1207 58b4e46
remove emptyDir and renderDir
vasucp1207 91da4bf
replace with cross-spawn
vasucp1207 ac5536a
replace with cross-spawn
vasucp1207 c375ed7
remove cross-spawn
vasucp1207 f027c6c
remove cross-spawn
vasucp1207 e01c429
Update contrib/create-waku/src/cli.ts
vasucp1207 c8e8b96
Update contrib/create-waku/src/cli.ts
vasucp1207 5ffbd5e
Update contrib/create-waku/src/cli.ts
vasucp1207 0713dc4
relative to the script location
vasucp1207 045d405
remove test file
vasucp1207 6cffde3
Update contrib/create-waku/src/cli.ts
vasucp1207 2a98e6a
Update contrib/create-waku/src/cli.ts
vasucp1207 2fc635b
refactor
vasucp1207 5fa654c
packageJson write
vasucp1207 00bc21f
packageJson write
vasucp1207 ef34f61
remove render
vasucp1207 6b1ede3
remove render
vasucp1207 c65f424
rebase
vasucp1207 9dff783
new monorepo structure
vasucp1207 b7f030c
new monorepo structure
vasucp1207 f025623
update dir structure
vasucp1207 6b990b3
Update package.json
vasucp1207 472d830
update pnpm yaml
vasucp1207 31792f0
Update packages/create-waku/package.json
dai-shi 2a52aac
types for fs-extra
vasucp1207 81a54d0
Update types.d.ts
vasucp1207 016f005
fix prettier issue
vasucp1207 47e71fa
Update .gitignore
vasucp1207 4c549d9
Update packages/create-waku/src/cli.ts
dai-shi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,46 +1,148 @@ | ||
#!/usr/bin/env node | ||
|
||
const path = require("node:path"); | ||
const fs = require("node:fs"); | ||
const https = require("node:https"); | ||
import fs from 'node:fs' | ||
import path from 'node:path' | ||
import prompts from 'prompts' | ||
import { red, green, bold } from 'kolorist' | ||
|
||
const dirName = "waku-example"; | ||
import emptyDir from './emptyDir.js' | ||
import renderTemplate from './renderTemplate.js' | ||
|
||
if (fs.existsSync(dirName)) { | ||
console.error(`Directory "${dirName}" already exists!`); | ||
process.exit(1); | ||
function isValidPackageName(projectName) { | ||
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( | ||
projectName | ||
) | ||
} | ||
|
||
const baseUrl = | ||
"https://raw.githubusercontent.com/dai-shi/waku/v0.14.0/examples/01_counter/"; | ||
|
||
const files = ` | ||
package.json | ||
tsconfig.json | ||
src/main.tsx | ||
src/entries.ts | ||
src/index.html | ||
src/components/App.tsx | ||
src/components/Counter.tsx | ||
` | ||
.split(/\s/) | ||
.filter((file) => file); | ||
|
||
const getFiles = (index = 0) => { | ||
const file = files[index]; | ||
if (!file) return; | ||
const destFile = path.join(dirName, file.replace("/", path.sep)); | ||
fs.mkdirSync(path.dirname(destFile), { recursive: true }); | ||
https.get(baseUrl + file, (res) => { | ||
res.pipe(fs.createWriteStream(destFile)); | ||
res.on("end", () => getFiles(index + 1)); | ||
}); | ||
}; | ||
|
||
getFiles(); | ||
|
||
process.on("exit", (code) => { | ||
if (!code) { | ||
console.info(`Done! Change directory "${dirName}"`); | ||
function toValidPackageName(projectName) { | ||
return projectName | ||
.trim() | ||
.toLowerCase() | ||
.replace(/\s+/g, '-') | ||
.replace(/^[._]/, '') | ||
.replace(/[^a-z0-9-~]+/g, '-') | ||
} | ||
|
||
// if the dir is empty or not exist | ||
function canSafelyOverwrite(dir) { | ||
return !fs.existsSync(dir) || fs.readdirSync(dir).length === 0 | ||
} | ||
|
||
async function init() { | ||
const cwd = process.cwd(); | ||
|
||
let targetDir; | ||
let defaultProjectName = 'waku-project' | ||
|
||
const CHOICES = fs.readdirSync(path.resolve(cwd, '../../examples')) | ||
let result = {} | ||
|
||
try { | ||
result = await prompts([ | ||
{ | ||
name: 'projectName', | ||
type: 'text', | ||
message: 'Project Name', | ||
initial: defaultProjectName, | ||
onState: (state) => (targetDir = String(state.value).trim() || defaultProjectName) | ||
}, | ||
{ | ||
name: 'shouldOverwrite', | ||
type: () => canSafelyOverwrite(targetDir) ? null : 'confirm', | ||
message: `${targetDir} is not empty. Remove existing files and continue?`, | ||
}, | ||
{ | ||
name: 'overwriteChecker', | ||
type: (values = {}) => { | ||
if (values.shouldOverwrite === false) { | ||
throw new Error(red('✖') + ' Operation cancelled') | ||
} | ||
return null | ||
} | ||
}, | ||
{ | ||
name: 'packageName', | ||
type: () => (isValidPackageName(targetDir) ? null : 'text'), | ||
message: 'Package name', | ||
initial: () => toValidPackageName(targetDir), | ||
validate: (dir) => isValidPackageName(dir) || 'Invalid package.json name' | ||
}, | ||
{ | ||
name: 'chooseProject', | ||
type: 'select', | ||
message: 'Choose a starter template', | ||
choices: [ | ||
{ title: 'basic', value: CHOICES[0] }, | ||
{ title: 'async-template', value: CHOICES[1] }, | ||
{ title: 'promise-template', value: CHOICES[2] }, | ||
], | ||
} | ||
], { | ||
onCancel: () => { | ||
throw new Error(red('✖') + ' Operation cancelled') | ||
} | ||
}) | ||
} catch (cancelled) { | ||
console.log(cancelled.message) | ||
process.exit(1) | ||
} | ||
|
||
const { packageName, shouldOverwrite, chooseProject } = result | ||
|
||
const root = path.join(cwd, targetDir) | ||
// const root = path.resolve(cwd, '../playground', targetDir) | ||
|
||
if (shouldOverwrite) { | ||
emptyDir(root) | ||
} else if (!fs.existsSync(root)) { | ||
fs.mkdirSync(root) | ||
} | ||
|
||
const pkg = { name: packageName, version: '0.0.0' } | ||
|
||
fs.writeFileSync( | ||
path.resolve(root, 'package.json'), | ||
JSON.stringify(pkg, null, 2), | ||
) | ||
|
||
console.log("Setting up project...") | ||
const templateRoot = path.resolve(cwd, '../../examples') | ||
|
||
const render = function render(templateName) { | ||
const templateDir = path.resolve(templateRoot, templateName) | ||
renderTemplate(templateDir, root) | ||
} | ||
|
||
render(chooseProject) | ||
|
||
const packageManager = /pnpm/.test(process.env.npm_execpath) | ||
? 'pnpm' | ||
: /yarn/.test(process.env.npm_execpath) | ||
? 'yarn' | ||
: 'npm' | ||
|
||
const commandsMap = { | ||
install: { | ||
pnpm: 'pnpm install', | ||
yarn: 'yarn', | ||
npm: 'npm install' | ||
}, | ||
dev: { | ||
pnpm: 'pnpm dev', | ||
yarn: 'yarn dev', | ||
npm: 'npm run dev' | ||
} | ||
} | ||
|
||
console.log(`\nDone. Now run:\n`) | ||
if (root !== cwd) { | ||
console.log(`${bold(green(`cd ${path.relative(cwd, root)}`))}`) | ||
} | ||
}); | ||
console.log(`${bold(green(commandsMap.install[packageManager]))}`) | ||
console.log(`${bold(green(commandsMap.dev[packageManager]))}`) | ||
console.log() | ||
} | ||
|
||
init().catch((e) => { | ||
console.error(e) | ||
}) | ||
dai-shi marked this conversation as resolved.
Show resolved
Hide resolved
|
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,19 @@ | ||
const isObject = val => val && typeof val === 'object' | ||
const mergeArrayWithDedupe = (a, b) => Array.from(new Set([...a, ...b])) | ||
|
||
export default function deepMerge(target, obj) { | ||
for (const key of Object.keys(obj)) { | ||
const oldVal = target[key] | ||
const newVal = obj[key] | ||
|
||
if (Array.isArray(oldVal) && Array.isArray(newVal)) { | ||
target[key] = mergeArrayWithDedupe(oldVal, newVal) | ||
} else if (isObject(oldVal) && isObject(newVal)) { | ||
target[key] = deepMerge(oldVal, newVal) | ||
} else { | ||
target[key] = newVal | ||
} | ||
} | ||
|
||
return target | ||
} |
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,19 @@ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
|
||
export default function emptyDir(dir) { | ||
// if the file empty | ||
if (!fs.existsSync(dir)) { | ||
return; | ||
} | ||
for (const file of fs.readdirSync(dir)) { | ||
const abs = path.resolve(dir, file); | ||
if (fs.lstatSync(abs).isDirectory()) { | ||
emptyDir(abs); | ||
// after emptying the dir remove the dir itself | ||
fs.rmdirSync(abs); | ||
} else { | ||
fs.unlinkSync(abs); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,5 +1,13 @@ | ||
{ | ||
"name": "create-waku", | ||
"version": "0.4.10", | ||
"bin": "./cli.js" | ||
"bin": "./cli.js", | ||
"type": "module", | ||
"scripts": { | ||
dai-shi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"test": "node ./tests/generateTemplates.test.js" | ||
}, | ||
"dependencies": { | ||
"kolorist": "^1.8.0", | ||
"prompts": "^2.4.2" | ||
} | ||
} |
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,36 @@ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import deepMerge from './deepMerge.js' | ||
|
||
function renderTemplate(src, dest) { | ||
const stats = fs.statSync(src); | ||
|
||
if (stats.isDirectory()) { | ||
fs.mkdirSync(dest, { recursive: true }); | ||
for (const file of fs.readdirSync(src)) { | ||
renderTemplate(path.resolve(src, file), path.resolve(dest, file)); | ||
} | ||
return; | ||
} | ||
|
||
const filename = path.basename(src); | ||
|
||
if (filename === 'package.json' && fs.existsSync(dest)) { | ||
// merge instead of overwriting | ||
const pkg = deepMerge( | ||
JSON.parse(fs.readFileSync(dest)), | ||
JSON.parse(fs.readFileSync(src)) | ||
); | ||
fs.writeFileSync(dest, JSON.stringify(pkg, null, 2) + '\n'); | ||
return; | ||
} | ||
|
||
if (filename.startsWith('_')) { | ||
// rename `_file` to `.file` | ||
dest = path.resolve(path.dirname(dest), filename.replace(/^_/, '.')); | ||
} | ||
|
||
fs.copyFileSync(src, dest); | ||
} | ||
|
||
export default renderTemplate; |
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,33 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import assert from 'assert' | ||
import { green, bold } from 'kolorist' | ||
|
||
import renderTemplate from '../renderTemplate.js' | ||
import emptyDir from '../emptyDir.js' | ||
|
||
function generateTemplate(targetDir, templateDir) { | ||
renderTemplate(templateDir, targetDir) | ||
} | ||
|
||
// Test case | ||
function testTemplateGeneration() { | ||
const cwd = process.cwd() | ||
|
||
const templateDir = path.resolve(cwd, '../../examples', '01_counter') | ||
const targetDir = path.resolve(cwd, './playground', 'basic') | ||
|
||
// Generate the template | ||
generateTemplate(targetDir, templateDir); | ||
|
||
// Check if the file was generated | ||
const fileExists = fs.existsSync(targetDir); | ||
assert.strictEqual(fileExists, true, console.log(bold(green(`Template generated successfully.`)))) | ||
|
||
// Clean up the generated file after the test | ||
emptyDir(targetDir) | ||
fs.rmdirSync(targetDir); | ||
} | ||
|
||
// Run the test | ||
testTemplateGeneration() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work as we don't publish examples dir.
We have two options.
Eventually, we should go with 1 because it fixes #81, but for now 2 is also fine.
If we were to go with 1, we would like to make the code in TypeScript and transpile with SWC in the build step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using esbuild,
npm run build:esbuild
anout.js
file generated.npm run build:estemplate
generates ancopy.js
file.node copy.js
templates copied fromexample
dir and atemplate
folder generated.node cli.js
works fine.Problem with transpiling with
swr
,swr
then theimports
in output files are not working ex,This import statement would not be able to resolve the file.
Is, I'm missing something about this
swr
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I don't mind using esbuild for now. I just thought SWC might work better and we also use it in
waku
. We can try that later.Can you move TS files into
./src
folder please?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, sure we can look around it in the near future.