Adding the first glitch gallery
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
const cwd = process.cwd()
|
||||
const templateDir = path.join(cwd, 'templates', 'react-vite-glitch-component')
|
||||
|
||||
function fail(message) {
|
||||
console.error(message)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function toKebabCase(value) {
|
||||
return value
|
||||
.trim()
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
||||
.replace(/[^a-zA-Z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
function toSnakeCase(value) {
|
||||
return value.replace(/-/g, '_')
|
||||
}
|
||||
|
||||
function toPascalCase(value) {
|
||||
return value
|
||||
.split('-')
|
||||
.filter(Boolean)
|
||||
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
||||
.join('')
|
||||
}
|
||||
|
||||
function toTitleCase(value) {
|
||||
return value
|
||||
.split('-')
|
||||
.filter(Boolean)
|
||||
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = [...argv]
|
||||
const result = {
|
||||
componentId: '',
|
||||
title: '',
|
||||
dir: ''
|
||||
}
|
||||
|
||||
while (args.length > 0) {
|
||||
const arg = args.shift()
|
||||
if (!arg) continue
|
||||
|
||||
if (!result.componentId && !arg.startsWith('--')) {
|
||||
result.componentId = arg
|
||||
continue
|
||||
}
|
||||
|
||||
if (arg === '--title') {
|
||||
result.title = args.shift() ?? ''
|
||||
continue
|
||||
}
|
||||
|
||||
if (arg === '--dir') {
|
||||
result.dir = args.shift() ?? ''
|
||||
continue
|
||||
}
|
||||
|
||||
fail(`Unknown argument: ${arg}`)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function copyTemplate(sourceDir, destinationDir, replacements) {
|
||||
fs.mkdirSync(destinationDir, { recursive: true })
|
||||
|
||||
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
||||
const sourcePath = path.join(sourceDir, entry.name)
|
||||
const destinationPath = path.join(destinationDir, entry.name)
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
copyTemplate(sourcePath, destinationPath, replacements)
|
||||
continue
|
||||
}
|
||||
|
||||
const source = fs.readFileSync(sourcePath, 'utf8')
|
||||
const rendered = Object.entries(replacements).reduce(
|
||||
(content, [key, value]) => content.replaceAll(key, value),
|
||||
source
|
||||
)
|
||||
fs.writeFileSync(destinationPath, rendered)
|
||||
}
|
||||
}
|
||||
|
||||
const options = parseArgs(process.argv.slice(2))
|
||||
if (!options.componentId) {
|
||||
fail('Usage: npm run glitch:new -- <component-id> --title "Display Name" [--dir /custom/path]')
|
||||
}
|
||||
|
||||
if (!fs.existsSync(templateDir)) {
|
||||
fail(`Template directory not found: ${templateDir}`)
|
||||
}
|
||||
|
||||
const componentId = toKebabCase(options.componentId)
|
||||
if (!componentId) {
|
||||
fail('Component id resolved to an empty value.')
|
||||
}
|
||||
|
||||
const folderName = `glitch_${toSnakeCase(componentId)}`
|
||||
const displayName = options.title.trim() || toTitleCase(componentId)
|
||||
const bundleName = componentId
|
||||
const destinationDir = options.dir
|
||||
? path.resolve(cwd, options.dir)
|
||||
: path.join(cwd, folderName)
|
||||
|
||||
if (fs.existsSync(destinationDir)) {
|
||||
fail(`Destination already exists: ${destinationDir}`)
|
||||
}
|
||||
|
||||
copyTemplate(templateDir, destinationDir, {
|
||||
'__COMPONENT_ID__': componentId,
|
||||
'__COMPONENT_DISPLAY_NAME__': displayName,
|
||||
'__LIB_GLOBAL_NAME__': toPascalCase(componentId),
|
||||
'__FOLDER_NAME__': folderName,
|
||||
'__BUNDLE_NAME__': bundleName
|
||||
})
|
||||
|
||||
console.log(`Created ${folderName}`)
|
||||
console.log(`Path: ${destinationDir}`)
|
||||
console.log('Next steps:')
|
||||
console.log(` cd ${folderName}`)
|
||||
console.log(' npm install')
|
||||
console.log(' npm run dev')
|
||||
Reference in New Issue
Block a user