111 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// @ts-check
 | 
						|
const { warn } = require('./logger')
 | 
						|
 | 
						|
/** @typedef {{after?: string|Array<string>}} Apply */
 | 
						|
/** @typedef {{id: string, apply: Apply}} Plugin */
 | 
						|
/** @typedef {{after: Set<string>}} OrderParams */
 | 
						|
 | 
						|
/** @type {Map<string, OrderParams>} */
 | 
						|
const orderParamsCache = new Map()
 | 
						|
 | 
						|
/**
 | 
						|
 *
 | 
						|
 * @param {Plugin} plugin
 | 
						|
 * @returns {OrderParams}
 | 
						|
 */
 | 
						|
function getOrderParams (plugin) {
 | 
						|
  if (!process.env.VUE_CLI_TEST && orderParamsCache.has(plugin.id)) {
 | 
						|
    return orderParamsCache.get(plugin.id)
 | 
						|
  }
 | 
						|
  const apply = plugin.apply
 | 
						|
 | 
						|
  let after = new Set()
 | 
						|
  if (typeof apply.after === 'string') {
 | 
						|
    after = new Set([apply.after])
 | 
						|
  } else if (Array.isArray(apply.after)) {
 | 
						|
    after = new Set(apply.after)
 | 
						|
  }
 | 
						|
  if (!process.env.VUE_CLI_TEST) {
 | 
						|
    orderParamsCache.set(plugin.id, { after })
 | 
						|
  }
 | 
						|
 | 
						|
  return { after }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * See leetcode 210
 | 
						|
 * @param {Array<Plugin>} plugins
 | 
						|
 * @returns {Array<Plugin>}
 | 
						|
 */
 | 
						|
function topologicalSorting (plugins) {
 | 
						|
  /** @type {Map<string, Plugin>} */
 | 
						|
  const pluginsMap = new Map(plugins.map(p => [p.id, p]))
 | 
						|
 | 
						|
  /** @type {Map<Plugin, number>} */
 | 
						|
  const indegrees = new Map()
 | 
						|
 | 
						|
  /** @type {Map<Plugin, Array<Plugin>>} */
 | 
						|
  const graph = new Map()
 | 
						|
 | 
						|
  plugins.forEach(p => {
 | 
						|
    const after = getOrderParams(p).after
 | 
						|
    indegrees.set(p, after.size)
 | 
						|
    if (after.size === 0) return
 | 
						|
    for (const id of after) {
 | 
						|
      const prerequisite = pluginsMap.get(id)
 | 
						|
      // remove invalid data
 | 
						|
      if (!prerequisite) {
 | 
						|
        indegrees.set(p, indegrees.get(p) - 1)
 | 
						|
        continue
 | 
						|
      }
 | 
						|
 | 
						|
      if (!graph.has(prerequisite)) {
 | 
						|
        graph.set(prerequisite, [])
 | 
						|
      }
 | 
						|
      graph.get(prerequisite).push(p)
 | 
						|
    }
 | 
						|
  })
 | 
						|
 | 
						|
  const res = []
 | 
						|
  const queue = []
 | 
						|
  indegrees.forEach((d, p) => {
 | 
						|
    if (d === 0) queue.push(p)
 | 
						|
  })
 | 
						|
  while (queue.length) {
 | 
						|
    const cur = queue.shift()
 | 
						|
    res.push(cur)
 | 
						|
    const neighbors = graph.get(cur)
 | 
						|
    if (!neighbors) continue
 | 
						|
 | 
						|
    neighbors.forEach(n => {
 | 
						|
      const degree = indegrees.get(n) - 1
 | 
						|
      indegrees.set(n, degree)
 | 
						|
      if (degree === 0) {
 | 
						|
        queue.push(n)
 | 
						|
      }
 | 
						|
    })
 | 
						|
  }
 | 
						|
  const valid = res.length === plugins.length
 | 
						|
  if (!valid) {
 | 
						|
    warn(`No proper plugin execution order found.`)
 | 
						|
    return plugins
 | 
						|
  }
 | 
						|
  return res
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Arrange plugins by 'after' property.
 | 
						|
 * @param {Array<Plugin>} plugins
 | 
						|
 * @returns {Array<Plugin>}
 | 
						|
 */
 | 
						|
function sortPlugins (plugins) {
 | 
						|
  if (plugins.length < 2) return plugins
 | 
						|
 | 
						|
  return topologicalSorting(plugins)
 | 
						|
}
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  topologicalSorting,
 | 
						|
  sortPlugins
 | 
						|
}
 |