@sequencemedia/gulp-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +13 -0
- package/bin/gulp.mjs +5 -0
- package/completion/README.md +20 -0
- package/completion/bash +27 -0
- package/completion/fish +10 -0
- package/completion/powershell +61 -0
- package/completion/zsh +25 -0
- package/gulp.1 +83 -0
- package/index.mjs +140 -0
- package/lib/ansi.mjs +46 -0
- package/lib/cli-options.mjs +120 -0
- package/lib/config/cli-flags.mjs +21 -0
- package/lib/config/env-flags.mjs +41 -0
- package/lib/config/load-files.mjs +50 -0
- package/lib/exit.mjs +8 -0
- package/lib/format-error.mjs +19 -0
- package/lib/get-blacklist.mjs +7 -0
- package/lib/get-completion.mjs +21 -0
- package/lib/get-duplicate.mjs +80 -0
- package/lib/get-package-blacklist.mjs +23 -0
- package/lib/get-process-title.mjs +3 -0
- package/lib/get-task.mjs +41 -0
- package/lib/index.mjs +59 -0
- package/lib/log/listen-for-gulp-events.mjs +46 -0
- package/lib/log/listen-for-level-events.mjs +49 -0
- package/lib/log/listen-for-sync-events.mjs +58 -0
- package/lib/log/tasks-json.mjs +16 -0
- package/lib/log/tasks-list.mjs +3 -0
- package/lib/log/tasks.mjs +163 -0
- package/lib/register-gulp-tasks.mjs +7 -0
- package/lib/run-gulp-tasks-json-tree.mjs +14 -0
- package/lib/run-gulp-tasks-list-tree.mjs +7 -0
- package/lib/run-gulp-tasks-tree.mjs +16 -0
- package/lib/run-gulp-tasks.mjs +46 -0
- package/lib/run-verify.mjs +56 -0
- package/lib/run-version.mjs +26 -0
- package/lib/tildify.mjs +5 -0
- package/package.json +84 -0
- package/where-am-i.mjs +9 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import copyProps from 'copy-props'
|
|
2
|
+
import {
|
|
3
|
+
join,
|
|
4
|
+
extname,
|
|
5
|
+
resolve,
|
|
6
|
+
dirname
|
|
7
|
+
} from 'node:path'
|
|
8
|
+
|
|
9
|
+
function getConfig (module) {
|
|
10
|
+
if (Reflect.has(module, 'default')) return Reflect.get(module, 'default')
|
|
11
|
+
return module
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default async function loadConfigFiles (configFiles = {}, configFileOrder = []) {
|
|
15
|
+
const config = {}
|
|
16
|
+
|
|
17
|
+
const keyList = (
|
|
18
|
+
configFileOrder
|
|
19
|
+
.filter((key) => configFiles[key])
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
while (keyList.length) {
|
|
23
|
+
const key = keyList.shift()
|
|
24
|
+
const filePath = configFiles[key]
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const module = (
|
|
28
|
+
extname(filePath) === '.json'
|
|
29
|
+
? await import(resolve(join(process.cwd(), filePath)), { assert: { type: 'json' } })
|
|
30
|
+
: await import(resolve(join(process.cwd(), filePath)))
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
copyProps(getConfig(module), config, ({ keyChain, value }) => {
|
|
34
|
+
if (keyChain === 'flags.gulpfile') {
|
|
35
|
+
return resolve(dirname(filePath), value)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return value
|
|
39
|
+
})
|
|
40
|
+
} catch (e) {
|
|
41
|
+
const {
|
|
42
|
+
code
|
|
43
|
+
} = e
|
|
44
|
+
|
|
45
|
+
if (code !== 'ERR_MODULE_NOT_FOUND') console.error(e)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return config
|
|
50
|
+
}
|
package/lib/exit.mjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Format orchestrator errors
|
|
2
|
+
export default function formatError (e) {
|
|
3
|
+
if (!e.error) {
|
|
4
|
+
return e.message
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// PluginError
|
|
8
|
+
if (typeof e.error.showStack === 'boolean') {
|
|
9
|
+
return e.error.toString()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Normal error
|
|
13
|
+
if (e.error.stack) {
|
|
14
|
+
return e.error.stack
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Unknown (string, number, etc.)
|
|
18
|
+
return new Error(String(e.error)).stack
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
readFile
|
|
5
|
+
} from 'node:fs/promises'
|
|
6
|
+
|
|
7
|
+
export default async function getCompletion (completionType) {
|
|
8
|
+
if (typeof completionType !== 'string') {
|
|
9
|
+
throw new Error('Completion type not provided')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const filePath = path.join('./completion', completionType)
|
|
14
|
+
const fileData = await readFile(filePath, 'utf8')
|
|
15
|
+
console.log(fileData.toString().trim())
|
|
16
|
+
process.exit(0)
|
|
17
|
+
} catch (e) {
|
|
18
|
+
console.error(`echo "Completion type "${completionType}" not found"`)
|
|
19
|
+
process.exit(5)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const DEFAULT_NODE_FACTORY = {
|
|
2
|
+
topNode: getDuplicateOf,
|
|
3
|
+
taskNode: getDuplicateOf,
|
|
4
|
+
childNode: getDuplicateOf
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function getDuplicateOf (node) {
|
|
8
|
+
return Object.fromEntries(Object.entries(node))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function hasCompactTasks ({ compactTasks = false }) {
|
|
12
|
+
return String(compactTasks) === 'true'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getTasksDepth ({ tasksDepth }) {
|
|
16
|
+
return (
|
|
17
|
+
typeof tasksDepth === 'number' && !isNaN(tasksDepth)
|
|
18
|
+
? Math.max(1, tasksDepth)
|
|
19
|
+
: null
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function nonRecursiveDuplicateNode (child, parent, nodeFactory) {
|
|
24
|
+
const dupe = nodeFactory.childNode(child)
|
|
25
|
+
dupe.nodes = []
|
|
26
|
+
|
|
27
|
+
parent.nodes.push(dupe)
|
|
28
|
+
|
|
29
|
+
if (child.branch) {
|
|
30
|
+
duplicateNodesFor(child, nonRecursiveDuplicateNode, dupe, nodeFactory)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function recursiveDuplicateNode (child, parent, maximumDepth, currentDepth, nodeFactory) {
|
|
35
|
+
const dupe = nodeFactory.childNode(child)
|
|
36
|
+
dupe.nodes = []
|
|
37
|
+
|
|
38
|
+
parent.nodes.push(dupe)
|
|
39
|
+
|
|
40
|
+
if (!maximumDepth || maximumDepth > currentDepth) {
|
|
41
|
+
duplicateNodesFor(child, recursiveDuplicateNode, dupe, maximumDepth, currentDepth + 1, nodeFactory)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function duplicateNodesFor ({ nodes }, duplicate, ...args) {
|
|
46
|
+
if (Array.isArray(nodes)) {
|
|
47
|
+
nodes
|
|
48
|
+
.forEach((node) => {
|
|
49
|
+
duplicate(node, ...args)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function duplicateNode (node, tree, cliProps, nodeFactory = DEFAULT_NODE_FACTORY) {
|
|
55
|
+
const dupe = nodeFactory.taskNode(node)
|
|
56
|
+
dupe.nodes = []
|
|
57
|
+
|
|
58
|
+
tree.nodes.push(dupe)
|
|
59
|
+
|
|
60
|
+
if (hasCompactTasks(cliProps)) {
|
|
61
|
+
duplicateNodesFor(node, nonRecursiveDuplicateNode, dupe, nodeFactory)
|
|
62
|
+
} else {
|
|
63
|
+
const maximumDepth = getTasksDepth(cliProps)
|
|
64
|
+
|
|
65
|
+
if (!maximumDepth || maximumDepth > 1) {
|
|
66
|
+
duplicateNodesFor(node, recursiveDuplicateNode, dupe, maximumDepth, 2, nodeFactory)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function duplicateTree (tree = {}, cliProps = {}, nodeFactory = DEFAULT_NODE_FACTORY) {
|
|
72
|
+
const dupe = nodeFactory.topNode(tree)
|
|
73
|
+
dupe.nodes = []
|
|
74
|
+
|
|
75
|
+
duplicateNodesFor(tree, duplicateNode, dupe, cliProps, nodeFactory)
|
|
76
|
+
|
|
77
|
+
return dupe
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default duplicateTree
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import matchdep from 'matchdep'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given a collection of plugin names verifies this collection against
|
|
5
|
+
* the blacklist. Returns an object with:
|
|
6
|
+
* [plugin name]=>[blacklisting reason]
|
|
7
|
+
* or an empty object if none of the dependencies to check are blacklisted.
|
|
8
|
+
*
|
|
9
|
+
* @param packageJson - The package JSON
|
|
10
|
+
* @param blacklistJson - The blacklist JSON
|
|
11
|
+
*/
|
|
12
|
+
function getPackageBlacklist (packageJson, blacklistJson) {
|
|
13
|
+
return (
|
|
14
|
+
matchdep
|
|
15
|
+
.filterAll(Object.keys(blacklistJson), packageJson)
|
|
16
|
+
.reduce((blacklist, dependency) => {
|
|
17
|
+
blacklist[dependency] = blacklistJson[dependency]
|
|
18
|
+
return blacklist
|
|
19
|
+
}, {})
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default getPackageBlacklist
|
package/lib/get-task.mjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import isObject from 'isobject'
|
|
2
|
+
|
|
3
|
+
function isString (value) {
|
|
4
|
+
return typeof value === 'string'
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function isFunction (value) {
|
|
8
|
+
return value instanceof Function
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getDescription (task = {}) {
|
|
12
|
+
if (isString(task.description)) {
|
|
13
|
+
return task.description
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (isFunction(task.unwrap)) {
|
|
17
|
+
return getDescription(task.unwrap())
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getFlags (task = {}) {
|
|
22
|
+
if (isObject(task.flags)) {
|
|
23
|
+
return task.flags
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (isFunction(task.unwrap)) {
|
|
27
|
+
return getFlags(task.unwrap())
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getTask (gulp) {
|
|
32
|
+
return function getTaskFor (name) {
|
|
33
|
+
const task = gulp.task(name)
|
|
34
|
+
return {
|
|
35
|
+
description: getDescription(task),
|
|
36
|
+
flags: getFlags(task)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default getTask
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import stdout from 'mute-stdout'
|
|
2
|
+
|
|
3
|
+
import listenForGulpEvents from './log/listen-for-gulp-events.mjs'
|
|
4
|
+
import listenForSyncEvents from './log/listen-for-sync-events.mjs'
|
|
5
|
+
import registerGulpTasks from './register-gulp-tasks.mjs'
|
|
6
|
+
|
|
7
|
+
import runGulpTasks from './run-gulp-tasks.mjs'
|
|
8
|
+
|
|
9
|
+
function getImportFromModulePath (params) {
|
|
10
|
+
const {
|
|
11
|
+
envProps: {
|
|
12
|
+
modulePath
|
|
13
|
+
}
|
|
14
|
+
} = params
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
import(modulePath)
|
|
18
|
+
.then(({ default: gulp }) => Object.assign(params, { gulp }))
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getImportFromConfigPath (params) {
|
|
23
|
+
const {
|
|
24
|
+
envProps: {
|
|
25
|
+
configPath
|
|
26
|
+
}
|
|
27
|
+
} = params
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
import(configPath)
|
|
31
|
+
.then((tasks) => Object.assign(params, { tasks }))
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isSilent (cliProps) {
|
|
36
|
+
return (cliProps.tasksList || cliProps.tasks || cliProps.tasksJson)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function run (cliProps, envProps, configProps = {}) {
|
|
40
|
+
if (isSilent(cliProps)) stdout.mute()
|
|
41
|
+
|
|
42
|
+
const { gulp, tasks } = (
|
|
43
|
+
await Promise.resolve({ cliProps, envProps, configProps })
|
|
44
|
+
.then(getImportFromModulePath)
|
|
45
|
+
.then(getImportFromConfigPath)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
listenForGulpEvents(gulp)
|
|
49
|
+
listenForSyncEvents(gulp, cliProps)
|
|
50
|
+
registerGulpTasks(gulp, tasks)
|
|
51
|
+
|
|
52
|
+
stdout.unmute()
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
runGulpTasks(gulp, cliProps, envProps, configProps)
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export default run
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import log from 'gulplog'
|
|
2
|
+
import prettyHrtime from 'pretty-hrtime'
|
|
3
|
+
|
|
4
|
+
import ansi from '../ansi.mjs'
|
|
5
|
+
import formatError from '../format-error.mjs'
|
|
6
|
+
|
|
7
|
+
const errors = new Set()
|
|
8
|
+
|
|
9
|
+
function start (event) {
|
|
10
|
+
const level = event.branch ? 'debug' : 'info'
|
|
11
|
+
log[level](`Starting '${ansi.cyan(event.name)}'...`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function stop (event) {
|
|
15
|
+
const level = event.branch ? 'debug' : 'info'
|
|
16
|
+
log[level](`Finished '${ansi.cyan(event.name)}' after ${ansi.magenta(prettyHrtime(event.duration))}`)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function error (event) {
|
|
20
|
+
const level = event.branch ? 'debug' : 'error'
|
|
21
|
+
log[level](`'${ansi.cyan(event.name)}' ${ansi.red('errored after')} ${ansi.magenta(prettyHrtime(event.duration))}`)
|
|
22
|
+
|
|
23
|
+
// Exit if we have logged this before
|
|
24
|
+
if (errors.has(event.error)) return
|
|
25
|
+
|
|
26
|
+
// If we haven't logged this before, log it and add it to the error list
|
|
27
|
+
log.error(formatError(event))
|
|
28
|
+
errors.add(event.error)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function stopListeningForGulpEvents (gulp) {
|
|
32
|
+
gulp
|
|
33
|
+
.removeListener('start', start)
|
|
34
|
+
.removeListener('stop', stop)
|
|
35
|
+
.removeListener('error', error)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Wire up logging events
|
|
39
|
+
export default function listenForGulpEvents (gulp) {
|
|
40
|
+
stopListeningForGulpEvents(gulp)
|
|
41
|
+
|
|
42
|
+
gulp
|
|
43
|
+
.on('start', start)
|
|
44
|
+
.on('stop', stop)
|
|
45
|
+
.on('error', error)
|
|
46
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import log from 'gulplog'
|
|
2
|
+
import fancyLog from 'fancy-log'
|
|
3
|
+
|
|
4
|
+
const noop = () => {}
|
|
5
|
+
|
|
6
|
+
// The sorting of the levels is
|
|
7
|
+
// significant.
|
|
8
|
+
const levels = [
|
|
9
|
+
'error', // -L: Logs error events.
|
|
10
|
+
'warn', // -LL: Logs warn and error events.
|
|
11
|
+
'info', // -LLL: Logs info, warn and error events.
|
|
12
|
+
'debug' // -LLLL: Logs all log levels.
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
function stopListeningForLevelEvents () {
|
|
16
|
+
levels
|
|
17
|
+
.forEach((level) => {
|
|
18
|
+
if (level === 'error') {
|
|
19
|
+
log.removeListener(level, noop).removeListener(level, fancyLog.error)
|
|
20
|
+
} else {
|
|
21
|
+
log.removeListener(level, fancyLog)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Wire up log levels
|
|
27
|
+
export default function listenForLevelEvents (cliProps) {
|
|
28
|
+
// Remove previous listeners to enable to call this twice.
|
|
29
|
+
stopListeningForLevelEvents()
|
|
30
|
+
|
|
31
|
+
// Silent?
|
|
32
|
+
if (cliProps.tasksList || cliProps.tasksJson || cliProps.help || cliProps.version || cliProps.silent) {
|
|
33
|
+
// Keep from crashing process when silent
|
|
34
|
+
log.on('error', noop)
|
|
35
|
+
} else {
|
|
36
|
+
// Default level is 3 (info)
|
|
37
|
+
const loglevel = cliProps.logLevel || 3
|
|
38
|
+
|
|
39
|
+
levels
|
|
40
|
+
.filter((level, i) => level && i < loglevel)
|
|
41
|
+
.forEach((level) => {
|
|
42
|
+
if (level === 'error') {
|
|
43
|
+
log.on(level, fancyLog.error)
|
|
44
|
+
} else {
|
|
45
|
+
log.on(level, fancyLog)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import log from 'gulplog'
|
|
2
|
+
import ansi from '../ansi.mjs'
|
|
3
|
+
|
|
4
|
+
const tasks = new Map()
|
|
5
|
+
|
|
6
|
+
function warn () {
|
|
7
|
+
if (tasks.size) {
|
|
8
|
+
const taskNames = Array.from(tasks.values()).join(', ')
|
|
9
|
+
|
|
10
|
+
process.exitCode = 1
|
|
11
|
+
|
|
12
|
+
log.warn(
|
|
13
|
+
ansi.red('The following tasks did not complete:')
|
|
14
|
+
)
|
|
15
|
+
log.warn(
|
|
16
|
+
ansi.cyan(taskNames)
|
|
17
|
+
)
|
|
18
|
+
log.warn(
|
|
19
|
+
ansi.red('Did you forget to signal async completion?')
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function start ({ uid, name }) {
|
|
25
|
+
tasks.set(uid, name)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function clear ({ uid }) {
|
|
29
|
+
tasks.delete(uid)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function clearAll () {
|
|
33
|
+
tasks.clear()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function stopListeningForSyncEvents (gulp) {
|
|
37
|
+
// Ensure to detach
|
|
38
|
+
process
|
|
39
|
+
.removeListener('exit', warn)
|
|
40
|
+
|
|
41
|
+
gulp
|
|
42
|
+
.removeListener('start', start)
|
|
43
|
+
.removeListener('stop', clear)
|
|
44
|
+
.removeListener('error', clear).removeListener('error', clearAll)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default function listenForSyncEvents (gulp, cliProps) {
|
|
48
|
+
stopListeningForSyncEvents(gulp)
|
|
49
|
+
|
|
50
|
+
process
|
|
51
|
+
.once('exit', warn)
|
|
52
|
+
|
|
53
|
+
// When not running in --continue mode we need to clear everything on error
|
|
54
|
+
gulp
|
|
55
|
+
.on('start', start)
|
|
56
|
+
.on('stop', clear)
|
|
57
|
+
.on('error', cliProps.continue ? clear : clearAll)
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeFile
|
|
3
|
+
} from 'node:fs/promises'
|
|
4
|
+
|
|
5
|
+
import getDuplicate from '../get-duplicate.mjs'
|
|
6
|
+
|
|
7
|
+
export default function logTasksJson (tree, cliProps) {
|
|
8
|
+
const dupe = getDuplicate(tree, cliProps)
|
|
9
|
+
const json = JSON.stringify(dupe)
|
|
10
|
+
|
|
11
|
+
// Write to a file if not `true`
|
|
12
|
+
if (cliProps.tasksJson !== true) return writeFile(cliProps.tasksJson, json, 'utf8')
|
|
13
|
+
|
|
14
|
+
// Otherwise
|
|
15
|
+
console.log(json.trim())
|
|
16
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import archy from 'archy'
|
|
2
|
+
import log from 'gulplog'
|
|
3
|
+
|
|
4
|
+
import sortBy from 'array-sort'
|
|
5
|
+
import isObject from 'isobject'
|
|
6
|
+
|
|
7
|
+
import ansi from '../ansi.mjs'
|
|
8
|
+
import getDuplicate from '../get-duplicate.mjs'
|
|
9
|
+
|
|
10
|
+
function getLineInfoCollector (lineInfo) {
|
|
11
|
+
return {
|
|
12
|
+
topTask (node) {
|
|
13
|
+
lineInfo.push({
|
|
14
|
+
name: node.label,
|
|
15
|
+
desc: node.desc,
|
|
16
|
+
type: 'top'
|
|
17
|
+
})
|
|
18
|
+
},
|
|
19
|
+
option (opt) {
|
|
20
|
+
lineInfo.push({
|
|
21
|
+
name: opt.label,
|
|
22
|
+
desc: opt.desc,
|
|
23
|
+
type: 'option'
|
|
24
|
+
})
|
|
25
|
+
},
|
|
26
|
+
childTask (node) {
|
|
27
|
+
lineInfo.push({
|
|
28
|
+
name: node.label,
|
|
29
|
+
type: 'child'
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getNodeFactory (getTask, entryObserver) {
|
|
36
|
+
return {
|
|
37
|
+
topNode (node) {
|
|
38
|
+
return {
|
|
39
|
+
label: node.label
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
taskNode (node) {
|
|
44
|
+
const task = getTask(node.label) || {}
|
|
45
|
+
|
|
46
|
+
const newNode = {
|
|
47
|
+
label: node.label,
|
|
48
|
+
desc: typeof task.description === 'string' ? task.description : '',
|
|
49
|
+
cliProps: []
|
|
50
|
+
}
|
|
51
|
+
entryObserver.topTask(newNode)
|
|
52
|
+
|
|
53
|
+
if (isObject(task.flags)) {
|
|
54
|
+
Object.keys(task.flags)
|
|
55
|
+
.sort()
|
|
56
|
+
.filter(Boolean)
|
|
57
|
+
.forEach((flag) => {
|
|
58
|
+
const opt = {
|
|
59
|
+
label: flag,
|
|
60
|
+
desc: typeof task.flags[flag] === 'string' ? task.flags[flag] : ''
|
|
61
|
+
}
|
|
62
|
+
entryObserver.option(opt)
|
|
63
|
+
newNode.cliProps.push(opt)
|
|
64
|
+
newNode.label += '\n' + opt.label // The way of archy for options.
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return newNode
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
childNode (node) {
|
|
72
|
+
const newChild = {
|
|
73
|
+
label: node.label
|
|
74
|
+
}
|
|
75
|
+
entryObserver.childTask(newChild)
|
|
76
|
+
newChild.label = '' // Because don't use child tasks to calc indents.
|
|
77
|
+
|
|
78
|
+
return newChild
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getSpacerForLineIndents (tree, lineInfo) {
|
|
84
|
+
let maxSize = 0
|
|
85
|
+
const sizes = []
|
|
86
|
+
|
|
87
|
+
archy(tree)
|
|
88
|
+
.split('\n')
|
|
89
|
+
.slice(1, -1)
|
|
90
|
+
.forEach((line, index) => {
|
|
91
|
+
const info = lineInfo[index]
|
|
92
|
+
if (info.type === 'top' || info.type === 'option') {
|
|
93
|
+
maxSize = Math.max(maxSize, line.length)
|
|
94
|
+
sizes.push(line.length)
|
|
95
|
+
} else {
|
|
96
|
+
sizes.push(0)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
maxSize += 3
|
|
101
|
+
|
|
102
|
+
return function getSpacerFor (index) {
|
|
103
|
+
return Array(maxSize - sizes[index]).join(' ')
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getLinesContainingOnlyBranches (tree) {
|
|
108
|
+
tree.nodes
|
|
109
|
+
.forEach((node) => {
|
|
110
|
+
node.label = ''
|
|
111
|
+
node.cliProps
|
|
112
|
+
.forEach(() => {
|
|
113
|
+
node.label += '\n'
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return archy(tree)
|
|
118
|
+
.split('\n')
|
|
119
|
+
.slice(1, -1)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function logLines (lines, spacer, lineInfo) {
|
|
123
|
+
lines
|
|
124
|
+
.forEach((branch, index) => {
|
|
125
|
+
const info = lineInfo[index]
|
|
126
|
+
|
|
127
|
+
let line = ansi.white(branch)
|
|
128
|
+
|
|
129
|
+
if (info.type === 'top') {
|
|
130
|
+
line += ansi.cyan(info.name)
|
|
131
|
+
if (info.desc.length > 0) {
|
|
132
|
+
line += spacer(index) + ansi.white(info.desc)
|
|
133
|
+
}
|
|
134
|
+
} else if (info.type === 'option') {
|
|
135
|
+
line += ansi.magenta(info.name)
|
|
136
|
+
if (info.desc.length > 0) {
|
|
137
|
+
line += spacer(index) + ansi.white('…' + info.desc)
|
|
138
|
+
}
|
|
139
|
+
} else { // If (info.type === 'child') {
|
|
140
|
+
line += ansi.white(info.name)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
log.info(line)
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Wire up log tasks
|
|
148
|
+
export default function logTasks (tree, cliProps, getTask) {
|
|
149
|
+
if (cliProps.sortTasks) {
|
|
150
|
+
tree.nodes = sortBy(tree.nodes, 'label')
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const lineInfo = []
|
|
154
|
+
const entryObserver = getLineInfoCollector(lineInfo)
|
|
155
|
+
const nodeFactory = getNodeFactory(getTask, entryObserver)
|
|
156
|
+
|
|
157
|
+
const dupe = getDuplicate(tree, cliProps, nodeFactory)
|
|
158
|
+
const spacer = getSpacerForLineIndents(dupe, lineInfo)
|
|
159
|
+
const lines = getLinesContainingOnlyBranches(dupe)
|
|
160
|
+
|
|
161
|
+
log.info(dupe.label)
|
|
162
|
+
logLines(lines, spacer, lineInfo)
|
|
163
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import tildify from './tildify.mjs'
|
|
2
|
+
|
|
3
|
+
import logTasksJson from './log/tasks-json.mjs'
|
|
4
|
+
|
|
5
|
+
export default function runGulpTasksJsonTree (gulp, cliProps, envProps, configProps) {
|
|
6
|
+
const tree = gulp.tree({ deep: true })
|
|
7
|
+
if (configProps.description && typeof configProps.description === 'string') {
|
|
8
|
+
tree.label = configProps.description
|
|
9
|
+
} else {
|
|
10
|
+
tree.label = `Tasks for ${tildify(envProps.configPath)}`
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return logTasksJson(tree, cliProps)
|
|
14
|
+
}
|