@architect/create
Advanced tools
Comparing version 2.0.2 to 3.0.0-RC.0
@@ -5,2 +5,27 @@ # Architect Create changelog | ||
## [3.0.0] 2021-10-17 | ||
### Added | ||
- Added ability to specify a project name with `-n` or `--name` parameter | ||
- Added support for runtime shorhands (e.g. `node` will now pin new created functions to the latest stable AWS Lambda Node.js version) | ||
- Added real file paths to boilerplate HTTP functions | ||
### Changed | ||
- Breaking change: updated internal module API to accept a proper options object | ||
- Breaking change: `-n` flag now optionally specifies a project name, and is not a shorcut for the `--no-install` param | ||
- Breaking change: removed export of internal `bootstrap` method | ||
- Significantly tidied up boilerplate `@http` functions | ||
- Create now only write config files (`/path/to/function/config.arc`) if necessary | ||
- Removed setting deprecated `INITIALIZED` env var when creating a new project | ||
### Fixed | ||
- When run from `@architect/architect`, Create no longer attempts to install Architect | ||
--- | ||
## [2.0.2] 2021-10-12 | ||
@@ -7,0 +32,0 @@ |
87
cli.js
#!/usr/bin/env node | ||
let { updater } = require('@architect/utils') | ||
let create = require('.') | ||
let banner = require('./src/bootstrap/_banner') | ||
let bootstrap = require('./src/bootstrap') | ||
let getName = require('./src/bootstrap/_get-name') | ||
let { version } = require('./package.json') | ||
let { updater } = require('@architect/utils') | ||
let _inventory = require('@architect/inventory') | ||
let simpleStatic = require('./src/simple-static') | ||
let minimist = require('minimist') | ||
let update = updater('Create') | ||
@@ -17,45 +12,36 @@ | ||
* | ||
* opts | ||
* -s|--static|static ........... init a static app | ||
* -r|--runtime|runtime ......... set up with one of node, deno, python, or ruby | ||
* -v|--verbose|verbose ......... prints all output to console | ||
* -n|--name ............ specify an app name | ||
* --noinstall .......... do not intall any Architect dependencies | ||
* -s|--static .......... init a static app | ||
* -r|--runtime ......... set up with one of node, deno, python, or ruby | ||
* -v|--verbose ......... prints all output to console | ||
*/ | ||
async function cmd (opts = {}) { | ||
let alias = { | ||
name: [ 'n' ], | ||
noInstall: [ 'noinstall' ], | ||
runtime: [ 'r' ], | ||
static: [ 's' ], | ||
verbose: [ 'v' ], | ||
} | ||
let string = [ 'name', 'runtime' ] | ||
let args = minimist(process.argv.slice(2), { alias, string }) | ||
let { _ } = args | ||
if ([ 'create', '@architect' ].includes(_[0])) _.splice(0, 1) | ||
let isRuntime = opt => opt === 'runtime' || opt === '--runtime' || opt === '-r' | ||
let isVerbose = opt => opt === 'verbose' || opt === '--verbose' || opt === '-v' | ||
let isStatic = opt => opt === 'static' || opt === '--static' || opt === '-s' | ||
let noInstall = opt => opt === 'noinstall' || opt === '--no-install' || opt === '-n' | ||
let install = opts.install | ||
if (typeof args.install === 'boolean') install = args.install | ||
if (typeof args.noInstall === 'boolean') install = !args.noInstall | ||
// eslint-disable-next-line | ||
async function cmd (options) { | ||
options = options || process.argv // passed-in options only used for testing | ||
// Get the folder name so we know where to inventory | ||
let { folder } = getName({ options, update }) | ||
let inventory = await _inventory({ cwd: folder }) | ||
// Print banner | ||
banner({ inventory, version }) | ||
if (options.some(isStatic)) { | ||
// just bail early here ... I don't use understand the code below so just stubbing in | ||
return simpleStatic() | ||
let params = { | ||
name: opts.name || args.name, | ||
folder: opts.folder || _[0], | ||
install, | ||
runtime: opts.runtime || args.runtime, | ||
standalone: opts.standalone, | ||
static: opts.static || args.static, | ||
update, | ||
verbose: opts.verbose || args.verbose, | ||
} | ||
// Populate basic project files | ||
let opts = { | ||
verbose: options.some(isVerbose), | ||
noInstall: options.some(noInstall), | ||
runtime: options.some(isRuntime) ? options.slice(options.findIndex(isRuntime))[1] : false, | ||
} | ||
// Used by bootstrap to differentiate between arc create and preflight bootstrap calls | ||
// (for testing we wanna be able to override it so we dont npm install all the things during integration tests) | ||
let standalone = opts.noInstall ? false : true | ||
// Bootstrap the project on the filesystem, including new dirs, npm i, app.arc manifest, etc. | ||
let { install } = bootstrap({ options, inventory, standalone, update, runtime: opts.runtime }) | ||
// re-seed the inventory since we may now have a new manifest due to bootstrap creating a new project | ||
inventory = await _inventory({ cwd: folder }) | ||
return create({ options: opts, inventory, folder, install, standalone, update }) | ||
return create(params) | ||
} | ||
@@ -69,3 +55,10 @@ | ||
try { | ||
await cmd() | ||
// If invoked by npm init, then we probably do need to `install` | ||
let options = { | ||
install: true, | ||
standalone: true, | ||
} | ||
// If invoked by Architect, assume installation is unncessary | ||
if (process.env.ARC_ENV) options.install = false | ||
await cmd(options) | ||
} | ||
@@ -72,0 +65,0 @@ catch (err) { |
{ | ||
"name": "@architect/create", | ||
"version": "2.0.2", | ||
"version": "3.0.0-RC.0", | ||
"description": "Idempotently initialize Architect projects", | ||
@@ -26,7 +26,7 @@ "main": "src/index.js", | ||
"dependencies": { | ||
"@architect/inventory": "~2.1.0", | ||
"@architect/inventory": "~2.1.1-RC.0", | ||
"@architect/utils": "~3.0.4", | ||
"chalk": "~4.1.2", | ||
"run-parallel": "~1.2.0", | ||
"run-series": "~1.1.9" | ||
"lambda-runtimes": "0.0.3", | ||
"minimist": "~1.2.5" | ||
}, | ||
@@ -33,0 +33,0 @@ "devDependencies": { |
@@ -10,21 +10,22 @@ let { join } = require('path') | ||
*/ | ||
module.exports = function arcPackage ({ options, name, folder }) { | ||
module.exports = function arcPackage ({ name, folder }) { | ||
let args = process.argv | ||
// Don't install if invoked from a globally installed @arc/arc | ||
let isGlobal = (options[0] && options[1] && options[2] && | ||
options[0].includes('node') && // Node invoke path may vary | ||
options[1].includes('arc')) && // .. same deal with the Arc path | ||
options[2] === 'create' || // == 'arc create' via global install | ||
options[2] === 'init' // Backwards compat | ||
let isGlobal = (args[0] && args[1] && args[2] && | ||
args[0].includes('node') && // Node invoke path may vary | ||
args[1].includes('arc')) && // .. same deal with the Arc path | ||
(args[2] === 'create' || // == 'arc create' via global install | ||
args[2] === 'init') // Backwards compat | ||
if (!isGlobal) { | ||
let package = { | ||
name, | ||
version: '0.0.0', | ||
description: 'A fresh new Architect project!', | ||
scripts: { | ||
start: 'npx sandbox' | ||
}, | ||
devDependencies: {} | ||
} | ||
let packageFile = join(folder, 'package.json') | ||
if (!existsSync(packageFile)) { | ||
let package = { | ||
name, | ||
version: '0.0.0', | ||
description: 'A fresh new Architect project!', | ||
scripts: { | ||
start: 'npx sandbox' | ||
}, | ||
devDependencies: {} | ||
} | ||
writeFileSync(packageFile, JSON.stringify(package, null, 2)) | ||
@@ -31,0 +32,0 @@ return true |
@@ -6,7 +6,12 @@ let { join } = require('path') | ||
let { name, folder, inventory, standalone, update, runtime } = params | ||
// Only add the @aws runtime setting into the Arc template if specified | ||
runtime = runtime ? `runtime ${runtime}\n` : '' | ||
// Most basic default Architect app possible | ||
let arcFile = `@app | ||
let appDotArc = join(folder, 'app.arc') | ||
let hasManifest = inventory.inv._project.manifest | ||
// Do nothing if a manifest already exists | ||
if (hasManifest && standalone) { | ||
update.done('Existing Architect project manifest found') | ||
} | ||
else if (!hasManifest) { | ||
// Most basic default Architect app possible | ||
let arcFile = `@app | ||
${name} | ||
@@ -18,15 +23,6 @@ | ||
${runtime ? '' : '# '}@aws | ||
${runtime}# profile default | ||
${runtime ? `runtime ${runtime}\n` : ''}# profile default | ||
# region us-west-1 | ||
` | ||
` | ||
let appDotArc = join(folder, 'app.arc') | ||
let hasManifest = inventory.inv._project.manifest | ||
// Do nothing if a manifest already exists | ||
if (hasManifest && standalone) { | ||
update.done('Existing Architect project manifest found') | ||
} | ||
else if (!hasManifest) { | ||
// This is used further down the line in @arc/arc processes to ensure correctly ordered printing | ||
process.env.INITIALIZED = true | ||
writeFileSync(appDotArc, arcFile) | ||
@@ -33,0 +29,0 @@ if (standalone) { |
@@ -1,6 +0,3 @@ | ||
let path = require('path') | ||
let { existsSync, mkdirSync } = require('fs') | ||
let { updater } = require('@architect/utils') | ||
let getName = require('./_get-name') | ||
let arcTemplate = require('./_arc-template') | ||
@@ -17,15 +14,6 @@ let arcPackage = require('./_arc-package') | ||
*/ | ||
module.exports = function bootstrap (params = {}) { | ||
let { options = [], inventory, runtime, standalone = false, update } = params | ||
if (!update) update = updater('Create') | ||
module.exports = function bootstrap (params) { | ||
let { name, folder, standalone, update } = params | ||
/** | ||
* First, figure out where we're working, and what our project name is | ||
*/ | ||
let { name, folder } = getName({ options, update }) | ||
// Get the name passed in, or use the current dir name | ||
let currentDirName = process.cwd().split(path.sep).reverse().shift() | ||
name = name || currentDirName | ||
/** | ||
* Next, create a dir and/or app.arc file, if necessary | ||
@@ -41,3 +29,3 @@ */ | ||
} | ||
arcTemplate({ name, folder, inventory, standalone, update, runtime }) | ||
arcTemplate(params) | ||
@@ -49,3 +37,3 @@ /** | ||
if (standalone) { | ||
install = arcPackage({ options, name, folder }) | ||
install = arcPackage({ name, folder }) | ||
} | ||
@@ -52,0 +40,0 @@ |
145
src/index.js
@@ -0,8 +1,13 @@ | ||
let { sep } = require('path') | ||
let { updater } = require('@architect/utils') | ||
let { sep } = require('path') | ||
let _inventory = require('@architect/inventory') | ||
let parallel = require('run-parallel') | ||
let code = require('./lambda') | ||
let assets = require('./static') | ||
let { version } = require('../package.json') | ||
let banner = require('./_banner') | ||
let { aliases, runtimes, runtimeList } = require('lambda-runtimes') | ||
let getName = require('./_get-name') | ||
let bootstrap = require('./bootstrap') | ||
let simpleStatic = require('./simple-static') | ||
let writeConfigs = require('./write-configs') | ||
let writeFunctions = require('./write-functions') | ||
let writeStatic = require('./write-static') | ||
let installArc = require('./_install-arc') | ||
@@ -15,7 +20,6 @@ | ||
* Rules: | ||
* - Go fast: create an entire project in one shot in parallel | ||
* - Create dep-free functions | ||
* - Min code possible | ||
* - Only one comment at the top of the file | ||
* - Add `.arc-config` by default | ||
* - Add `config.arc` only if runtime configuration deems it necessary | ||
* | ||
@@ -26,7 +30,15 @@ * @param {Object} params - Object of params | ||
*/ | ||
// eslint-disable-next-line | ||
module.exports = async function create (params = {}, callback) { | ||
// Although create should be synchronous, callers may await it, so keep it async | ||
let { install, inventory, runtime, standalone, update } = params | ||
if (!update) update = updater('Create') | ||
let { options = {}, folder = process.cwd(), install, inventory, standalone, update } = params | ||
let { node } = process.versions | ||
let nodeVer = Number(node.split('.')[0]) | ||
if (nodeVer < 14) { | ||
update.error('Sorry, Architect Create requires Node 14 and above') | ||
process.exit(1) | ||
} | ||
// TODO: This blows up 12 if required in global; move this back after 12 is EOL | ||
// eslint-disable-next-line | ||
let _inventory = require('@architect/inventory') | ||
@@ -42,61 +54,68 @@ let promise | ||
if (!inventory) inventory = await _inventory({ cwd: folder }) | ||
if (!update) update = updater('Create') | ||
// Validate the runtime | ||
if (runtime && (runtime !== 'deno' && | ||
!runtimes[runtime] && | ||
!runtimeList.includes(runtime)) && | ||
!aliases[runtime]) { | ||
update.error(`Invalid runtime specified: ${runtime}`) | ||
process.exit(1) | ||
} | ||
// Get the folder name so we know where to inventory | ||
if (params.folder === '/') { | ||
update.error('Please specify a valid project name or path') | ||
process.exit(1) | ||
} | ||
if (standalone) { | ||
// Print banner | ||
banner(version) | ||
} | ||
// TODO [DEPRECATE] | ||
if (params.static) { | ||
return simpleStatic() | ||
} | ||
// Establish the project name and intended folder | ||
let { name, folder } = getName(params) | ||
// Get Inventory to determine whether we need to bootstrap a manifest | ||
if (!inventory) { | ||
params.inventory = await _inventory({ cwd: folder }) | ||
} | ||
// Bootstrap the project on the filesystem, including new dirs, app.arc manifest, etc. | ||
bootstrap({ ...params, name, folder }) | ||
try { | ||
let { inv } = inventory | ||
let prefs = inv._project.preferences | ||
let { http, events, queues, scheduled, static, streams, ws, plugins } = inv | ||
// These are the boilerplate-enabled pragmas | ||
let pragmas = [ 'http', 'events', 'plugins', 'queues', 'scheduled', 'static', 'streams', 'ws' ] | ||
let supported = [ 'node', 'deno', 'ruby', 'python', 'rb', 'py', 'js' ] | ||
let node = 'nodejs12.x' | ||
let deno = 'deno' | ||
let ruby = 'ruby2.7' | ||
let python = 'python3.8' | ||
// Re-seed the inventory since we may now have a new manifest | ||
inventory = await _inventory({ cwd: folder }) | ||
let runtime = inv._project.defaultFunctionConfig.runtime | ||
let override = options.runtime | ||
if (supported.includes(override)) { | ||
let runtimes = { node, ruby, python, rb: ruby, py: python, js: node, deno } | ||
runtime = runtimes[override] | ||
} | ||
// Create dirs (and necessary config.arc files) that do not yet exist | ||
let dirs = writeConfigs({ ...params, pragmas, inventory }) | ||
let functions = [] | ||
if (dirs.length) { | ||
// One final inventory run now that we have function config files | ||
inventory = await _inventory({ cwd: folder }) | ||
let binder = {} | ||
let lambdae = [ 'http', 'events', 'plugins', 'queues', 'scheduled', 'static', 'streams', 'ws' ] | ||
lambdae.forEach(type => { | ||
binder[type] = fn => code.bind({}, { ...fn, type, runtime, prefs }) | ||
}) | ||
writeFunctions({ ...params, dirs, inventory }) | ||
writeStatic({ folder, inventory }) | ||
// Generate minimal static assets and Lambdae | ||
if (static) functions.push(assets.bind({}, { folder, inv })) | ||
if (http) functions.push(...http.map(binder.http)) | ||
if (events) functions.push(...events.map(binder.events)) | ||
if (queues) functions.push(...queues.map(binder.queues)) | ||
if (scheduled) functions.push(...scheduled.map(binder.scheduled)) | ||
if (ws) functions.push(...ws.map(binder.ws)) | ||
if (streams) functions.push(...streams.map(binder.streams)) | ||
if (plugins) functions.push(...plugins.map(binder.plugins)) | ||
parallel(functions, function done (err, results) { | ||
if (err) callback(err) | ||
else { | ||
let dirs = [ ...new Set(results) ].filter(d => d) | ||
if (dirs.length) { | ||
dirs.forEach(d => { | ||
let dir = d.replace(process.cwd(), '') | ||
if (dir.startsWith(sep)) dir = dir.substr(1) | ||
update.done(`Created new project files in ${dir}${sep}`) | ||
}) | ||
} | ||
if (install && standalone) { | ||
installArc({ folder, update }, callback) | ||
} | ||
else { | ||
if (standalone) update.done('Done!') | ||
callback() | ||
} | ||
} | ||
}) | ||
dirs.forEach(d => { | ||
let dir = d.src.replace(process.cwd(), '') | ||
if (dir.startsWith(sep)) dir = dir.substr(1) | ||
update.done(`Created new project files in ${dir}${sep}`) | ||
}) | ||
} | ||
if (install && standalone) { | ||
installArc({ folder, update }, callback) | ||
} | ||
else { | ||
if (standalone) update.done('Done!') | ||
callback() | ||
} | ||
} | ||
@@ -109,3 +128,1 @@ catch (err) { | ||
} | ||
module.exports.bootstrap = bootstrap |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
10
48742
828
2
2
+ Addedlambda-runtimes@0.0.3
+ Addedminimist@~1.2.5
+ Addedlambda-runtimes@0.0.3(transitive)
+ Addedminimist@1.2.8(transitive)
- Removedrun-parallel@~1.2.0
- Removedrun-series@~1.1.9
- Removedqueue-microtask@1.2.3(transitive)
- Removedrun-parallel@1.2.0(transitive)