WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cmd/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ module.exports = async (ipc, argv = Bare.argv.slice(1)) => {
summary('Create initial project files'),
description`
Links:
pear://electron/template
${ansi.italic(ansi.dim('pear://your.key.here/your/path/here'))}
pear://templates/terminal/default
pear://templates/desktop/electron
pear://templates/modules/bare
${ansi.italic(ansi.dim('pear://<key>/path/to/template'))}

Names:
default, ui, node-compat
Names: default, ui
`,
arg('[link|name]', 'Link or core template to init from'),
arg('[dir]', 'Project directory path (default: .)'),
Expand Down
133 changes: 132 additions & 1 deletion cmd/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ const fsp = require('bare-fs/promises')
const os = require('bare-os')
const { basename, resolve } = require('bare-path')
const { ansi, outputter, permit } = require('pear-terminal')
const { pipelinePromise, Readable } = require('streamx')
const { pathToFileURL } = require('url-file-url')
const Localdrive = require('localdrive')
const { Interact } = require('pear-terminal')
const stamp = require('pear-stamp')
const plink = require('pear-link')

const {
ERR_PERMISSION_REQUIRED,
ERR_OPERATION_FAILED,
ERR_DIR_NONEMPTY,
ERR_INVALID_TEMPLATE
} = require('pear-errors')

const output = outputter('init', {
writing: () => '',
Expand Down Expand Up @@ -43,7 +56,7 @@ module.exports = (ipc) =>
try {
await output(
false,
await require('../init')(link, dir, {
await render(link, dir, {
cwd,
ipc,
autosubmit: yes,
Expand All @@ -62,3 +75,121 @@ module.exports = (ipc) =>
await ipc.close()
}
}

async function render(link = 'default', dir, opts = {}) {
const { cwd, ipc, header, autosubmit, defaults, force = false, pkg } = opts
let { ask = true } = opts
const isPear = link.startsWith('pear://')
const isFile = link.startsWith('file://')
const isPath =
link[0] === '.' ||
link[0] === '/' ||
link[1] === ':' ||
link.startsWith('\\')
const isName = !isPear && !isFile && !isPath

if (isName) {
const map = new Map(
Object.entries({
ui: 'pear://templates/ui/electron',
default: 'pear://templates/terminal/default'
})
)
if (map.has(link)) {
link = map.get(link)
ask = false
}
}

let params = null
if (isPear && ask) {
if ((await ipc.trusted(link)) === false) {
const { drive } = plink.parse(link)
throw ERR_PERMISSION_REQUIRED('Permission required to use template', {
key: drive.key
})
}
}

if (isPath) {
let url = pathToFileURL(cwd).toString()
if (url.slice(1) !== '/') url += '/'
link = new URL(link, url).toString()
}

for await (const { tag, data } of ipc.dump({
link: link + '/_template.json',
dir: '-'
})) {
if (tag === 'error' && data.code === 'ERR_PERMISSION_REQUIRED') {
throw ERR_PERMISSION_REQUIRED(data.message, data.info)
}
if (tag !== 'file') continue
try {
const definition = JSON.parse(data.value)
params = definition.params
for (const prompt of params) {
defaults[prompt.name] = Array.isArray(prompt.override)
? prompt.override.reduce((o, k) => o?.[k], pkg)
: (prompt.default ?? defaults[prompt.name])
if (typeof prompt.validation !== 'string') continue
prompt.validation = new Function(
'value',
'return (' + prompt.validation + ')(value)'
) // eslint-disable-line
}
} catch {
params = null
}
break
}
if (params === null)
throw ERR_INVALID_TEMPLATE('Invalid Template or Unreachable Link')
const dst = new Localdrive(dir)
if (force === false) {
let empty = true
for await (const entry of dst.list()) {
if (entry) {
empty = false
break
}
}
if (empty === false)
throw ERR_DIR_NONEMPTY('Dir is not empty. To overwrite: --force')
}
const output = new Readable({ objectMode: true })
const prompt = new Interact(header, params, { defaults })
const { fields, shave } = await prompt.run({ autosubmit })
output.push({ tag: 'writing' })
const promises = []
for await (const { tag, data } of ipc.dump({ link, dir: '-' })) {
if (tag === 'error') {
throw ERR_OPERATION_FAILED('Dump Failed: ' + data.stack)
}
if (tag !== 'file') continue
const { key, value = null } = data
if (key === '/_template.json') continue
if (value === null) continue // dir
const file = stamp.sync(key, fields)
const writeStream = dst.createWriteStream(file)
const promise = pipelinePromise(
stamp.stream(value, fields, shave),
writeStream
)
promise.catch((err) => {
output.push({ tag: 'error', data: err })
})
promise.then(() => {
output.push({ tag: 'wrote', data: { path: file } })
})
promises.push(promise)
}

Promise.allSettled(promises).then((results) => {
const success = results.every(({ status }) => status === 'fulfilled')
output.push({ tag: 'written' })
output.push({ tag: 'final', data: { success } })
output.push(null)
})
return output
}
139 changes: 0 additions & 139 deletions init/index.js

This file was deleted.

4 changes: 0 additions & 4 deletions init/templates/default/__main__

This file was deleted.

20 changes: 0 additions & 20 deletions init/templates/default/_template.json

This file was deleted.

18 changes: 0 additions & 18 deletions init/templates/default/package.json

This file was deleted.

1 change: 0 additions & 1 deletion init/templates/default/test/index.test.js

This file was deleted.

5 changes: 0 additions & 5 deletions init/templates/node-compat/__main__

This file was deleted.

20 changes: 0 additions & 20 deletions init/templates/node-compat/_template.json

This file was deleted.

3 changes: 0 additions & 3 deletions init/templates/node-compat/compat.js

This file was deleted.

Loading