Comparing version 3.2.0 to 3.2.1
# master | ||
# 3.3.1 | ||
* [BUGFIX] restore static APIs on Broccoli.Builder that got dropped during the typescript conversion | ||
# 3.3.0 | ||
* Code-base utilizes async/await where appropriate | ||
* [BUGFIX] no longer cause spurious unhandled promise rejections warnings | ||
* convert lib to typescript | ||
* migrate to github actions | ||
# 3.2.0 | ||
@@ -15,3 +26,3 @@ | ||
* [BUGFIX] Add `annotation` object for broccoli-sane-watcher compatiblity | ||
* [BUGFIX] Add `annotation` object for broccoli-sane-watcher compatibility | ||
@@ -18,0 +29,0 @@ # 3.1.0 |
@@ -1,23 +0,24 @@ | ||
'use strict'; | ||
const promiseFinally = require('promise.prototype.finally'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const EventEmitter = require('events').EventEmitter; | ||
const tmp = require('tmp'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const fs_1 = __importDefault(require("fs")); | ||
const tmp_1 = __importDefault(require("tmp")); | ||
const path_1 = __importDefault(require("path")); | ||
const broccoli_source_1 = require("broccoli-source"); | ||
const transform_node_1 = __importDefault(require("./wrappers/transform-node")); | ||
const source_node_1 = __importDefault(require("./wrappers/source-node")); | ||
const builder_1 = __importDefault(require("./errors/builder")); | ||
const node_setup_1 = __importDefault(require("./errors/node-setup")); | ||
const build_1 = __importDefault(require("./errors/build")); | ||
const cancelation_request_1 = __importDefault(require("./cancelation-request")); | ||
const filter_map_1 = __importDefault(require("./utils/filter-map")); | ||
const events_1 = require("events"); | ||
const node_1 = __importDefault(require("./wrappers/node")); | ||
const heimdall = require('heimdalljs'); | ||
const underscoreString = require('underscore.string'); | ||
const WatchedDir = require('broccoli-source').WatchedDir; | ||
const broccoliNodeInfo = require('broccoli-node-info'); | ||
const NodeWrapper = require('./wrappers/node'); | ||
const TransformNodeWrapper = require('./wrappers/transform-node'); | ||
const SourceNodeWrapper = require('./wrappers/source-node'); | ||
const BuilderError = require('./errors/builder'); | ||
const NodeSetupError = require('./errors/node-setup'); | ||
const BuildError = require('./errors/build'); | ||
const CancelationRequest = require('./cancelation-request'); | ||
const Cancelation = require('./errors/cancelation'); | ||
const logger = require('heimdalljs-logger')('broccoli:builder'); | ||
const filterMap = require('./utils/filter-map'); | ||
// Clean up left-over temporary directories on uncaught exception. | ||
tmp.setGracefulCleanup(); | ||
tmp_1.default.setGracefulCleanup(); | ||
// For an explanation and reference of the API that we use to communicate with | ||
@@ -28,12 +29,10 @@ // nodes (__broccoliFeatures__ and __broccoliGetInfo__), see | ||
// | ||
// ```js | ||
// const builder = new Builder(outputNode) | ||
// builder.build() | ||
// .then(() => { | ||
// // Build output has been written to builder.outputPath | ||
// }) | ||
// // To rebuild, call builder.build() repeatedly | ||
// .finally(() => { | ||
// // Delete temporary directories | ||
// return builder.cleanup() | ||
// }) | ||
// try { | ||
// const { outputPath } = await builder.build() | ||
// } finally { | ||
// await builder.cleanup() | ||
// } | ||
// ``` | ||
// | ||
@@ -43,7 +42,5 @@ // Note that the API of this Builder may change between minor Broccoli | ||
// plugin that works with Broccoli 1.0 will work with 1.x. | ||
module.exports = class Builder extends EventEmitter { | ||
constructor(outputNode, options) { | ||
class Builder extends events_1.EventEmitter { | ||
constructor(outputNode, options = {}) { | ||
super(); | ||
if (options == null) | ||
options = {}; | ||
this.outputNode = outputNode; | ||
@@ -76,2 +73,9 @@ this.tmpdir = options.tmpdir; // can be null | ||
} | ||
static get BuilderError() { return builder_1.default; } | ||
static get InvalidNodeError() { return broccoliNodeInfo.InvalidNodeError; } | ||
static get NodeSetupError() { return node_setup_1.default; } | ||
static get BuildError() { return build_1.default; } | ||
static get NodeWrapper() { return node_1.default; } | ||
static get TransformNodeWrapper() { return transform_node_1.default; } | ||
static get SourceNodeWrapper() { return source_node_1.default; } | ||
// Trigger a (re)build. | ||
@@ -83,7 +87,7 @@ // | ||
// other than a BuildError. | ||
build() { | ||
async build() { | ||
if (this._cancelationRequest) { | ||
return Promise.reject(new BuilderError('Cannot start a build if one is already running')); | ||
throw new builder_1.default('Cannot start a build if one is already running'); | ||
} | ||
let promise = Promise.resolve(); | ||
let pipeline = Promise.resolve(); | ||
this.buildId++; | ||
@@ -93,57 +97,58 @@ for (const nw of this._nodeWrappers.values()) { | ||
nw.buildState = {}; | ||
promise = promise.then(() => { | ||
let needsEndNode = false; | ||
// We use a nested .then/.catch so that the .catch can only catch errors | ||
// from this node, but not from previous nodes. | ||
return promiseFinally(Promise.resolve() | ||
.then(() => this._cancelationRequest.throwIfRequested()) | ||
.then(() => { | ||
this.emit('beginNode', nw); | ||
needsEndNode = true; | ||
}) | ||
.then(() => nw.build()), () => { | ||
if (needsEndNode) { | ||
this.emit('endNode', nw); | ||
} | ||
}) | ||
.then(() => this._cancelationRequest.throwIfRequested()) | ||
.catch(err => { | ||
if (Cancelation.isCancelationError(err)) { | ||
throw err; | ||
} | ||
else { | ||
throw new BuildError(err, nw); | ||
} | ||
}); | ||
// the build is two passes, first we create a promise chain representing | ||
// the complete build, then we pass that terminal promises which | ||
// represents the build to the CancelationRequest, after which the build | ||
// itself begins. | ||
// | ||
// 1. build up a promise chain, which represents the complete build | ||
pipeline = pipeline.then(async () => { | ||
// 3. begin next build step | ||
this._cancelationRequest.throwIfRequested(); | ||
this.emit('beginNode', nw); | ||
try { | ||
await nw.build(); | ||
this.emit('endNode', nw); | ||
} | ||
catch (e) { | ||
this.emit('endNode', nw); | ||
// wrap the error which occurred from a node wrappers build with | ||
// additional build information. This includes which build step | ||
// caused the error, and where that build step was instantiated. | ||
throw new build_1.default(e, nw); | ||
} | ||
}); | ||
} | ||
this._cancelationRequest = new CancelationRequest(promise); | ||
return promiseFinally(promise | ||
.then(() => { | ||
return this.outputNodeWrapper; | ||
}) | ||
.then(outputNodeWrapper => { | ||
this.buildHeimdallTree(outputNodeWrapper); | ||
}), () => { | ||
let buildsSkipped = filterMap(this._nodeWrappers.values(), nw => nw.buildState.built === false).length; | ||
// 2. Create CancelationRequest which waits on the complete build itself | ||
// This allows us to initiate a cancellation, but wait until any | ||
// un-cancelable work completes before canceling. This allows us to safely | ||
// wait until cancelation is complete before performance actions such as | ||
// cleanup, or restarting the build itself. | ||
this._cancelationRequest = new cancelation_request_1.default(pipeline); | ||
try { | ||
await pipeline; | ||
this.buildHeimdallTree(this.outputNodeWrapper); | ||
} | ||
finally { | ||
let buildsSkipped = filter_map_1.default(this._nodeWrappers.values(), (nw) => nw.buildState.built === false).length; | ||
logger.debug(`Total nodes skipped: ${buildsSkipped} out of ${this._nodeWrappers.size}`); | ||
this._cancelationRequest = null; | ||
}); | ||
} | ||
} | ||
cancel() { | ||
if (!this._cancelationRequest) { | ||
// No current build, so no cancelation | ||
return Promise.resolve(); | ||
async cancel() { | ||
if (this._cancelationRequest) { | ||
return this._cancelationRequest.cancel(); | ||
} | ||
return this._cancelationRequest.cancel(); | ||
} | ||
// Destructor-like method. Waits on current node to finish building, then cleans up temp directories | ||
cleanup() { | ||
return promiseFinally(this.cancel(), () => this.builderTmpDirCleanup()); | ||
async cleanup() { | ||
try { | ||
await this.cancel(); | ||
} | ||
finally { | ||
await this.builderTmpDirCleanup(); | ||
} | ||
} | ||
// This method recursively traverses the node graph and returns a nodeWrapper. | ||
// The nodeWrapper graph parallels the node graph 1:1. | ||
makeNodeWrapper(node, _stack) { | ||
if (_stack == null) | ||
_stack = []; | ||
makeNodeWrapper(node, _stack = []) { | ||
let wrapper = this._nodeWrappers.get(node); | ||
@@ -154,5 +159,5 @@ if (wrapper !== undefined) { | ||
// Turn string nodes into WatchedDir nodes | ||
const originalNode = node; // keep original (possibly string) node around for deduping | ||
const originalNode = node; // keep original (possibly string) node around so we can later deduplicate | ||
if (typeof node === 'string') { | ||
node = new WatchedDir(node, { annotation: 'string node' }); | ||
node = new broccoli_source_1.WatchedDir(node, { annotation: 'string node' }); | ||
} | ||
@@ -187,3 +192,3 @@ // Call node.__broccoliGetInfo__() | ||
// nodeWrapper for the _stack. Later we'll add more properties. | ||
const nodeWrapper = nodeInfo.nodeType === 'transform' ? new TransformNodeWrapper() : new SourceNodeWrapper(); | ||
const nodeWrapper = nodeInfo.nodeType === 'transform' ? new transform_node_1.default() : new source_node_1.default(); | ||
nodeWrapper.nodeInfo = nodeInfo; | ||
@@ -201,11 +206,11 @@ nodeWrapper.originalNode = originalNode; | ||
cycleMessage += nodeWrapper.label; | ||
throw new this.constructor.BuilderError(cycleMessage); | ||
throw new builder_1.default(cycleMessage); | ||
} | ||
} | ||
// For 'transform' nodes, recurse into the input nodes; for 'source' nodes, | ||
// record paths. | ||
// For 'transform' nodes, recursively enter into the input nodes; for | ||
// 'source' nodes, record paths. | ||
let inputNodeWrappers = []; | ||
if (nodeInfo.nodeType === 'transform') { | ||
const newStack = _stack.concat([nodeWrapper]); | ||
inputNodeWrappers = nodeInfo.inputNodes.map(inputNode => { | ||
inputNodeWrappers = nodeInfo.inputNodes.map((inputNode) => { | ||
return this.makeNodeWrapper(inputNode, newStack); | ||
@@ -237,3 +242,3 @@ }); | ||
get watchedSourceNodeWrappers() { | ||
return filterMap(this._nodeWrappers.values(), nw => { | ||
return filter_map_1.default(this._nodeWrappers.values(), (nw) => { | ||
return nw.nodeInfo.nodeType === 'source' && nw.nodeInfo.watched; | ||
@@ -247,9 +252,9 @@ }); | ||
try { | ||
isDirectory = fs.statSync(this.watchedPaths[i]).isDirectory(); | ||
isDirectory = fs_1.default.statSync(this.watchedPaths[i]).isDirectory(); | ||
} | ||
catch (err) { | ||
throw new this.constructor.BuilderError('Directory not found: ' + this.watchedPaths[i]); | ||
throw new builder_1.default('Directory not found: ' + this.watchedPaths[i]); | ||
} | ||
if (!isDirectory) { | ||
throw new this.constructor.BuilderError('Not a directory: ' + this.watchedPaths[i]); | ||
throw new builder_1.default('Not a directory: ' + this.watchedPaths[i]); | ||
} | ||
@@ -261,5 +266,5 @@ } | ||
// | ||
// out-01-someplugin/ | ||
// out-01-some-plugin/ | ||
// out-02-otherplugin/ | ||
// cache-01-someplugin/ | ||
// cache-01-some-plugin/ | ||
// cache-02-otherplugin/ | ||
@@ -270,3 +275,3 @@ // | ||
// | ||
// 01-someplugin/ | ||
// 01-some-plugin/ | ||
// out/ | ||
@@ -278,12 +283,13 @@ // cache/ | ||
// ... | ||
const tmpobj = tmp.dirSync({ | ||
// @ts-ignore | ||
const tmpObj = tmp_1.default.dirSync({ | ||
prefix: 'broccoli-', | ||
unsafeCleanup: true, | ||
dir: this.tmpdir, | ||
dir: this.tmpdir || undefined, | ||
}); | ||
this.builderTmpDir = tmpobj.name; | ||
this.builderTmpDirCleanup = tmpobj.removeCallback; | ||
this.builderTmpDir = tmpObj.name; | ||
this.builderTmpDirCleanup = tmpObj.removeCallback; | ||
for (let nodeWrapper of this._nodeWrappers.values()) { | ||
if (nodeWrapper.nodeInfo.nodeType === 'transform') { | ||
nodeWrapper.inputPaths = nodeWrapper.inputNodeWrappers.map(nw => nw.outputPath); | ||
nodeWrapper.inputPaths = nodeWrapper.inputNodeWrappers.map((nw) => nw.outputPath); | ||
nodeWrapper.outputPath = this.mkTmpDir(nodeWrapper, 'out'); | ||
@@ -313,4 +319,4 @@ if (nodeWrapper.nodeInfo.needsCache) { | ||
const dirname = type + '-' + paddedId + '-' + suffix; | ||
const tmpDir = path.join(this.builderTmpDir, dirname); | ||
fs.mkdirSync(tmpDir); | ||
const tmpDir = path_1.default.join(this.builderTmpDir, dirname); | ||
fs_1.default.mkdirSync(tmpDir); | ||
return tmpDir; | ||
@@ -328,3 +334,3 @@ } | ||
catch (err) { | ||
throw new NodeSetupError(err, nw); | ||
throw new node_setup_1.default(err, nw); | ||
} | ||
@@ -336,3 +342,3 @@ } | ||
let name; | ||
if (node instanceof SourceNodeWrapper) { | ||
if (node instanceof source_node_1.default) { | ||
name = node.nodeInfo.sourceDirectory; | ||
@@ -348,3 +354,3 @@ } | ||
broccoliId: node.id, | ||
// we should do this instead of reparentNodes | ||
// we should do this instead of reParentNodes | ||
// broccoliInputIds: node.inputNodeWrappers.map(input => input.id), | ||
@@ -367,3 +373,3 @@ broccoliCachedNode: false, | ||
// Why? | ||
reparentNodes(outputNodeWrapper); | ||
reParentNodes(outputNodeWrapper); | ||
// What uses this?? | ||
@@ -375,5 +381,5 @@ aggregateTime(); | ||
} | ||
}; | ||
function reparentNodes(outputNodeWrapper) { | ||
// reparent heimdall nodes according to input nodes | ||
} | ||
function reParentNodes(outputNodeWrapper) { | ||
// re-parent heimdall nodes according to input nodes | ||
const seen = new Set(); | ||
@@ -442,9 +448,3 @@ const queue = [outputNodeWrapper]; | ||
} | ||
module.exports.BuilderError = BuilderError; | ||
module.exports.InvalidNodeError = broccoliNodeInfo.InvalidNodeError; | ||
module.exports.NodeSetupError = NodeSetupError; | ||
module.exports.BuildError = BuildError; | ||
module.exports.NodeWrapper = NodeWrapper; | ||
module.exports.TransformNodeWrapper = TransformNodeWrapper; | ||
module.exports.SourceNodeWrapper = SourceNodeWrapper; | ||
module.exports = Builder; | ||
//# sourceMappingURL=builder.js.map |
@@ -1,4 +0,8 @@ | ||
'use strict'; | ||
const CancelationError = require('./errors/cancelation'); | ||
module.exports = class CancelationRequest { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const cancelation_1 = __importDefault(require("./errors/cancelation")); | ||
class CancelationRequest { | ||
constructor(pendingWork) { | ||
@@ -13,3 +17,3 @@ this._pendingWork = pendingWork; // all | ||
if (this.isCanceled) { | ||
throw new CancelationError('Build Canceled'); | ||
throw new cancelation_1.default('Build Canceled'); | ||
} | ||
@@ -25,3 +29,3 @@ } | ||
this._canceling = this._pendingWork.catch(e => { | ||
if (CancelationError.isCancelationError(e)) { | ||
if (cancelation_1.default.isCancelationError(e)) { | ||
return; | ||
@@ -35,3 +39,4 @@ } | ||
} | ||
}; | ||
} | ||
exports.default = CancelationRequest; | ||
//# sourceMappingURL=cancelation-request.js.map |
181
dist/cli.js
@@ -1,12 +0,69 @@ | ||
'use strict'; | ||
const promiseFinally = require('promise.prototype.finally'); | ||
const TreeSync = require('tree-sync'); | ||
const childProcess = require('child_process'); | ||
const fs = require('fs'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const tree_sync_1 = __importDefault(require("tree-sync")); | ||
const child_process_1 = __importDefault(require("child_process")); | ||
const fs_1 = __importDefault(require("fs")); | ||
const path_1 = __importDefault(require("path")); | ||
const cli_1 = __importDefault(require("./errors/cli")); | ||
const index_1 = __importDefault(require("./index")); | ||
const messages_1 = __importDefault(require("./messages")); | ||
const WatchDetector = require('watch-detector'); | ||
const path = require('path'); | ||
const UI = require('console-ui'); | ||
const broccoli = require('./index'); | ||
const messages = require('./messages'); | ||
const CliError = require('./errors/cli'); | ||
function getBuilder(options) { | ||
const brocfile = index_1.default.loadBrocfile(options); | ||
return new index_1.default.Builder(brocfile(buildBrocfileOptions(options))); | ||
} | ||
function getWatcher(options) { | ||
return options.watch ? index_1.default.Watcher : require('./dummy-watcher'); | ||
} | ||
function buildWatcherOptions(options, ui) { | ||
if (!options) { | ||
options = {}; | ||
} | ||
const detector = new WatchDetector({ | ||
ui, | ||
childProcess: child_process_1.default, | ||
fs: fs_1.default, | ||
watchmanSupportsPlatform: /^win/.test(process.platform), | ||
root: process.cwd(), | ||
}); | ||
const watchPreference = detector.findBestWatcherOption({ | ||
watcher: options.watcher, | ||
}); | ||
const watcher = watchPreference.watcher; | ||
return { | ||
saneOptions: { | ||
poll: watcher === 'polling', | ||
watchman: watcher === 'watchman', | ||
node: watcher === 'node' || !watcher, | ||
}, | ||
}; | ||
} | ||
function buildBrocfileOptions(options) { | ||
return { | ||
env: options.environment, | ||
}; | ||
} | ||
function guardOutputDir(outputDir) { | ||
if (isParentDirectory(outputDir)) { | ||
throw new cli_1.default(`build directory can not be the current or direct parent directory: ${outputDir}`); | ||
} | ||
} | ||
function isParentDirectory(outputPath) { | ||
if (!fs_1.default.existsSync(outputPath)) { | ||
return false; | ||
} | ||
outputPath = fs_1.default.realpathSync(outputPath); | ||
const rootPath = process.cwd(); | ||
const rootPathParents = [rootPath]; | ||
let dir = path_1.default.dirname(rootPath); | ||
rootPathParents.push(dir); | ||
while (dir !== path_1.default.dirname(dir)) { | ||
dir = path_1.default.dirname(dir); | ||
rootPathParents.push(dir); | ||
} | ||
return rootPathParents.indexOf(outputPath) !== -1; | ||
} | ||
module.exports = function broccoliCLI(args, ui = new UI()) { | ||
@@ -35,3 +92,3 @@ // always require a fresh commander, as it keeps state at module scope | ||
.option('--dev', 'alias for --environment=development') | ||
.action(options => { | ||
.action((options) => { | ||
if (options.prod) { | ||
@@ -52,3 +109,3 @@ options.environment = 'production'; | ||
catch (e) { | ||
if (e instanceof CliError) { | ||
if (e instanceof cli_1.default) { | ||
ui.writeError(e.message); | ||
@@ -59,6 +116,6 @@ return process.exit(1); | ||
} | ||
const outputTree = new TreeSync(builder.outputPath, outputDir); | ||
const outputTree = new tree_sync_1.default(builder.outputPath, outputDir); | ||
watcher.on('buildSuccess', () => outputTree.sync()); | ||
} | ||
actionPromise = broccoli.server.serve(watcher, options.host, parseInt(options.port, 10), undefined, undefined, ui, options.ssl, options.sslKey, options.sslCert); | ||
actionPromise = index_1.default.server.serve(watcher, options.host, parseInt(options.port, 10), undefined, undefined, ui, options.ssl, options.sslKey, options.sslCert); | ||
}); | ||
@@ -98,3 +155,3 @@ program | ||
catch (e) { | ||
if (e instanceof CliError) { | ||
if (e instanceof cli_1.default) { | ||
ui.writeError(e); | ||
@@ -107,7 +164,7 @@ return process.exit(1); | ||
const Watcher = getWatcher(options); | ||
const outputTree = new TreeSync(builder.outputPath, outputDir); | ||
const outputTree = new tree_sync_1.default(builder.outputPath, outputDir); | ||
const watcher = new Watcher(builder, builder.watchedSourceNodeWrappers, buildWatcherOptions(options, ui)); | ||
watcher.on('buildSuccess', () => { | ||
outputTree.sync(); | ||
messages.onBuildSuccess(builder, ui); | ||
messages_1.default.onBuildSuccess(builder, ui); | ||
if (!options.watch) { | ||
@@ -117,3 +174,3 @@ watcher.quit(); | ||
}); | ||
watcher.on('buildFailure', err => { | ||
watcher.on('buildFailure', (err) => { | ||
ui.writeLine('build failure', 'ERROR'); | ||
@@ -127,73 +184,31 @@ ui.writeError(err); | ||
process.on('SIGTERM', cleanupAndExit); | ||
actionPromise = promiseFinally(watcher.start().catch(err => ui.writeError(err)), () => { | ||
builder.cleanup(); | ||
process.exit(0); | ||
}).catch(err => { | ||
ui.writeLine('Cleanup error:', 'ERROR'); | ||
ui.writeError(err); | ||
process.exit(1); | ||
}); | ||
actionPromise = (async () => { | ||
try { | ||
await watcher.start(); | ||
} | ||
catch (e) { | ||
ui.writeError(e); | ||
} | ||
finally { | ||
try { | ||
builder.cleanup(); | ||
process.exit(0); | ||
} | ||
catch (e) { | ||
ui.writeLine('Cleanup error:', 'ERROR'); | ||
ui.writeError(e); | ||
process.exit(1); | ||
} | ||
} | ||
})(); | ||
}); | ||
program.parse(args || process.argv); | ||
if (!actionPromise) { | ||
if (actionPromise) { | ||
return actionPromise; | ||
} | ||
else { | ||
program.outputHelp(); | ||
return process.exit(1); | ||
process.exit(1); | ||
} | ||
return actionPromise || Promise.resolve(); | ||
}; | ||
function getBuilder(options) { | ||
const brocfile = broccoli.loadBrocfile(options); | ||
return new broccoli.Builder(brocfile(buildBrocfileOptions(options))); | ||
} | ||
function getWatcher(options) { | ||
return options.watch ? broccoli.Watcher : require('./dummy-watcher'); | ||
} | ||
function buildWatcherOptions(options, ui) { | ||
if (!options) { | ||
options = {}; | ||
} | ||
const detector = new WatchDetector({ | ||
ui, | ||
childProcess, | ||
fs, | ||
watchmanSupportsPlatform: /^win/.test(process.platform), | ||
root: process.cwd(), | ||
}); | ||
const watchPreference = detector.findBestWatcherOption({ | ||
watcher: options.watcher, | ||
}); | ||
const watcher = watchPreference.watcher; | ||
return { | ||
saneOptions: { | ||
poll: watcher === 'polling', | ||
watchman: watcher === 'watchman', | ||
node: watcher === 'node' || !watcher, | ||
}, | ||
}; | ||
} | ||
function buildBrocfileOptions(options) { | ||
return { | ||
env: options.environment, | ||
}; | ||
} | ||
function guardOutputDir(outputDir) { | ||
if (isParentDirectory(outputDir)) { | ||
throw new CliError(`build directory can not be the current or direct parent directory: ${outputDir}`); | ||
} | ||
} | ||
function isParentDirectory(outputPath) { | ||
if (!fs.existsSync(outputPath)) { | ||
return false; | ||
} | ||
outputPath = fs.realpathSync(outputPath); | ||
const rootPath = process.cwd(); | ||
const rootPathParents = [rootPath]; | ||
let dir = path.dirname(rootPath); | ||
rootPathParents.push(dir); | ||
while (dir !== path.dirname(dir)) { | ||
dir = path.dirname(dir); | ||
rootPathParents.push(dir); | ||
} | ||
return rootPathParents.indexOf(outputPath) !== -1; | ||
} | ||
//# sourceMappingURL=cli.js.map |
@@ -1,4 +0,4 @@ | ||
'use strict'; | ||
const EventEmitter = require('events').EventEmitter; | ||
module.exports = class Watcher extends EventEmitter { | ||
"use strict"; | ||
const events_1 = require("events"); | ||
class Watcher extends events_1.EventEmitter { | ||
constructor(builder) { | ||
@@ -8,3 +8,4 @@ super(); | ||
this.currentBuild = null; | ||
let lifetime = (this._lifetimeDeferred = {}); | ||
this._lifetimeDeferred = {}; | ||
let lifetime = this._lifetimeDeferred; | ||
lifetime.promise = new Promise((resolve, reject) => { | ||
@@ -19,9 +20,13 @@ lifetime.resolve = resolve; | ||
.then(() => this.emit('buildSuccess')) | ||
.catch(err => this.emit('buildFailure', err)); | ||
.catch((err) => this.emit('buildFailure', err)); | ||
return this._lifetimeDeferred.promise; | ||
} | ||
quit() { | ||
this._lifetimeDeferred.resolve(); | ||
if (this._lifetimeDeferred.resolve) { | ||
this._lifetimeDeferred.resolve(); | ||
} | ||
} | ||
}; | ||
} | ||
; | ||
module.exports = Watcher; | ||
//# sourceMappingURL=dummy-watcher.js.map |
@@ -1,5 +0,9 @@ | ||
'use strict'; | ||
const BuilderError = require('./builder'); | ||
const wrapPrimitiveErrors = require('../utils/wrap-primitive-errors'); | ||
module.exports = class BuildError extends BuilderError { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const builder_1 = __importDefault(require("./builder")); | ||
const wrap_primitive_errors_1 = __importDefault(require("../utils/wrap-primitive-errors")); | ||
class BuildError extends builder_1.default { | ||
constructor(originalError, nodeWrapper) { | ||
@@ -11,3 +15,3 @@ if (nodeWrapper == null) { | ||
} | ||
originalError = wrapPrimitiveErrors(originalError); | ||
originalError = wrap_primitive_errors_1.default(originalError); | ||
// Create heavily augmented message for easy printing to the terminal. Web | ||
@@ -65,3 +69,5 @@ // interfaces should refer to broccoliPayload.originalError.message instead. | ||
} | ||
}; | ||
} | ||
exports.default = BuildError; | ||
; | ||
//# sourceMappingURL=build.js.map |
@@ -1,20 +0,15 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Base class for builder errors | ||
module.exports = class BuilderError extends Error { | ||
class BuilderError extends Error { | ||
constructor(message = '') { | ||
super(message); | ||
this.isBuilderError = true; | ||
} | ||
static isBuilderError(error) { | ||
return error !== null && typeof error === 'object' && error.isBuilderError; | ||
} | ||
constructor(a, b, c) { | ||
// Subclassing Error in ES5 is non-trivial because reasons, so we need this | ||
// extra constructor logic from http://stackoverflow.com/a/17891099/525872. | ||
// Note that ES5 subclasses of BuilderError don't in turn need any special | ||
// code. | ||
let temp = super(a, b, c); | ||
// Need to assign temp.name for correct error class in .stack and .message | ||
temp.name = this.name = this.constructor.name; | ||
this.stack = temp.stack; | ||
this.message = temp.message; | ||
this.isBuilderError = true; | ||
} | ||
}; | ||
} | ||
exports.default = BuilderError; | ||
; | ||
//# sourceMappingURL=builder.js.map |
@@ -1,21 +0,16 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Base class for builder errors | ||
module.exports = class Cancelation extends Error { | ||
class Cancelation extends Error { | ||
constructor(message = '') { | ||
super(message); | ||
this.isCancelation = true; | ||
this.isSilent = true; | ||
} | ||
static isCancelationError(e) { | ||
return typeof e === 'object' && e !== null && e.isCancelation === true; | ||
} | ||
constructor(a, b, c) { | ||
// Subclassing Error in ES5 is non-trivial because reasons, so we need this | ||
// extra constructor logic from http://stackoverflow.com/a/17891099/525872. | ||
// Note that ES5 subclasses of BuilderError don't in turn need any special | ||
// code. | ||
let temp = super(a, b, c); | ||
// Need to assign temp.name for correct error class in .stack and .message | ||
temp.name = this.name = this.constructor.name; | ||
this.stack = temp.stack; | ||
this.message = temp.message; | ||
this.isCancelation = true; | ||
this.isSilent = true; | ||
} | ||
}; | ||
} | ||
exports.default = Cancelation; | ||
; | ||
//# sourceMappingURL=cancelation.js.map |
@@ -1,5 +0,8 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Base class for cli errors | ||
module.exports = class CliError extends Error { | ||
}; | ||
class CliError extends Error { | ||
} | ||
exports.default = CliError; | ||
; | ||
//# sourceMappingURL=cli.js.map |
@@ -1,5 +0,9 @@ | ||
'use strict'; | ||
const BuilderError = require('./builder'); | ||
const wrapPrimitiveErrors = require('../utils/wrap-primitive-errors'); | ||
module.exports = class NodeSetupError extends BuilderError { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const builder_1 = __importDefault(require("./builder")); | ||
const wrap_primitive_errors_1 = __importDefault(require("../utils/wrap-primitive-errors")); | ||
class NodeSetupError extends builder_1.default { | ||
constructor(originalError, nodeWrapper) { | ||
@@ -11,3 +15,3 @@ if (nodeWrapper == null) { | ||
} | ||
originalError = wrapPrimitiveErrors(originalError); | ||
originalError = wrap_primitive_errors_1.default(originalError); | ||
const message = originalError.message + | ||
@@ -21,3 +25,5 @@ '\nat ' + | ||
} | ||
}; | ||
} | ||
exports.default = NodeSetupError; | ||
; | ||
//# sourceMappingURL=node-setup.js.map |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
module.exports = { | ||
@@ -3,0 +3,0 @@ get Builder() { |
@@ -1,4 +0,7 @@ | ||
'use strict'; | ||
const path = require('path'); | ||
const findup = require('findup-sync'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const path_1 = __importDefault(require("path")); | ||
const findup_sync_1 = __importDefault(require("findup-sync")); | ||
const esmRequire = require('esm')(module); | ||
@@ -41,12 +44,9 @@ /** | ||
} | ||
module.exports = function loadBrocfile(options) { | ||
if (!options) { | ||
options = {}; | ||
} | ||
module.exports = function loadBrocfile(options = {}) { | ||
let brocfilePath; | ||
if (options.brocfilePath) { | ||
brocfilePath = path.resolve(options.brocfilePath); | ||
brocfilePath = path_1.default.resolve(options.brocfilePath); | ||
} | ||
else { | ||
brocfilePath = findup('Brocfile.{ts,js}', { | ||
brocfilePath = findup_sync_1.default('Brocfile.{ts,js}', { | ||
nocase: true, | ||
@@ -58,3 +58,3 @@ }); | ||
} | ||
const baseDir = options.cwd || path.dirname(brocfilePath); | ||
const baseDir = options.cwd || path_1.default.dirname(brocfilePath); | ||
// The chdir should perhaps live somewhere else and not be a side effect of | ||
@@ -61,0 +61,0 @@ // this function, or go away entirely |
@@ -1,6 +0,10 @@ | ||
'use strict'; | ||
const printSlowNodes = require('./utils/slow-trees'); | ||
module.exports = { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const slow_trees_1 = __importDefault(require("./utils/slow-trees")); | ||
exports.default = { | ||
onBuildSuccess(builder, ui) { | ||
printSlowNodes(builder.outputNodeWrapper.__heimdall__, 0.05, ui); | ||
slow_trees_1.default(builder.outputNodeWrapper.__heimdall__, 0.05, ui); | ||
ui.writeLine('Built - ' + | ||
@@ -7,0 +11,0 @@ Math.round(builder.outputNodeWrapper.buildState.totalTime) + |
@@ -1,7 +0,10 @@ | ||
'use strict'; | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const handlebars = require('handlebars'); | ||
const url = require('url'); | ||
const mime = require('mime-types'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const fs_1 = __importDefault(require("fs")); | ||
const url_1 = __importDefault(require("url")); | ||
const path_1 = __importDefault(require("path")); | ||
const mime_types_1 = __importDefault(require("mime-types")); | ||
const handlebars_1 = __importDefault(require("handlebars")); | ||
const resolvePath = require('resolve-path'); | ||
@@ -14,4 +17,4 @@ const ansiHTML = require('ansi-html'); | ||
}); | ||
const errorTemplate = handlebars.compile(fs.readFileSync(path.resolve(__dirname, 'templates/error.html')).toString()); | ||
const dirTemplate = handlebars.compile(fs.readFileSync(path.resolve(__dirname, 'templates/dir.html')).toString()); | ||
const errorTemplate = handlebars_1.default.compile(fs_1.default.readFileSync(path_1.default.resolve(__dirname, 'templates/error.html')).toString()); | ||
const dirTemplate = handlebars_1.default.compile(fs_1.default.readFileSync(path_1.default.resolve(__dirname, 'templates/dir.html')).toString()); | ||
// You must call watcher.start() before you call `getMiddleware` | ||
@@ -25,110 +28,112 @@ // | ||
// liveReloadPath - LiveReload script URL for error pages | ||
module.exports = function getMiddleware(watcher, options) { | ||
if (options == null) | ||
options = {}; | ||
function handleRequest(outputPath, request, response, next, options) { | ||
const urlObj = url_1.default.parse(request.url); | ||
let pathname = urlObj.pathname || ''; | ||
let filename, stat, lastModified, buffer; | ||
try { | ||
filename = decodeURIComponent(pathname); | ||
if (!filename) { | ||
response.writeHead(400); | ||
response.end(); | ||
return; | ||
} | ||
filename = resolvePath(outputPath, filename.substr(1)); | ||
} | ||
catch (err) { | ||
response.writeHead(err.status || 500); | ||
response.end(); | ||
return; | ||
} | ||
try { | ||
stat = fs_1.default.statSync(filename); | ||
} | ||
catch (e) { | ||
// not found | ||
next(); | ||
return; | ||
} | ||
if (stat.isDirectory()) { | ||
const indexFilename = path_1.default.join(filename, 'index.html'); | ||
const hasIndex = fs_1.default.existsSync(indexFilename); | ||
if (!hasIndex && !options.autoIndex) { | ||
next(); | ||
return; | ||
} | ||
if (pathname[pathname.length - 1] !== '/') { | ||
urlObj.pathname += '/'; | ||
urlObj.host = request.headers['host']; | ||
urlObj.protocol = request.socket.encrypted ? 'https' : 'http'; | ||
response.setHeader('Location', url_1.default.format(urlObj)); | ||
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate'); | ||
response.writeHead(301); | ||
response.end(); | ||
return; | ||
} | ||
if (!hasIndex) { | ||
// implied: options.autoIndex is true | ||
const context = { | ||
url: request.url, | ||
files: fs_1.default | ||
.readdirSync(filename) | ||
.sort() | ||
.map(child => { | ||
const stat = fs_1.default.statSync(path_1.default.join(filename, child)), isDir = stat.isDirectory(); | ||
return { | ||
href: child + (isDir ? '/' : ''), | ||
type: isDir | ||
? 'dir' | ||
: path_1.default | ||
.extname(child) | ||
.replace('.', '') | ||
.toLowerCase(), | ||
}; | ||
}), | ||
liveReloadPath: options.liveReloadPath, | ||
}; | ||
response.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate'); | ||
response.writeHead(200); | ||
response.end(dirTemplate(context)); | ||
return; | ||
} | ||
// otherwise serve index.html | ||
filename = indexFilename; | ||
stat = fs_1.default.statSync(filename); | ||
} | ||
lastModified = stat.mtime.toUTCString(); | ||
response.setHeader('Last-Modified', lastModified); | ||
// nginx style treat last-modified as a tag since browsers echo it back | ||
if (request.headers['if-modified-since'] === lastModified) { | ||
response.writeHead(304); | ||
response.end(); | ||
return; | ||
} | ||
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate'); | ||
response.setHeader('Content-Length', stat.size); | ||
response.setHeader('Content-Type', mime_types_1.default.contentType(path_1.default.extname(filename))); | ||
// read file sync so we don't hold open the file creating a race with | ||
// the builder (Windows does not allow us to delete while the file is open). | ||
buffer = fs_1.default.readFileSync(filename); | ||
response.writeHead(200); | ||
response.end(buffer); | ||
} | ||
module.exports = function getMiddleware(watcher, options = {}) { | ||
if (options.autoIndex == null) | ||
options.autoIndex = true; | ||
const outputPath = path.resolve(watcher.builder.outputPath); | ||
return function broccoliMiddleware(request, response, next) { | ||
const outputPath = path_1.default.resolve(watcher.builder.outputPath); | ||
return async function broccoliMiddleware(request, response, next) { | ||
if (watcher.currentBuild == null) { | ||
throw new Error('Waiting for initial build to start'); | ||
} | ||
watcher.currentBuild | ||
.then(() => { | ||
const urlObj = url.parse(request.url); | ||
let pathname = urlObj.pathname; | ||
let filename, stat, lastModified, buffer; | ||
try { | ||
filename = decodeURIComponent(pathname); | ||
if (!filename) { | ||
response.writeHead(400); | ||
response.end(); | ||
return; | ||
} | ||
filename = resolvePath(outputPath, filename.substr(1)); | ||
} | ||
catch (err) { | ||
response.writeHead(err.status || 500); | ||
response.end(); | ||
return; | ||
} | ||
try { | ||
stat = fs.statSync(filename); | ||
} | ||
catch (e) { | ||
// not found | ||
next(); | ||
return; | ||
} | ||
if (stat.isDirectory()) { | ||
const indexFilename = path.join(filename, 'index.html'); | ||
const hasIndex = fs.existsSync(indexFilename); | ||
if (!hasIndex && !options.autoIndex) { | ||
next(); | ||
return; | ||
} | ||
if (pathname[pathname.length - 1] !== '/') { | ||
urlObj.pathname += '/'; | ||
urlObj.host = request.headers['host']; | ||
urlObj.protocol = request.socket.encrypted ? 'https' : 'http'; | ||
response.setHeader('Location', url.format(urlObj)); | ||
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate'); | ||
response.writeHead(301); | ||
response.end(); | ||
return; | ||
} | ||
if (!hasIndex) { | ||
// implied: options.autoIndex is true | ||
const context = { | ||
url: request.url, | ||
files: fs | ||
.readdirSync(filename) | ||
.sort() | ||
.map(child => { | ||
const stat = fs.statSync(path.join(filename, child)), isDir = stat.isDirectory(); | ||
return { | ||
href: child + (isDir ? '/' : ''), | ||
type: isDir | ||
? 'dir' | ||
: path | ||
.extname(child) | ||
.replace('.', '') | ||
.toLowerCase(), | ||
}; | ||
}), | ||
liveReloadPath: options.liveReloadPath, | ||
}; | ||
response.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate'); | ||
response.writeHead(200); | ||
response.end(dirTemplate(context)); | ||
return; | ||
} | ||
// otherwise serve index.html | ||
filename = indexFilename; | ||
stat = fs.statSync(filename); | ||
} | ||
lastModified = stat.mtime.toUTCString(); | ||
response.setHeader('Last-Modified', lastModified); | ||
// nginx style treat last-modified as a tag since browsers echo it back | ||
if (request.headers['if-modified-since'] === lastModified) { | ||
response.writeHead(304); | ||
response.end(); | ||
return; | ||
} | ||
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate'); | ||
response.setHeader('Content-Length', stat.size); | ||
response.setHeader('Content-Type', mime.contentType(path.extname(filename))); | ||
// read file sync so we don't hold open the file creating a race with | ||
// the builder (Windows does not allow us to delete while the file is open). | ||
buffer = fs.readFileSync(filename); | ||
response.writeHead(200); | ||
response.end(buffer); | ||
}, buildError => { | ||
try { | ||
await watcher.currentBuild; | ||
handleRequest(outputPath, request, response, next, options); | ||
} | ||
catch (error) { | ||
// All errors thrown from builder.build() are guaranteed to be | ||
// Builder.BuildError instances. | ||
const context = { | ||
stack: ansiHTML(buildError.stack || ''), | ||
stack: ansiHTML(error.stack || ''), | ||
liveReloadPath: options.liveReloadPath, | ||
payload: buildError.broccoliPayload, | ||
payload: error.broccoliPayload, | ||
}; | ||
@@ -138,6 +143,6 @@ response.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||
response.end(errorTemplate(context)); | ||
}) | ||
.catch(err => err.stack); | ||
return error.stack; | ||
} | ||
}; | ||
}; | ||
//# sourceMappingURL=middleware.js.map |
@@ -1,11 +0,13 @@ | ||
'use strict'; | ||
const promiseFinally = require('promise.prototype.finally'); | ||
const http = require('http'); | ||
const https = require('https'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const messages = require('./messages'); | ||
const middleware = require('./middleware'); | ||
const EventEmitter = require('events'); | ||
class Server extends EventEmitter { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const http_1 = __importDefault(require("http")); | ||
const https_1 = __importDefault(require("https")); | ||
const fs_1 = __importDefault(require("fs")); | ||
const path_1 = __importDefault(require("path")); | ||
const messages_1 = __importDefault(require("./messages")); | ||
const middleware_1 = __importDefault(require("./middleware")); | ||
const events_1 = __importDefault(require("events")); | ||
class Server extends events_1.default { | ||
constructor(watcher, host, port, connect = require('connect'), ui, ssl, sslKey, sslCert) { | ||
@@ -36,3 +38,3 @@ super(); | ||
} | ||
start() { | ||
async start() { | ||
if (this._started) { | ||
@@ -42,3 +44,3 @@ throw new Error('Watcher.prototype.start() must not be called more than once'); | ||
const promise = new Promise((resolve, reject) => { | ||
this.app = this._connect().use(middleware(this._watcher)); | ||
this.app = this._connect().use(middleware_1.default(this._watcher)); | ||
if (this._ssl) { | ||
@@ -48,13 +50,13 @@ let sslOptions; | ||
sslOptions = { | ||
key: fs.readFileSync(this._sslKey), | ||
cert: fs.readFileSync(this._sslCert), | ||
key: fs_1.default.readFileSync(this._sslKey), | ||
cert: fs_1.default.readFileSync(this._sslCert), | ||
}; | ||
} | ||
catch (err) { | ||
throw new Error(`SSL key and certificate files should be present at ${path.join(process.cwd(), this._sslKey)} and ${path.join(process.cwd(), this._sslCert)} respectively.`); | ||
throw new Error(`SSL key and certificate files should be present at ${path_1.default.join(process.cwd(), this._sslKey)} and ${path_1.default.join(process.cwd(), this._sslCert)} respectively.`); | ||
} | ||
this.instance = https.createServer(sslOptions, this.app); | ||
this.instance = https_1.default.createServer(sslOptions, this.app); | ||
} | ||
else { | ||
this.instance = http.createServer(this.app); | ||
this.instance = http_1.default.createServer(this.app); | ||
} | ||
@@ -66,3 +68,3 @@ this.instance.listen(this._port, this._host); | ||
}); | ||
this.instance.on('error', error => { | ||
this.instance.on('error', (error) => { | ||
if (error.code !== 'EADDRINUSE') { | ||
@@ -79,5 +81,5 @@ throw error; | ||
this.emit('buildSuccess'); | ||
messages.onBuildSuccess(this._builder, this.ui); | ||
messages_1.default.onBuildSuccess(this._builder, this.ui); | ||
}); | ||
this._watcher.on('buildFailure', err => { | ||
this._watcher.on('buildFailure', (err) => { | ||
this.emit('buildFailure'); | ||
@@ -88,3 +90,8 @@ this.ui.writeLine('build failure', 'ERROR'); | ||
}); | ||
return promiseFinally(promise, () => this.stop()); | ||
try { | ||
await promise; | ||
} | ||
finally { | ||
await this.stop(); | ||
} | ||
} | ||
@@ -95,3 +102,3 @@ _detachListeners() { | ||
} | ||
stop() { | ||
async stop() { | ||
this._detachListeners(); | ||
@@ -101,6 +108,7 @@ if (this.instance) { | ||
} | ||
return this._watcher.quit().then(() => this._builder.cleanup()); | ||
await this._watcher.quit(); | ||
await this._builder.cleanup(); | ||
} | ||
} | ||
exports.serve = function serve(watcher, host, port, _connect = require('connect'), _process = process, ui, ssl, sslKey, sslCert) { | ||
function serve(watcher, host, port, _connect = require('connect'), _process = process, ui, ssl, sslKey, sslCert) { | ||
const server = new Server(watcher, host, port, _connect, ui, ssl, sslKey, sslCert); | ||
@@ -115,4 +123,8 @@ return server | ||
}); | ||
} | ||
; | ||
module.exports = { | ||
Server, | ||
serve | ||
}; | ||
exports.Server = Server; | ||
//# sourceMappingURL=server.js.map |
@@ -1,2 +0,3 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function byTotalSelfTime(a, b) { | ||
@@ -15,3 +16,3 @@ return b.totalSelfTime - a.totalSelfTime; | ||
} | ||
module.exports = function calculateSummary(tree) { | ||
function calculateSummary(tree) { | ||
let totalTime = 0; | ||
@@ -22,5 +23,5 @@ let nodes = []; | ||
// calculate times | ||
tree.visitPostOrder(node => { | ||
tree.visitPostOrder((node) => { | ||
let nonbroccoliChildrenTime = 0; | ||
node.forEachChild(childNode => { | ||
node.forEachChild((childNode) => { | ||
// subsume non-broccoli nodes as their ancestor broccoli nodes' | ||
@@ -67,3 +68,5 @@ // broccoliSelfTime | ||
}; | ||
}; | ||
} | ||
exports.default = calculateSummary; | ||
; | ||
//# sourceMappingURL=calculate-summary.js.map |
@@ -1,3 +0,4 @@ | ||
'use strict'; | ||
module.exports = function filterMap(iterator, cb) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function filterMap(iterator, cb) { | ||
const result = []; | ||
@@ -10,3 +11,5 @@ for (const entry of iterator) { | ||
return result; | ||
}; | ||
} | ||
exports.default = filterMap; | ||
; | ||
//# sourceMappingURL=filter-map.js.map |
@@ -1,3 +0,7 @@ | ||
'use strict'; | ||
const calculateSummary = require('./calculate-summary'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const calculate_summary_1 = __importDefault(require("./calculate-summary")); | ||
function ellipsize(string, desiredLength) { | ||
@@ -11,5 +15,5 @@ if (string.length > desiredLength) { | ||
} | ||
module.exports = function printSlowNodes(tree, factor, ui) { | ||
function printSlowNodes(tree, factor, ui) { | ||
try { | ||
const summary = calculateSummary(tree); | ||
const summary = calculate_summary_1.default(tree); | ||
const pcThreshold = factor || 0.05; | ||
@@ -47,3 +51,5 @@ const msThreshold = pcThreshold * summary.totalTime; | ||
} | ||
}; | ||
} | ||
exports.default = printSlowNodes; | ||
; | ||
function pad(str, len, char, dir) { | ||
@@ -50,0 +56,0 @@ if (!char) { |
@@ -1,4 +0,5 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Replace all `undefined` values with `null`, so that they show up in JSON output | ||
module.exports = function undefinedToNull(obj) { | ||
function undefinedToNull(obj) { | ||
for (const key in obj) { | ||
@@ -10,3 +11,5 @@ if (obj.hasOwnProperty(key) && obj[key] === undefined) { | ||
return obj; | ||
}; | ||
} | ||
exports.default = undefinedToNull; | ||
; | ||
//# sourceMappingURL=undefined-to-null.js.map |
@@ -1,3 +0,4 @@ | ||
'use strict'; | ||
module.exports = function wrapPrimitiveErrors(err) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function wrapPrimitiveErrors(err) { | ||
if (err !== null && typeof err === 'object') { | ||
@@ -11,3 +12,5 @@ return err; | ||
} | ||
}; | ||
} | ||
exports.default = wrapPrimitiveErrors; | ||
; | ||
//# sourceMappingURL=wrap-primitive-errors.js.map |
@@ -1,19 +0,15 @@ | ||
'use strict'; | ||
const EventEmitter = require('events').EventEmitter; | ||
const sane = require('sane'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const sane_1 = __importDefault(require("sane")); | ||
const events_1 = require("events"); | ||
const source_node_1 = __importDefault(require("./wrappers/source-node")); | ||
const bind_file_event_1 = __importDefault(require("./utils/bind-file-event")); | ||
const logger = require('heimdalljs-logger')('broccoli:watcherAdapter'); | ||
const SourceNode = require('./wrappers/source-node'); | ||
function defaultFilterFunction(name) { | ||
return /^[^.]/.test(name); | ||
} | ||
function bindFileEvent(adapter, watcher, node, event) { | ||
watcher.on(event, (filepath, root) => { | ||
logger.debug(event, root + '/' + filepath); | ||
logger.debug(`revise called on node [${node.id}]`); | ||
node.revise(); | ||
adapter.emit('change', event, filepath, root); | ||
}); | ||
} | ||
module.exports = class WatcherAdapter extends EventEmitter { | ||
constructor(watchedNodes, options) { | ||
class WatcherAdapter extends events_1.EventEmitter { | ||
constructor(watchedNodes, options = {}) { | ||
super(); | ||
@@ -24,3 +20,3 @@ if (!Array.isArray(watchedNodes)) { | ||
for (const node of watchedNodes) { | ||
if (!(node instanceof SourceNode)) { | ||
if (!(node instanceof source_node_1.default)) { | ||
throw new Error(`${node} is not a SourceNode`); | ||
@@ -33,3 +29,3 @@ } | ||
this.watchedNodes = watchedNodes; | ||
this.options = options || {}; | ||
this.options = options; | ||
this.options.filter = this.options.filter || defaultFilterFunction; | ||
@@ -39,9 +35,9 @@ this.watchers = []; | ||
watch() { | ||
let watchers = this.watchedNodes.map(node => { | ||
let watchers = this.watchedNodes.map((node) => { | ||
const watchedPath = node.nodeInfo.sourceDirectory; | ||
const watcher = new sane(watchedPath, this.options); | ||
const watcher = sane_1.default(watchedPath, this.options); | ||
this.watchers.push(watcher); | ||
bindFileEvent(this, watcher, node, 'change'); | ||
bindFileEvent(this, watcher, node, 'add'); | ||
bindFileEvent(this, watcher, node, 'delete'); | ||
bind_file_event_1.default(this, watcher, node, 'change'); | ||
bind_file_event_1.default(this, watcher, node, 'add'); | ||
bind_file_event_1.default(this, watcher, node, 'delete'); | ||
return new Promise((resolve, reject) => { | ||
@@ -53,3 +49,3 @@ watcher.on('ready', resolve); | ||
watcher.removeAllListeners('error'); | ||
watcher.on('error', err => { | ||
watcher.on('error', (err) => { | ||
logger.debug('error', err); | ||
@@ -64,3 +60,5 @@ this.emit('error', err); | ||
quit() { | ||
let closing = this.watchers.map(watcher => new Promise((resolve, reject) => watcher.close(err => { | ||
let closing = this.watchers.map((watcher) => new Promise((resolve, reject) => | ||
// @ts-ignore | ||
watcher.close((err) => { | ||
if (err) | ||
@@ -74,4 +72,5 @@ reject(err); | ||
} | ||
}; | ||
module.exports.bindFileEvent = bindFileEvent; | ||
} | ||
; | ||
module.exports = WatcherAdapter; | ||
//# sourceMappingURL=watcher_adapter.js.map |
@@ -1,6 +0,8 @@ | ||
'use strict'; | ||
const path = require('path'); | ||
const promiseFinally = require('promise.prototype.finally'); | ||
const EventEmitter = require('events').EventEmitter; | ||
const WatcherAdapter = require('./watcher_adapter'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const path_1 = __importDefault(require("path")); | ||
const events_1 = require("events"); | ||
const watcher_adapter_1 = __importDefault(require("./watcher_adapter")); | ||
const logger = require('heimdalljs-logger')('broccoli:watcher'); | ||
@@ -10,3 +12,3 @@ // This Watcher handles all the Broccoli logic, such as debouncing. The | ||
// principle. | ||
module.exports = class Watcher extends EventEmitter { | ||
class Watcher extends events_1.EventEmitter { | ||
constructor(builder, watchedNodes, options = {}) { | ||
@@ -18,6 +20,6 @@ super(); | ||
} | ||
this._currentBuild = Promise.resolve(); | ||
this.builder = builder; | ||
this.watcherAdapter = | ||
this.options.watcherAdapter || new WatcherAdapter(watchedNodes, this.options.saneOptions); | ||
this.currentBuild = null; | ||
this.options.watcherAdapter || new watcher_adapter_1.default(watchedNodes, this.options.saneOptions); | ||
this._rebuildScheduled = false; | ||
@@ -29,2 +31,25 @@ this._ready = false; | ||
} | ||
get currentBuild() { | ||
return this._currentBuild; | ||
} | ||
// TODO: this is an interim solution, pending a largerly cleanup of this class. | ||
// Currently I can rely on understanding the various pieces of this class, to | ||
// know this is safe. This is not a good long term solution, but given | ||
// relatively little time to address this currently, it is "ok". I do plan, | ||
// as time permits to circle back, and do a more thorough refactoring of this | ||
// class, to ensure it is safe for future travelers. | ||
_updateCurrentBuild(promise) { | ||
this._currentBuild = promise; | ||
promise.catch(() => { | ||
/** | ||
* The watcher internally follows currentBuild, and outputs errors appropriately. | ||
* Since watcher.currentBuild is public API, we must allow public follows | ||
* to still be informed of rejections. However we do not want `_currentBuild` itself | ||
* to trigger unhandled rejections. | ||
* | ||
* By catching errors here, but returning `promise` instead of the chain from | ||
* `promise.catch`, both goals are accomplished. | ||
*/ | ||
}); | ||
} | ||
start() { | ||
@@ -34,3 +59,4 @@ if (this._lifetime != null) { | ||
} | ||
let lifetime = (this._lifetime = {}); | ||
this._lifetime = {}; | ||
let lifetime = this._lifetime; | ||
lifetime.promise = new Promise((resolve, reject) => { | ||
@@ -42,17 +68,17 @@ lifetime.resolve = resolve; | ||
this.watcherAdapter.on('error', this._error.bind(this)); | ||
this.currentBuild = Promise.resolve() | ||
.then(() => { | ||
return this.watcherAdapter.watch(); | ||
}) | ||
.then(() => { | ||
logger.debug('ready'); | ||
this._ready = true; | ||
this.currentBuild = this._build(); | ||
}) | ||
.catch(err => this._error(err)) | ||
.then(() => this.currentBuild); | ||
this._updateCurrentBuild((async () => { | ||
try { | ||
await this.watcherAdapter.watch(); | ||
logger.debug('ready'); | ||
this._ready = true; | ||
} | ||
catch (e) { | ||
this._error(e); | ||
} | ||
await this._build(); | ||
})()); | ||
return this._lifetime.promise; | ||
} | ||
_change(event, filePath, root) { | ||
this._changedFiles.push(path.join(root, filePath)); | ||
async _change(event, filePath, root) { | ||
this._changedFiles.push(path_1.default.join(root, filePath)); | ||
if (!this._ready) { | ||
@@ -69,21 +95,30 @@ logger.debug('change', 'ignored: before ready'); | ||
this._rebuildScheduled = true; | ||
// Wait for current build, and ignore build failure | ||
return Promise.resolve(this.currentBuild) | ||
.catch(() => { }) | ||
.then(() => { | ||
if (this._quitting) { | ||
return; | ||
} | ||
const buildPromise = new Promise(resolve => { | ||
logger.debug('debounce'); | ||
this.emit('debounce'); | ||
setTimeout(resolve, this.options.debounce); | ||
}).then(() => { | ||
try { | ||
// Wait for current build, and ignore build failure | ||
await this.currentBuild; | ||
} | ||
catch (e) { | ||
/* we don't care about failures in the last build, simply start the | ||
* next build once the last build has completed | ||
* */ | ||
} | ||
if (this._quitting) { | ||
this._updateCurrentBuild(Promise.resolve()); | ||
return; | ||
} | ||
this._updateCurrentBuild(new Promise((resolve, reject) => { | ||
logger.debug('debounce'); | ||
this.emit('debounce'); | ||
setTimeout(() => { | ||
// Only set _rebuildScheduled to false *after* the setTimeout so that | ||
// change events during the setTimeout don't trigger a second rebuild | ||
this._rebuildScheduled = false; | ||
return this._build(path.join(root, filePath)); | ||
}); | ||
this.currentBuild = buildPromise; | ||
}); | ||
try { | ||
this._rebuildScheduled = false; | ||
resolve(this._build(path_1.default.join(root, filePath))); | ||
} | ||
catch (e) { | ||
reject(e); | ||
} | ||
}, this.options.debounce); | ||
})); | ||
} | ||
@@ -93,4 +128,4 @@ _build(filePath) { | ||
this.emit('buildStart'); | ||
const hrstart = process.hrtime(); | ||
// This is to maintain backwards compatiblity with broccoli-sane-watcher | ||
const start = process.hrtime(); | ||
// This is to maintain backwards compatibility with broccoli-sane-watcher | ||
let annotation = { | ||
@@ -107,6 +142,6 @@ type: filePath ? 'rebuild' : 'initial', | ||
buildPromise.then((results = {}) => { | ||
const hrend = process.hrtime(hrstart); | ||
logger.debug('Build execution time: %ds %dms', hrend[0], Math.round(hrend[1] / 1e6)); | ||
const end = process.hrtime(start); | ||
logger.debug('Build execution time: %ds %dms', end[0], Math.round(end[1] / 1e6)); | ||
logger.debug('buildSuccess'); | ||
// This property is added to keep compatiblity for ember-cli | ||
// This property is added to keep compatibility for ember-cli | ||
// as it relied on broccoli-sane-watcher to add it: | ||
@@ -119,3 +154,3 @@ // https://github.com/ember-cli/broccoli-sane-watcher/blob/48860/index.js#L92-L95 | ||
this.emit('buildSuccess', results); | ||
}, err => { | ||
}, (err) => { | ||
this._changedFiles = []; | ||
@@ -127,3 +162,3 @@ logger.debug('buildFailure'); | ||
} | ||
_error(err) { | ||
async _error(err) { | ||
if (this._quittingPromise) { | ||
@@ -135,5 +170,11 @@ logger.debug('error', 'ignored: already quitting'); | ||
this.emit('error', err); | ||
return this._quit() | ||
.catch(() => { }) | ||
.then(() => this._lifetime.reject(err)); | ||
try { | ||
await this._quit(); | ||
} | ||
catch (e) { | ||
// ignore errors that occur during quitting | ||
} | ||
if (this._lifetime && typeof this._lifetime.reject === 'function') { | ||
this._lifetime.reject(err); | ||
} | ||
} | ||
@@ -146,3 +187,3 @@ quit() { | ||
let quitting = this._quit(); | ||
if (this._lifetime) { | ||
if (this._lifetime && typeof this._lifetime.resolve === 'function') { | ||
this._lifetime.resolve(quitting); | ||
@@ -158,12 +199,21 @@ return this._lifetime.promise; | ||
this.emit('quitStart'); | ||
this._quittingPromise = promiseFinally(promiseFinally(Promise.resolve().then(() => this.watcherAdapter.quit()), () => { | ||
// Wait for current build, and ignore build failure | ||
return Promise.resolve(this.currentBuild).catch(() => { }); | ||
}), () => { | ||
logger.debug('quitEnd'); | ||
this.emit('quitEnd'); | ||
}); | ||
this._quittingPromise = (async () => { | ||
try { | ||
await this.watcherAdapter.quit(); | ||
} | ||
finally { | ||
try { | ||
await this.currentBuild; | ||
} | ||
catch (e) { | ||
// Wait for current build, and ignore build failure | ||
} | ||
logger.debug('quitEnd'); | ||
this.emit('quitEnd'); | ||
} | ||
})(); | ||
return this._quittingPromise; | ||
} | ||
}; | ||
} | ||
module.exports = Watcher; | ||
//# sourceMappingURL=watcher.js.map |
@@ -1,4 +0,8 @@ | ||
'use strict'; | ||
const undefinedToNull = require('../utils/undefined-to-null'); | ||
module.exports = class NodeWrapper { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const undefined_to_null_1 = __importDefault(require("../utils/undefined-to-null")); | ||
class NodeWrapper { | ||
constructor() { | ||
@@ -15,3 +19,3 @@ this.buildState = {}; | ||
toJSON() { | ||
return undefinedToNull({ | ||
return undefined_to_null_1.default({ | ||
id: this.id, | ||
@@ -29,3 +33,9 @@ nodeInfo: this.nodeInfoToJSON(), | ||
} | ||
}; | ||
nodeInfoToJSON() { | ||
return {}; | ||
} | ||
; | ||
} | ||
exports.default = NodeWrapper; | ||
; | ||
//# sourceMappingURL=node.js.map |
@@ -1,6 +0,10 @@ | ||
'use strict'; | ||
const NodeWrapper = require('./node'); | ||
const fs = require('fs'); | ||
const undefinedToNull = require('../utils/undefined-to-null'); | ||
module.exports = class SourceNodeWrapper extends NodeWrapper { | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = __importDefault(require("fs")); | ||
const node_1 = __importDefault(require("./node")); | ||
const undefined_to_null_1 = __importDefault(require("../utils/undefined-to-null")); | ||
class SourceNodeWrapper extends node_1.default { | ||
setup( /* features */) { } | ||
@@ -10,3 +14,3 @@ build() { | ||
try { | ||
if (!fs.statSync(this.nodeInfo.sourceDirectory).isDirectory()) { | ||
if (!fs_1.default.statSync(this.nodeInfo.sourceDirectory).isDirectory()) { | ||
throw new Error('Not a directory'); | ||
@@ -31,3 +35,3 @@ } | ||
nodeInfoToJSON() { | ||
return undefinedToNull({ | ||
return undefined_to_null_1.default({ | ||
nodeType: 'source', | ||
@@ -40,3 +44,5 @@ sourceDirectory: this.nodeInfo.sourceDirectory, | ||
} | ||
}; | ||
} | ||
exports.default = SourceNodeWrapper; | ||
; | ||
//# sourceMappingURL=source-node.js.map |
@@ -1,8 +0,12 @@ | ||
'use strict'; | ||
const NodeWrapper = require('./node'); | ||
const fs = require('fs'); | ||
const undefinedToNull = require('../utils/undefined-to-null'); | ||
const rimraf = require('rimraf'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = __importDefault(require("fs")); | ||
const rimraf_1 = __importDefault(require("rimraf")); | ||
const undefined_to_null_1 = __importDefault(require("../utils/undefined-to-null")); | ||
const node_1 = __importDefault(require("./node")); | ||
const logger = require('heimdalljs-logger')('broccoli:transform-node'); | ||
module.exports = class TransformNodeWrapper extends NodeWrapper { | ||
class TransformNodeWrapper extends node_1.default { | ||
setup(features) { | ||
@@ -22,3 +26,3 @@ this.nodeInfo.setup(features, { | ||
let nodesThatChanged = []; | ||
this.inputNodeWrappers.forEach(wrapper => { | ||
this.inputNodeWrappers.forEach((wrapper) => { | ||
let wrapper_revision_meta = this.inputRevisions.get(wrapper); | ||
@@ -52,35 +56,31 @@ if (!wrapper_revision_meta || wrapper_revision_meta.revision !== wrapper.revision) { | ||
} | ||
build() { | ||
let startTime; | ||
return new Promise(resolve => { | ||
startTime = process.hrtime(); | ||
if (!this.shouldBuild()) { | ||
this.buildState.built = false; | ||
return resolve(); // Noop the build since inputs did not change | ||
} | ||
if (!this.nodeInfo.persistentOutput) { | ||
rimraf.sync(this.outputPath); | ||
fs.mkdirSync(this.outputPath); | ||
} | ||
if (this.nodeInfo.trackInputChanges === true) { | ||
let changed = this.inputNodeWrappers.map(wrapper => this.inputRevisions.get(wrapper).changed); | ||
resolve(this.callbackObject.build({ changedNodes: changed })); | ||
} | ||
else { | ||
resolve(this.callbackObject.build()); | ||
} | ||
this.revise(); | ||
}).then(() => { | ||
const now = process.hrtime(); | ||
const endTime = process.hrtime(startTime); | ||
// Build time in milliseconds | ||
this.buildState.selfTime = 1000 * (now[0] - startTime[0] + (now[1] - startTime[1]) / 1e9); | ||
this.buildState.totalTime = this.buildState.selfTime; | ||
for (let i = 0; i < this.inputNodeWrappers.length; i++) { | ||
this.buildState.totalTime += this.inputNodeWrappers[i].buildState.totalTime; | ||
} | ||
if (this.buildState.selfTime >= 100) { | ||
logger.debug(`Node build execution time: %ds %dms`, endTime[0], Math.round(endTime[1] / 1e6)); | ||
} | ||
}); | ||
async build() { | ||
let startTime = process.hrtime(); | ||
if (!this.shouldBuild()) { | ||
this.buildState.built = false; | ||
return; // Noop the build since inputs did not change | ||
} | ||
if (!this.nodeInfo.persistentOutput) { | ||
rimraf_1.default.sync(this.outputPath); | ||
fs_1.default.mkdirSync(this.outputPath); | ||
} | ||
if (this.nodeInfo.trackInputChanges === true) { | ||
let changed = this.inputNodeWrappers.map(wrapper => this.inputRevisions.get(wrapper).changed); | ||
await this.callbackObject.build({ changedNodes: changed }); | ||
} | ||
else { | ||
await this.callbackObject.build(); | ||
} | ||
this.revise(); | ||
const now = process.hrtime(); | ||
const endTime = process.hrtime(startTime); | ||
// Build time in milliseconds | ||
this.buildState.selfTime = 1000 * (now[0] - startTime[0] + (now[1] - startTime[1]) / 1e9); | ||
this.buildState.totalTime = this.buildState.selfTime; | ||
for (let i = 0; i < this.inputNodeWrappers.length; i++) { | ||
this.buildState.totalTime += this.inputNodeWrappers[i].buildState.totalTime || 0; | ||
} | ||
if (this.buildState.selfTime >= 100) { | ||
logger.debug(`Node build execution time: %ds %dms`, endTime[0], Math.round(endTime[1] / 1e6)); | ||
} | ||
} | ||
@@ -100,3 +100,3 @@ toString() { | ||
nodeInfoToJSON() { | ||
return undefinedToNull({ | ||
return undefined_to_null_1.default({ | ||
nodeType: 'transform', | ||
@@ -109,3 +109,5 @@ name: this.nodeInfo.name, | ||
} | ||
}; | ||
} | ||
exports.default = TransformNodeWrapper; | ||
; | ||
//# sourceMappingURL=transform-node.js.map |
{ | ||
"name": "broccoli", | ||
"version": "3.2.0", | ||
"version": "3.2.1", | ||
"description": "Fast client-side asset builder", | ||
@@ -30,11 +30,14 @@ "keywords": [ | ||
"pretest": "multidep test/multidep.json", | ||
"test": "yarn build && mocha", | ||
"test:debug": "yarn build && mocha --inspect-brk", | ||
"test": "yarn build && mocha -r test/utils/requires", | ||
"test:debug": "yarn build && mocha --inspect-brk -r test/utils/requires", | ||
"watch": "tsc --watch" | ||
}, | ||
"dependencies": { | ||
"@types/chai": "^4.2.9", | ||
"@types/chai-as-promised": "^7.1.2", | ||
"@types/express": "^4.17.2", | ||
"ansi-html": "^0.0.7", | ||
"broccoli-node-info": "^2.1.0", | ||
"broccoli-slow-trees": "^3.0.1", | ||
"broccoli-source": "^1.1.0", | ||
"broccoli-source": "^3.0.0", | ||
"commander": "^2.15.1", | ||
@@ -50,7 +53,6 @@ "connect": "^3.6.6", | ||
"mime-types": "^2.1.19", | ||
"promise.prototype.finally": "^3.1.0", | ||
"resolve-path": "^1.4.0", | ||
"rimraf": "^2.6.2", | ||
"sane": "^4.0.0", | ||
"tmp": "0.0.33", | ||
"tmp": "^0.0.33", | ||
"tree-sync": "^1.2.2", | ||
@@ -61,6 +63,16 @@ "underscore.string": "^3.2.2", | ||
"devDependencies": { | ||
"@types/console-ui": "^2.2.3", | ||
"@types/findup-sync": "^2.0.2", | ||
"@types/mime-types": "^2.1.0", | ||
"@types/node": "^12.7.1", | ||
"@types/rimraf": "^2.0.2", | ||
"@types/sane": "^2.0.0", | ||
"@types/tmp": "^0.0.33", | ||
"@typescript-eslint/eslint-plugin": "^2.3.0", | ||
"@typescript-eslint/parser": "^2.3.0", | ||
"broccoli-node-api": "^1.7.0", | ||
"chai": "^4.1.2", | ||
"chai-as-promised": "^7.1.1", | ||
"copyfiles": "^2.1.1", | ||
"eslint": "^6.4.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
@@ -72,2 +84,3 @@ "eslint-plugin-mocha": "^5.0.0", | ||
"got": "^9.0.0", | ||
"longjohn": "^0.2.12", | ||
"mocha": "^5.2.0", | ||
@@ -81,5 +94,6 @@ "mocha-eslint": "^4.1.0", | ||
"sinon-chai": "^3.1.0", | ||
"source-map-support": "^0.5.16", | ||
"symlink-or-copy": "^1.2.0", | ||
"ts-node": "^8.0.3", | ||
"typescript": "^3.3.3333" | ||
"typescript": "~3.8.0" | ||
}, | ||
@@ -86,0 +100,0 @@ "engines": { |
@@ -5,4 +5,3 @@ # Broccoli | ||
[![Build Status](https://travis-ci.org/broccolijs/broccoli.svg?branch=master)](https://travis-ci.org/broccolijs/broccoli) | ||
[![Build status](https://ci.appveyor.com/api/projects/status/jd3ts93gryjeqclf/branch/master?svg=true)](https://ci.appveyor.com/project/joliss/broccoli/branch/master) | ||
[![Build Status](https://github.com/broccolijs/broccoli/workflows/CI/badge.svg)](https://github.com/broccolijs/broccoli/actions) | ||
@@ -9,0 +8,0 @@ A fast, reliable asset pipeline, supporting constant-time rebuilds and compact |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
162771
56
1865
3
24
33
281
+ Added@types/chai@^4.2.9
+ Added@types/express@^4.17.2
+ Added@types/body-parser@1.19.5(transitive)
+ Added@types/chai@4.3.20(transitive)
+ Added@types/chai-as-promised@7.1.8(transitive)
+ Added@types/connect@3.4.38(transitive)
+ Added@types/express@4.17.21(transitive)
+ Added@types/express-serve-static-core@4.19.6(transitive)
+ Added@types/http-errors@2.0.4(transitive)
+ Added@types/mime@1.3.5(transitive)
+ Added@types/node@22.9.1(transitive)
+ Added@types/qs@6.9.17(transitive)
+ Added@types/range-parser@1.2.7(transitive)
+ Added@types/send@0.17.4(transitive)
+ Added@types/serve-static@1.15.7(transitive)
+ Addedbroccoli-node-api@1.7.0(transitive)
+ Addedbroccoli-source@3.0.1(transitive)
+ Addedundici-types@6.19.8(transitive)
- Removedpromise.prototype.finally@^3.1.0
- Removedarray-buffer-byte-length@1.0.1(transitive)
- Removedarraybuffer.prototype.slice@1.0.3(transitive)
- Removedavailable-typed-arrays@1.0.7(transitive)
- Removedbroccoli-source@1.1.0(transitive)
- Removeddata-view-buffer@1.0.1(transitive)
- Removeddata-view-byte-length@1.0.1(transitive)
- Removeddata-view-byte-offset@1.0.0(transitive)
- Removeddefine-properties@1.2.1(transitive)
- Removedes-abstract@1.23.5(transitive)
- Removedes-object-atoms@1.0.0(transitive)
- Removedes-set-tostringtag@2.0.3(transitive)
- Removedes-to-primitive@1.2.1(transitive)
- Removedfor-each@0.3.3(transitive)
- Removedfunction.prototype.name@1.1.6(transitive)
- Removedfunctions-have-names@1.2.3(transitive)
- Removedget-symbol-description@1.0.2(transitive)
- Removedglobalthis@1.0.4(transitive)
- Removedhas-bigints@1.0.2(transitive)
- Removedhas-tostringtag@1.0.2(transitive)
- Removedinternal-slot@1.0.7(transitive)
- Removedis-array-buffer@3.0.4(transitive)
- Removedis-async-function@2.0.0(transitive)
- Removedis-bigint@1.0.4(transitive)
- Removedis-boolean-object@1.1.2(transitive)
- Removedis-callable@1.2.7(transitive)
- Removedis-data-view@1.0.1(transitive)
- Removedis-date-object@1.0.5(transitive)
- Removedis-finalizationregistry@1.0.2(transitive)
- Removedis-generator-function@1.0.10(transitive)
- Removedis-map@2.0.3(transitive)
- Removedis-negative-zero@2.0.3(transitive)
- Removedis-number-object@1.0.7(transitive)
- Removedis-regex@1.1.4(transitive)
- Removedis-set@2.0.3(transitive)
- Removedis-shared-array-buffer@1.0.3(transitive)
- Removedis-string@1.0.7(transitive)
- Removedis-symbol@1.0.4(transitive)
- Removedis-typed-array@1.1.13(transitive)
- Removedis-weakmap@2.0.2(transitive)
- Removedis-weakref@1.0.2(transitive)
- Removedis-weakset@2.0.3(transitive)
- Removedobject-inspect@1.13.3(transitive)
- Removedobject.assign@4.1.5(transitive)
- Removedpossible-typed-array-names@1.0.0(transitive)
- Removedpromise.prototype.finally@3.1.8(transitive)
- Removedreflect.getprototypeof@1.0.6(transitive)
- Removedregexp.prototype.flags@1.5.3(transitive)
- Removedsafe-array-concat@1.1.2(transitive)
- Removedsafe-regex-test@1.0.3(transitive)
- Removedset-function-name@2.0.2(transitive)
- Removedside-channel@1.0.6(transitive)
- Removedstring.prototype.trim@1.2.9(transitive)
- Removedstring.prototype.trimend@1.0.8(transitive)
- Removedstring.prototype.trimstart@1.0.8(transitive)
- Removedtyped-array-buffer@1.0.2(transitive)
- Removedtyped-array-byte-length@1.0.1(transitive)
- Removedtyped-array-byte-offset@1.0.3(transitive)
- Removedtyped-array-length@1.0.6(transitive)
- Removedunbox-primitive@1.0.2(transitive)
- Removedwhich-boxed-primitive@1.0.2(transitive)
- Removedwhich-builtin-type@1.1.4(transitive)
- Removedwhich-collection@1.0.2(transitive)
- Removedwhich-typed-array@1.1.15(transitive)
Updatedbroccoli-source@^3.0.0
Updatedtmp@^0.0.33