Skip to content

Commit

Permalink
feat: create-farc
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Feb 9, 2024
1 parent 31e78e9 commit 0927c96
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 4 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ jobs:
run: |
jq --arg prop "workspaces" 'del(.[$prop])' package.json > package.tmp.json && rm package.json && cp package.tmp.json package.json && rm package.tmp.json
cd src
npm --no-git-tag-version version 0.0.0
npm --no-git-tag-version version $(npm pkg get version | sed 's/"//g')-$(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//').$(date +'%Y%m%dT%H%M%S')
cd ../create-vocs
npm --no-git-tag-version version $(npm pkg get version | sed 's/"//g')-$(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//').$(date +'%Y%m%dT%H%M%S')
- name: Build
run: bun run build

- name: Publish to npm
run: cd src && npm publish --tag $(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//')
run: |
cd src
npm publish --tag $(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//')
cd ../create-vocs
npm publish --tag $(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//')
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Binary file modified bun.lockb
Binary file not shown.
18 changes: 18 additions & 0 deletions create-farc/bin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
import { createRequire } from 'node:module'
import { cac } from 'cac'
import { type CreateParameters, create } from './create.js'

const require = createRequire(import.meta.url)
const pkg = require('../package.json')

const cli = cac('create-vocs')

cli.usage('[options]').option('-n, --name [name]', 'Name of project')

cli.help()
cli.version(pkg.version)

const { options } = cli.parse()

if (!options.help) create(options as CreateParameters)
95 changes: 95 additions & 0 deletions create-farc/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { intro, log, outro, text } from '@clack/prompts'
import { default as fs } from 'fs-extra'
import { default as pc } from 'picocolors'

export type CreateParameters = { name: string }

const __dirname = dirname(fileURLToPath(import.meta.url))

export async function create(params: CreateParameters) {
intro('Welcome to Farc!')

const templateDir = resolve(__dirname, '../templates/default')

const displayName =
params.name ||
((await text({
message: 'Enter the name of your project',
placeholder: 'my-first-farc',
validate(value) {
if (!value) return 'Please enter a name.'
return
},
})) as string)
const name = kebabcase(displayName)

const destDir = resolve(process.cwd(), name)

// Copy contents
fs.copySync(templateDir, destDir)

// Replace dotfiles
for (const file of fs.readdirSync(destDir)) {
if (!file.startsWith('_')) continue
fs.renameSync(resolve(destDir, file), resolve(destDir, `.${file.slice(1)}`))
}

// Replace package.json properties
const pkgJson = fs.readJsonSync(resolve(destDir, 'package.json'))
pkgJson.name = name
fs.writeJsonSync(resolve(destDir, 'package.json'), pkgJson, { spaces: 2 })

// Wrap up
log.success(`Project successfully scaffolded in ${pc.blue(destDir)}!`)

const pkgManager = detectPackageManager()

log.message('Next steps:')
log.step(`1. ${pc.blue(`cd ./${name}`)} - Navigate to project`)
log.step(
`2. ${pc.blue(
pkgManagerInstallCommand(pkgManager),
)} - Install dependencies`,
)
log.step(
`3. ${pc.blue(pkgManagerRunCommand(pkgManager, 'dev'))} - Start dev server`,
)
log.step(`4. Head to ${pc.blue('http://localhost:3000')}`)

outro('Done! 🤠')
}

type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun'

function detectPackageManager(): PackageManager {
const userAgent = process.env.npm_config_user_agent
if (!userAgent) return 'npm'
if (userAgent.includes('bun')) return 'bun'
if (userAgent.includes('yarn')) return 'yarn'
if (userAgent.includes('pnpm')) return 'pnpm'
if (userAgent.includes('npm')) return 'npm'
return 'npm'
}

function pkgManagerInstallCommand(pkgManager: PackageManager) {
if (pkgManager === 'bun') return 'bun install'
if (pkgManager === 'yarn') return 'yarn'
if (pkgManager === 'pnpm') return 'pnpm install'
return 'npm install'
}

function pkgManagerRunCommand(pkgManager: PackageManager, command: string) {
if (pkgManager === 'bun') return `bun run ${command}`
if (pkgManager === 'yarn') return `yarn ${command}`
if (pkgManager === 'pnpm') return `pnpm ${command}`
return `npm run ${command}`
}

function kebabcase(str: string) {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase()
}
16 changes: 16 additions & 0 deletions create-farc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "create-farc",
"version": "0.0.1",
"type": "module",
"bin": {
"create-farc": "./_lib/bin.js"
},
"dependencies": {
"@clack/prompts": "^0.7.0",
"cac": "^6.7.14",
"detect-package-manager": "^3.0.1",
"fs-extra": "^11.1.1",
"picocolors": "^1.0.0"
},
"repository": "wevm/farc"
}
21 changes: 21 additions & 0 deletions create-farc/templates/default/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# production
/docs/dist

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# typescript
*.tsbuildinfo
1 change: 1 addition & 0 deletions create-farc/templates/default/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a [Farc](https://farc.dev) project bootstrapped with `create-farc`.
15 changes: 15 additions & 0 deletions create-farc/templates/default/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "Example",
"private": true,
"scripts": {
"dev": "bun run --hot src/index.tsx"
},
"dependencies": {
"bun": "latest",
"farc": "main",
"hono": "^3.12.8"
},
"devDependencies": {
"@types/bun": "latest"
}
}
58 changes: 58 additions & 0 deletions create-farc/templates/default/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Button, Farc, TextInput } from 'farc'

const app = new Farc()

app.frame('/', (context) => {
const { buttonValue, inputText, status } = context
const fruit = inputText || buttonValue
return {
image: (
<div
style={{
alignItems: 'center',
background:
status === 'response'
? 'linear-gradient(to right, #432889, #17101F)'
: 'black',
backgroundSize: '100% 100%',
display: 'flex',
flexDirection: 'column',
flexWrap: 'nowrap',
height: '100%',
justifyContent: 'center',
textAlign: 'center',
width: '100%',
}}
>
<div
style={{
color: 'white',
fontSize: 60,
fontStyle: 'normal',
letterSpacing: '-0.025em',
lineHeight: 1.4,
marginTop: 30,
padding: '0 120px',
whiteSpace: 'pre-wrap',
}}
>
{status === 'response'
? `Nice choice.${fruit ? ` ${fruit.toUpperCase()}!!` : ''}`
: 'Welcome!'}
</div>
</div>
),
intents: [
<TextInput placeholder="Enter custom fruit..." />,
<Button value="apples">Apples</Button>,
<Button value="oranges">Oranges</Button>,
<Button value="bananas">Bananas</Button>,
status === 'response' && <Button.Reset>Reset</Button.Reset>,
],
}
})

export default {
port: 3000,
fetch: app.fetch,
}
23 changes: 23 additions & 0 deletions create-farc/templates/default/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["**/*.ts", "**/*.tsx"]
}
15 changes: 15 additions & 0 deletions create-farc/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// This file is used to compile the for cjs and esm (see package.json build scripts). It should exclude all test files.
"extends": "../tsconfig.base.json",
"exclude": ["_lib", "node_modules"],
"include": ["*"],
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationMap": true,
"module": "ESNext",
"moduleResolution": "Node",
"outDir": "./_lib",
"sourceMap": true
}
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"workspaces": ["example", "src"],
"workspaces": ["create-farc", "example", "src"],
"scripts": {
"dev": "bun run --hot ./example/src/index.tsx",
"build": "bun run clean && tsc --project ./tsconfig.build.json",
"build": "bun run clean && bun run build:farc && bun run build:create-farc",
"build:farc": "tsc --project ./tsconfig.build.json",
"build:create-farc": "rimraf create-farc/_lib && tsc -p create-farc/tsconfig.build.json",
"changeset": "changeset",
"changeset:release": "bun run build && changeset publish",
"changeset:version": "changeset version && bun install --lockfile-only",
Expand All @@ -18,6 +20,7 @@
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.1",
"@types/bun": "latest",
"@types/fs-extra": "^11.0.4",
"@vitest/coverage-v8": "^1.2.2",
"hono": "^3.12.8",
"rimraf": "^5.0.5",
Expand Down

0 comments on commit 0927c96

Please sign in to comment.