123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- /**
- * @module match-tasks
- * @author Toru Nagashima
- * @copyright 2015 Toru Nagashima. All rights reserved.
- * See LICENSE file in root directory for full license.
- */
- 'use strict'
- // ------------------------------------------------------------------------------
- // Requirements
- // ------------------------------------------------------------------------------
- const { minimatch } = require('minimatch')
- const Minimatch = minimatch.Minimatch
- // ------------------------------------------------------------------------------
- // Helpers
- // ------------------------------------------------------------------------------
- const COLON_OR_SLASH = /[:/]/g
- const CONVERT_MAP = { ':': '/', '/': ':' }
- /**
- * Swaps ":" and "/", in order to use ":" as the separator in minimatch.
- *
- * @param {string} s - A text to swap.
- * @returns {string} The text which was swapped.
- */
- function swapColonAndSlash (s) {
- return s.replace(COLON_OR_SLASH, (matched) => CONVERT_MAP[matched])
- }
- /**
- * Creates a filter from user-specified pattern text.
- *
- * The task name is the part until the first space.
- * The rest part is the arguments for this task.
- *
- * @param {string} pattern - A pattern to create filter.
- * @returns {{match: function, task: string, args: string}} The filter object of the pattern.
- */
- function createFilter (pattern) {
- const trimmed = pattern.trim()
- const spacePos = trimmed.indexOf(' ')
- const task = spacePos < 0 ? trimmed : trimmed.slice(0, spacePos)
- const args = spacePos < 0 ? '' : trimmed.slice(spacePos)
- const matcher = new Minimatch(swapColonAndSlash(task), { nonegate: true })
- const match = matcher.match.bind(matcher)
- return { match, task, args }
- }
- /**
- * The set to remove overlapped task.
- */
- class TaskSet {
- /**
- * Creates a instance.
- */
- constructor () {
- this.result = []
- this.sourceMap = Object.create(null)
- }
- /**
- * Adds a command (a pattern) into this set if it's not overlapped.
- * "Overlapped" is meaning that the command was added from a different source.
- *
- * @param {string} command - A pattern text to add.
- * @param {string} source - A task name to check.
- * @returns {void}
- */
- add (command, source) {
- const sourceList = this.sourceMap[command] || (this.sourceMap[command] = [])
- if (sourceList.length === 0 || sourceList.indexOf(source) !== -1) {
- this.result.push(command)
- }
- sourceList.push(source)
- }
- }
- // ------------------------------------------------------------------------------
- // Public Interface
- // ------------------------------------------------------------------------------
- /**
- * Enumerates tasks which matches with given patterns.
- *
- * @param {string[]} taskList - A list of actual task names.
- * @param {string[]} patterns - Pattern texts to match.
- * @returns {string[]} Tasks which matches with the patterns.
- * @private
- */
- module.exports = function matchTasks (taskList, patterns) {
- const filters = patterns.map(createFilter)
- const candidates = taskList.map(swapColonAndSlash)
- const taskSet = new TaskSet()
- const unknownSet = Object.create(null)
- // Take tasks while keep the order of patterns.
- for (const filter of filters) {
- let found = false
- for (const candidate of candidates) {
- if (filter.match(candidate)) {
- found = true
- taskSet.add(
- swapColonAndSlash(candidate) + filter.args,
- filter.task
- )
- }
- }
- // Built-in tasks should be allowed.
- if (!found && (filter.task === 'restart' || filter.task === 'env')) {
- taskSet.add(filter.task + filter.args, filter.task)
- found = true
- }
- if (!found) {
- unknownSet[filter.task] = true
- }
- }
- const unknownTasks = Object.keys(unknownSet)
- if (unknownTasks.length > 0) {
- throw new Error(`Task not found: "${unknownTasks.join('", ')}"`)
- }
- return taskSet.result
- }
|