code: a abbr audio b bdi bdo canvas cite code data del dfn em i iframe ins kbd label map mark noscript object output picture q ruby s samp small span strong sub sup svg time u var video

license: mit


code: abstract arguments await boolean break byte case catch char class const continue debugger default delete do double else enum eval export extends false final finally float for function goto if implements import in instanceof int interface let long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var void volatile while with yield


code: unidentified alt alt-graph caps-lock control fn fn-lock meta num-lock scroll-lock shift symbol symbol-lock hyper super enter tab arrow-down arrow-left arrow-right arrow-up end home page-down page-up backspace clear copy cr-sel cut delete erase-eof ex-sel insert paste redo undo accept again attn cancel context-menu escape execute find help pause select zoom-in zoom-out brightness-down brightness-up eject log-off power print-screen hibernate standby wake-up all-candidates alphanumeric code-input compose convert dead final-mode group-first group-last group-next group-previous mode-change next-candidate non-convert previous-candidate process single-candidate hangul-mode hanja-mode junja-mode eisu hankaku hiragana hiragana-katakana kana-mode kanji-mode katakana romaji zenkaku zenkaku-hankaku f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 soft1 soft2 soft3 soft4 channel-down channel-up close mail-forward mail-reply mail-send media-close media-fast-forward media-pause media-play-pause media-record media-rewind media-stop media-track-next media-track-previous new open print save spell-check key11 key12 audio-balance-left audio-balance-right audio-bass-boost-down audio-bass-boost-toggle audio-bass-boost-up audio-fader-front audio-fader-rear audio-surround-mode-next audio-treble-down audio-treble-up audio-volume-down audio-volume-up audio-volume-mute microphone-toggle microphone-volume-down microphone-volume-up microphone-volume-mute speech-correction-list speech-input-toggle launch-application1 launch-application2 launch-calendar launch-contacts launch-mail launch-media-player launch-music-player launch-phone launch-screen-saver launch-spreadsheet launch-web-browser launch-web-cam launch-word-processor browser-back browser-favorites browser-forward browser-home browser-refresh browser-search browser-stop app-switch call camera camera-focus end-call go-back go-home headset-hook last-number-redial notification manner-mode voice-dial t-v t-v3-d-mode t-v-antenna-cable t-v-audio-description t-v-audio-description-mix-down t-v-audio-description-mix-up t-v-contents-menu t-v-data-service t-v-input t-v-input-component1 t-v-input-component2 t-v-input-composite1 t-v-input-composite2 t-v-input-h-d-m-i1 t-v-input-h-d-m-i2 t-v-input-h-d-m-i3 t-v-input-h-d-m-i4 t-v-input-v-g-a1 t-v-media-context t-v-network t-v-number-entry t-v-power t-v-radio-service t-v-satellite t-v-satellite-b-s t-v-satellite-c-s t-v-satellite-toggle t-v-terrestrial-analog t-v-terrestrial-digital t-v-timer a-v-r-input a-v-r-power color-f0-red color-f1-green color-f2-yellow color-f3-blue color-f4-grey color-f5-brown closed-caption-toggle dimmer display-swap d-v-r exit favorite-clear0 favorite-clear1 favorite-clear2 favorite-clear3 favorite-recall0 favorite-recall1 favorite-recall2 favorite-recall3 favorite-store0 favorite-store1 favorite-store2 favorite-store3 guide guide-next-day guide-previous-day info instant-replay link list-program live-content lock media-apps media-last media-skip-backward media-skip-forward media-step-backward media-step-forward media-top-menu navigate-in navigate-next navigate-out navigate-previous next-favorite-channel next-user-profile on-demand pairing pin-p-down pin-p-move pin-p-toggle pin-p-up play-speed-down play-speed-reset play-speed-up random-toggle rc-low-battery record-speed-next rf-bypass scan-channels-toggle screen-mode-next settings split-screen-toggle s-t-b-input s-t-b-power subtitle teletext video-mode-next wink zoom-toggle audio-volume-down audio-volume-up audio-volume-mute browser-back browser-forward channel-down channel-up context-menu eject end enter home media-fast-forward media-play media-play-pause media-record media-rewind media-stop media-next-track media-pause media-previous-track power unidentified


code: math maction annotation annotation-xml menclose merror mfenced mfrac mi mmultiscripts mn mo mover mpadded mphantom mprescripts mroot mrow ms semantics mspace msqrt mstyle msub msup msubsup mtable mtd mtext mtr munder munderover


code:
/**
 * @author Yosuke Ota
 * @copyright 2021 Yosuke Ota. All rights reserved.
 * See LICENSE file in root directory for full license.
 */
'use strict'

const utils = require('./index')
const eslintUtils = require('@eslint-community/eslint-utils')

/**
 * @typedef {import('./style-variables').StyleVariablesContext} StyleVariablesContext
 */
/**
 * @typedef {object} IHasPropertyOption
 * @property {boolean} [unknownCallAsAny]
 */
/**
 * @typedef {object} NestPropertyNodeForExpression
 * @property {'expression'} type
 * @property {MemberExpression} node
 *
 * @typedef {object} NestPropertyNodeForPattern
 * @property {'pattern'} type
 * @property {MemberExpression | Identifier | ObjectPattern | ArrayPattern} node
 *
 * @typedef {NestPropertyNodeForExpression | NestPropertyNodeForPattern} NestPropertyNode
 */
/**
 * @typedef {object} IPropertyReferences
 * @property { (name: string, option?: IHasPropertyOption) => boolean } hasProperty
 * @property { () => Map<string, {nodes:ASTNode[]}> } allProperties Get all properties.
 * @property { (name: string) => IPropertyReferences } getNest Get the nesting property references.
 * @property { (name: string) => Iterable<NestPropertyNode> } getNestNodes Get the nesting property nodes.
 */

/** @type {IPropertyReferences} */
const ANY = {
  hasProperty: () => true,
  allProperties: () => new Map(),
  getNest: () => ANY,
  getNestNodes: () => []
}

/** @type {IPropertyReferences} */
const NEVER = {
  hasProperty: () => false,
  allProperties: () => new Map(),
  getNest: () => NEVER,
  getNestNodes: () => []
}

/**
 * @param {RuleContext} context
 * @param {Identifier} id
 * @returns {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration | null}
 */
function findFunction(context, id) {
  const calleeVariable = utils.findVariableByIdentifier(context, id)
  if (!calleeVariable) {
    return null
  }
  if (calleeVariable.defs.length === 1) {
    const def = calleeVariable.defs[0]
    if (def.node.type === 'FunctionDeclaration') {
      return def.node
    }
    if (
      def.type === 'Variable' &&
      def.parent.kind === 'const' &&
      def.node.init
    ) {
      if (
        def.node.init.type === 'FunctionExpression' ||
        def.node.init.type === 'ArrowFunctionExpression'
      ) {
        return def.node.init
      }
      if (def.node.init.type === 'Identifier') {
        return findFunction(context, def.node.init)
      }
    }
  }
  return null
}

module.exports = {
  definePropertyReferenceExtractor,
  mergePropertyReferences
}

/**
 * @param {RuleContext} context The rule context.
 */
function definePropertyReferenceExtractor(
  context,
  { unknownMemberAsUnreferenced = false, returnAsUnreferenced = false } = {}
) {
  /** @type {Map<Expression, IPropertyReferences>} */
  const cacheForExpression = new Map()
  /** @type {Map<Pattern, IPropertyReferences>} */
  const cacheForPattern = new Map()
  /** @type {Map<FunctionExpression | ArrowFunctionExpression | FunctionDeclaration, Map<number, IPropertyReferences>>} */
  const cacheForFunction = new Map()
  /** @type {{ toRefNodes: Set<ESNode>, toRefsNodes: Set<ESNode>} | null} */
  let toRefSet = null

  let isFunctionalTemplate = false
  const templateBody = context.getSourceCode().ast.templateBody
  if (templateBody) {
    isFunctionalTemplate = utils.hasAttribute(templateBody, 'functional')
  }

  function getToRefSet() {
    if (toRefSet) {
      return toRefSet
    }
    const tracker = new eslintUtils.ReferenceTracker(
      context.getSourceCode().scopeManager.scopes[0]
    )
    const toRefNodes = new Set()
    for (const { node } of utils.iterateReferencesTraceMap(tracker, {
      [eslintUtils.ReferenceTracker.ESM]: true,
      toRef: {
        [eslintUtils.ReferenceTracker.CALL]: true
      }
    })) {
      toRefNodes.add(node)
    }
    const toRefsNodes = new Set()
    for (const { node } of utils.iterateReferencesTraceMap(tracker, {
      [eslintUtils.ReferenceTracker.ESM]: true,
      toRefs: {
        [eslintUtils.ReferenceTracker.CALL]: true
      }
    })) {
      toRefsNodes.add(node)
    }

    return (toRefSet = { toRefNodes, toRefsNodes })
  }

  /**
   * Collects the property references for member expr.
   * @implements {IPropertyReferences}
   */
  class PropertyReferencesForMember {
    /**
     *
     * @param {MemberExpression} node
     * @param {string} name
     * @param {boolean} withInTemplate
     */
    constructor(node, name, withInTemplate) {
      this.node = node
      this.name = name
      this.withInTemplate = withInTemplate
    }

    /**
     * @param {string} name
     */
    hasProperty(name) {
      return name === this.name
    }

    allProperties() {
      return new Map([[this.name, { nodes: [this.node.property] }]])
    }

    /**
     * @param {string} name
     * @returns {IPropertyReferences}
     */
    getNest(name) {
      return name === this.name
        ? extractFromExpression(this.node, this.withInTemplate)
        : NEVER
    }

    /**
     * @param {string} name
     * @returns {Iterable<NestPropertyNodeForExpression>}
     */
    *getNestNodes(name) {
      if (name === this.name) {
        yield {
          type: 'expression',
          node: this.node
        }
      }
    }
  }
  /**
   * Collects the property references for object.
   * @implements {IPropertyReferences}
   */
  class PropertyReferencesForObject {
    constructor() {
      /** @type {Record<string, AssignmentProperty[]>} */
      this.properties = Object.create(null)
    }

    /**
     * @param {string} name
     */
    hasProperty(name) {
      return Boolean(this.properties[name])
    }

    allProperties() {
      const result = new Map()
      for (const [name, nodes] of Object.entries(this.properties)) {
        result.set(name, { nodes: nodes.map((node) => node.key) })
      }
      return result
    }

    /**
     * @param {string} name
     * @returns {IPropertyReferences}
     */
    getNest(name) {
      const properties = this.properties[name]
      return properties
        ? mergePropertyReferences(
            properties.map((property) => getNestFromPattern(property.value))
          )
        : NEVER
    }

    /**
     * @param {string} name
     * @returns {Iterable<NestPropertyNodeForPattern>}
     */
    *getNestNodes(name) {
      const properties = this.properties[name]
      if (!properties) {
        return
      }
      const values = properties.map((property) => property.value)
      let node
      while ((node = values.shift())) {
        if (
          node.type === 'Identifier' ||
          node.type === 'MemberExpression' ||
          node.type === 'ObjectPattern' ||
          node.type === 'ArrayPattern'
        ) {
          yield {
            type: 'pattern',
            node
          }
        } else if (node.type === 'AssignmentPattern') {
          values.unshift(node.left)
        }
      }
      return properties ? properties.map((p) => p.value) : []
    }
  }

  /**
   * @param {Pattern} pattern
   * @returns {IPropertyReferences}
   */
  function getNestFromPattern(pattern) {
    if (pattern.type === 'ObjectPattern') {
      return extractFromObjectPattern(pattern)
    }
    if (pattern.type === 'Identifier') {
      return extractFromIdentifier(pattern)
    } else if (pattern.type === 'AssignmentPattern') {
      return getNestFromPattern(pattern.left)
    }
    return ANY
  }

  /**
   * Extract the property references from Expression.
   * @param {Identifier | MemberExpression | ChainExpression | ThisExpression | CallExpression} node
   * @param {boolean} withInTemplate
   * @returns {IPropertyReferences}
   */
  function extractFromExpression(node, withInTemplate) {
    const ref = cacheForExpression.get(node)
    if (ref) {
      return ref
    }
    cacheForExpression.set(node, ANY)
    const result = extractWithoutCache()
    cacheForExpression.set(node, result)
    return result

    function extractWithoutCache() {
      const parent = node.parent
      switch (parent.type) {
        case 'AssignmentExpression': {
          // `({foo} = arg)`
          return !withInTemplate &&
            parent.right === node &&
            parent.operator === '='
            ? extractFromPattern(parent.left)
            : NEVER
        }
        case 'VariableDeclarator': {
          // `const {foo} = arg`
          // `const foo = arg`
          return !withInTemplate && parent.init === node
            ? extractFromPattern(parent.id)
            : NEVER
        }
        case 'MemberExpression': {
          if (parent.object === node) {
            // `arg.foo`
            const name = utils.getStaticPropertyName(parent)

            if (
              name === '$props' &&
              parent.parent.type === 'MemberExpression'
            ) {
              // `$props.arg`
              const propName = utils.getStaticPropertyName(parent.parent)

              if (!propName) return unknownMemberAsUnreferenced ? NEVER : ANY

              return new PropertyReferencesForMember(
                parent.parent,
                propName,
                withInTemplate
              )
            } else if (name) {
              return new PropertyReferencesForMember(
                parent,
                name,
                withInTemplate
              )
            } else {
              return unknownMemberAsUnreferenced ? NEVER : ANY
            }
          }
          return NEVER
        }
        case 'CallExpression': {
          const argIndex = parent.arguments.indexOf(node)
          // `foo(arg)`
          return !withInTemplate && argIndex > -1
            ? extractFromCall(parent, argIndex)
            : NEVER
        }
        case 'ChainExpression': {
          return extractFromExpression(parent, withInTemplate)
        }
        case 'ArrowFunctionExpression':
        case 'VExpressionContainer':
        case 'Property':
        case 'ArrayExpression': {
          return maybeExternalUsed(parent) ? ANY : NEVER
        }
        case 'ReturnStatement': {
          if (returnAsUnreferenced) {
            return NEVER
          } else {
            return maybeExternalUsed(parent) ? ANY : NEVER
          }
        }
      }
      return NEVER
    }

    /**
     * @param {ASTNode} parentTarget
     * @returns {boolean}
     */
    function maybeExternalUsed(parentTarget) {
      if (
        parentTarget.type === 'ReturnStatement' ||
        parentTarget.type === 'VExpressionContainer'
      ) {
        return true
      }
      if (parentTarget.type === 'ArrayExpression') {
        return maybeExternalUsed(parentTarget.parent)
      }
      if (parentTarget.type === 'Property') {
        return maybeExternalUsed(parentTarget.parent.parent)
      }
      if (parentTarget.type === 'ArrowFunctionExpression') {
        return parentTarget.body === node
      }
      return false
    }
  }

  /**
   * Extract the property references from one parameter of the function.
   * @param {Pattern} node
   * @returns {IPropertyReferences}
   */
  function extractFromPattern(node) {
    const ref = cacheForPattern.get(node)
    if (ref) {
      return ref
    }
    cacheForPattern.set(node, ANY)
    const result = extractWithoutCache()
    cacheForPattern.set(node, result)
    return result

    function extractWithoutCache() {
      while (node.type === 'AssignmentPattern') {
        node = node.left
      }
      if (node.type === 'RestElement' || node.type === 'ArrayPattern') {
        // cannot check
        return NEVER
      }
      if (node.type === 'ObjectPattern') {
        return extractFromObjectPattern(node)
      }
      if (node.type === 'Identifier') {
        return extractFromIdentifier(node)
      }
      return NEVER
    }
  }

  /**
   * Extract the property references from ObjectPattern.
   * @param {ObjectPattern} node
   * @returns {IPropertyReferences}
   */
  function extractFromObjectPattern(node) {
    const refs = new PropertyReferencesForObject()
    for (const prop of node.properties) {
      if (prop.type === 'Property') {
        const name = utils.getStaticPropertyName(prop)
        if (name) {
          const list = refs.properties[name] || (refs.properties[name] = [])
          list.push(prop)
        } else {
          // If cannot trace name, everything is used!
          return ANY
        }
      } else {
        // If use RestElement, everything is used!
        return ANY
      }
    }
    return refs
  }

  /**
   * Extract the property references from id.
   * @param {Identifier} node
   * @returns {IPropertyReferences}
   */
  function extractFromIdentifier(node) {
    const variable = utils.findVariableByIdentifier(context, node)
    if (!variable) {
      return NEVER
    }
    return mergePropertyReferences(
      variable.references.map((reference) => {
        const id = reference.identifier
        return extractFromExpression(id, false)
      })
    )
  }

  /**
   * Extract the property references from call.
   * @param {CallExpression} node
   * @param {number} argIndex
   * @returns {IPropertyReferences}
   */
  function extractFromCall(node, argIndex) {
    if (node.callee.type !== 'Identifier') {
      return {
        hasProperty(_name, options) {
          return Boolean(options && options.unknownCallAsAny)
        },
        allProperties: () => new Map(),
        getNest: () => ANY,
        getNestNodes: () => []
      }
    }

    const fnNode = findFunction(context, node.callee)
    if (!fnNode) {
      if (argIndex === 0) {
        if (getToRefSet().toRefNodes.has(node)) {
          return extractFromToRef(node)
        } else if (getToRefSet().toRefsNodes.has(node)) {
          return extractFromToRefs(node)
        }
      }
      return {
        hasProperty(_name, options) {
          return Boolean(options && options.unknownCallAsAny)
        },
        allProperties: () => new Map(),
        getNest: () => ANY,
        getNestNodes: () => []
      }
    }

    return extractFromFunctionParam(fnNode, argIndex)
  }

  /**
   * Extract the property references from function param.
   * @param {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration} node
   * @param {number} argIndex
   * @returns {IPropertyReferences}
   */
  function extractFromFunctionParam(node, argIndex) {
    let cacheForIndexes = cacheForFunction.get(node)
    if (!cacheForIndexes) {
      cacheForIndexes = new Map()
      cacheForFunction.set(node, cacheForIndexes)
    }
    const ref = cacheForIndexes.get(argIndex)
    if (ref) {
      return ref
    }
    cacheForIndexes.set(argIndex, NEVER)
    const arg = node.params[argIndex]
    if (!arg) {
      return NEVER
    }
    const result = extractFromPattern(arg)
    cacheForIndexes.set(argIndex, result)
    return result
  }

  /**
   * Extract the property references from path.
   * @param {string} pathString
   * @param {Identifier | Literal | TemplateLiteral} node
   * @returns {IPropertyReferences}
   */
  function extractFromPath(pathString, node) {
    return extractFromSegments(pathString.split('.'))

    /**
     * @param {string[]} segments
     * @returns {IPropertyReferences}
     */
    function extractFromSegments(segments) {
      if (segments.length === 0) {
        return ANY
      }
      const segmentName = segments[0]
      return {
        hasProperty: (name) => name === segmentName,
        allProperties: () => new Map([[segmentName, { nodes: [node] }]]),
        getNest: (name) =>
          name === segmentName ? extractFromSegments(segments.slice(1)) : NEVER,
        getNestNodes: () => []
      }
    }
  }

  /**
   * Extract the property references from name literal.
   * @param {Expression} node
   * @returns {IPropertyReferences}
   */
  function extractFromNameLiteral(node) {
    const referenceName =
      node.type === 'Literal' || node.type === 'TemplateLiteral'
        ? utils.getStringLiteralValue(node)
        : null
    return referenceName
      ? {
          hasProperty: (name) => name === referenceName,
          allProperties: () => new Map([[referenceName, { nodes: [node] }]]),
          getNest: (name) => (name === referenceName ? ANY : NEVER),
          getNestNodes: () => []
        }
      : NEVER
  }

  /**
   * Extract the property references from name.
   * @param {string} referenceName
   * @param {Expression|SpreadElement} nameNode
   * @param { () => IPropertyReferences } [getNest]
   * @returns {IPropertyReferences}
   */
  function extractFromName(referenceName, nameNode, getNest) {
    return {
      hasProperty: (name) => name === referenceName,
      allProperties: () => new Map([[referenceName, { nodes: [nameNode] }]]),
      getNest: (name) =>
        name === referenceName ? (getNest ? getNest() : ANY) : NEVER,
      getNestNodes: () => []
    }
  }

  /**
   * Extract the property references from toRef call.
   * @param {CallExpression} node
   * @returns {IPropertyReferences}
   */
  function extractFromToRef(node) {
    const nameNode = node.arguments[1]
    const refName =
      nameNode &&
      (nameNode.type === 'Literal' || nameNode.type === 'TemplateLiteral')
        ? utils.getStringLiteralValue(nameNode)
        : null
    if (!refName) {
      // unknown name
      return ANY
    }
    return extractFromName(refName, nameNode, () =>
      extractFromExpression(node, false).getNest('value')
    )
  }

  /**
   * Extract the property references from toRefs call.
   * @param {CallExpression} node
   * @returns {IPropertyReferences}
   */
  function extractFromToRefs(node) {
    const base = extractFromExpression(node, false)
    return {
      hasProperty: (name, option) => base.hasProperty(name, option),
      allProperties: () => base.allProperties(),
      getNest: (name) => base.getNest(name).getNest('value'),
      getNestNodes: (name) => base.getNest(name).getNestNodes('value')
    }
  }

  /**
   * Extract the property references from VExpressionContainer.
   * @param {VExpressionContainer} node
   * @param {object} [options]
   * @param {boolean} [options.ignoreGlobals]
   * @returns {IPropertyReferences}
   */
  function extractFromVExpressionContainer(node, options) {
    const ignoreGlobals = options && options.ignoreGlobals

    /** @type { (name:string)=>boolean } */
    let ignoreRef = () => false
    if (ignoreGlobals) {
      const globalScope =
        context.getSourceCode().scopeManager.globalScope ||
        context.getSourceCode().scopeManager.scopes[0]

      ignoreRef = (name) => globalScope.set.has(name)
    }
    /** @type {IPropertyReferences[]} */
    const references = []
    for (const id of node.references
      .filter((ref) => ref.variable == null)
      .map((ref) => ref.id)) {
      if (ignoreRef(id.name)) {
        continue
      }
      if (isFunctionalTemplate) {
        if (id.name === 'props') {
          references.push(extractFromExpression(id, true))
        }
      } else {
        const referenceId =
          id.name === '$props' &&
          id.parent.type === 'MemberExpression' &&
          id.parent.property.type === 'Identifier'
            ? id.parent.property
            : id

        references.push(
          extractFromName(referenceId.name, referenceId, () =>
            extractFromExpression(referenceId, true)
          )
        )
      }
    }
    return mergePropertyReferences(references)
  }
  /**
   * Extract the property references from StyleVariablesContext.
   * @param {StyleVariablesContext} ctx
   * @returns {IPropertyReferences}
   */
  function extractFromStyleVariablesContext(ctx) {
    const references = []
    for (const { id } of ctx.references) {
      references.push(
        extractFromName(id.name, id, () => extractFromExpression(id, true))
      )
    }
    return mergePropertyReferences(references)
  }

  return {
    extractFromExpression,
    extractFromPattern,
    extractFromFunctionParam,
    extractFromPath,
    extractFromName,
    extractFromNameLiteral,
    extractFromVExpressionContainer,
    extractFromStyleVariablesContext
  }
}

/**
 * @param {IPropertyReferences[]} references
 * @returns {IPropertyReferences}
 */
function mergePropertyReferences(references) {
  if (references.length === 0) {
    return NEVER
  }
  if (references.length === 1) {
    return references[0]
  }
  return new PropertyReferencesForMerge(references)
}

/**
 * Collects the property references for merge.
 * @implements {IPropertyReferences}
 */
class PropertyReferencesForMerge {
  /**
   * @param {IPropertyReferences[]} references
   */
  constructor(references) {
    this.references = references
  }

  /**
   * @param {string} name
   * @param {IHasPropertyOption} [option]
   */
  hasProperty(name, option) {
    return this.references.some((ref) => ref.hasProperty(name, option))
  }

  allProperties() {
    const result = new Map()
    for (const reference of this.references) {
      for (const [name, { nodes }] of reference.allProperties()) {
        const r = result.get(name)
        if (r) {
          r.nodes = [...new Set([...r.nodes, ...nodes])]
        } else {
          result.set(name, { nodes: [...nodes] })
        }
      }
    }
    return result
  }

  /**
   * @param {string} name
   * @returns {IPropertyReferences}
   */
  getNest(name) {
    /** @type {IPropertyReferences[]} */
    const nest = []
    for (const ref of this.references) {
      if (ref.hasProperty(name)) {
        nest.push(ref.getNest(name))
      }
    }
    return mergePropertyReferences(nest)
  }

  /**
   * @param {string} name
   * @returns {Iterable<NestPropertyNode>}
   */
  *getNestNodes(name) {
    for (const ref of this.references) {
      if (ref.hasProperty(name)) {
        yield* ref.getNestNodes(name)
      }
    }
  }
}


code:
/**
 * @author Yosuke Ota
 * @copyright 2022 Yosuke Ota. All rights reserved.
 * See LICENSE file in root directory for full license.
 */
'use strict'

const utils = require('./index')
const eslintUtils = require('@eslint-community/eslint-utils')
const { definePropertyReferenceExtractor } = require('./property-references')
const { ReferenceTracker } = eslintUtils

/**
 * @typedef {object} RefObjectReferenceForExpression
 * @property {'expression'} type
 * @property {MemberExpression | CallExpression} node
 * @property {string} method
 * @property {CallExpression} define
 * @property {(CallExpression | Identifier | MemberExpression)[]} defineChain Holds the initialization path for assignment of ref objects.
 *
 * @typedef {object} RefObjectReferenceForPattern
 * @property {'pattern'} type
 * @property {ObjectPattern} node
 * @property {string} method
 * @property {CallExpression} define
 * @property {(CallExpression | Identifier | MemberExpression)[]} defineChain Holds the initialization path for assignment of ref objects.
 *
 * @typedef {object} RefObjectReferenceForIdentifier
 * @property {'expression' | 'pattern'} type
 * @property {Identifier} node
 * @property {VariableDeclarator | null} variableDeclarator
 * @property {VariableDeclaration | null} variableDeclaration
 * @property {string} method
 * @property {CallExpression} define
 * @property {(CallExpression | Identifier | MemberExpression)[]} defineChain Holds the initialization path for assignment of ref objects.
 *
 * @typedef {RefObjectReferenceForIdentifier | RefObjectReferenceForExpression | RefObjectReferenceForPattern} RefObjectReference
 */
/**
 * @typedef {object} ReactiveVariableReference
 * @property {Identifier} node
 * @property {boolean} escape Within escape hint (`$$()`)
 * @property {VariableDeclaration} variableDeclaration
 * @property {string} method
 * @property {CallExpression} define
 */

/**
 * @typedef {object} RefObjectReferences
 * @property {<T extends Identifier | Expression | Pattern | Super> (node: T) =>
 *   T extends Identifier ?
 *     RefObjectReferenceForIdentifier | null :
 *   T extends Expression ?
 *     RefObjectReferenceForExpression | null :
 *   T extends Pattern ?
 *     RefObjectReferenceForPattern | null :
 *   null} get
 */
/**
 * @typedef {object} ReactiveVariableReferences
 * @property {(node: Identifier) => ReactiveVariableReference | null} get
 */

const REF_MACROS = [
  '$ref',
  '$computed',
  '$shallowRef',
  '$customRef',
  '$toRef',
  '$'
]

/** @type {WeakMap<Program, RefObjectReferences>} */
const cacheForRefObjectReferences = new WeakMap()
/** @type {WeakMap<Program, ReactiveVariableReferences>} */
const cacheForReactiveVariableReferences = new WeakMap()

/**
 * Iterate the call expressions that define the ref object.
 * @param {import('eslint').Scope.Scope} globalScope
 * @returns {Iterable<{ node: CallExpression, name: string }>}
 */
function* iterateDefineRefs(globalScope) {
  const tracker = new ReferenceTracker(globalScope)
  for (const { node, path } of utils.iterateReferencesTraceMap(tracker, {
    ref: {
      [ReferenceTracker.CALL]: true
    },
    computed: {
      [ReferenceTracker.CALL]: true
    },
    toRef: {
      [ReferenceTracker.CALL]: true
    },
    customRef: {
      [ReferenceTracker.CALL]: true
    },
    shallowRef: {
      [ReferenceTracker.CALL]: true
    },
    toRefs: {
      [ReferenceTracker.CALL]: true
    }
  })) {
    const expr = /** @type {CallExpression} */ (node)
    yield {
      node: expr,
      name: path[path.length - 1]
    }
  }
}

/**
 * Iterate the call expressions that defineModel() macro.
 * @param {import('eslint').Scope.Scope} globalScope
 * @returns {Iterable<{ node: CallExpression }>}
 */
function* iterateDefineModels(globalScope) {
  for (const { identifier } of iterateMacroReferences()) {
    if (
      identifier.parent.type === 'CallExpression' &&
      identifier.parent.callee === identifier
    ) {
      yield {
        node: identifier.parent
      }
    }
  }

  /**
   * Iterate macro reference.
   * @returns {Iterable<Reference>}
   */
  function* iterateMacroReferences() {
    const variable = globalScope.set.get('defineModel')
    if (
      variable &&
      variable.defs.length === 0 /* It was automatically defined. */
    ) {
      yield* variable.references
    }
    for (const ref of globalScope.through) {
      if (ref.identifier.name === 'defineModel') {
        yield ref
      }
    }
  }
}

/**
 * Iterate the call expressions that define the reactive variables.
 * @param {import('eslint').Scope.Scope} globalScope
 * @returns {Iterable<{ node: CallExpression, name: string }>}
 */
function* iterateDefineReactiveVariables(globalScope) {
  for (const { identifier } of iterateRefMacroReferences()) {
    if (
      identifier.parent.type === 'CallExpression' &&
      identifier.parent.callee === identifier
    ) {
      yield {
        node: identifier.parent,
        name: identifier.name
      }
    }
  }

  /**
   * Iterate ref macro reference.
   * @returns {Iterable<Reference>}
   */
  function* iterateRefMacroReferences() {
    yield* REF_MACROS.map((m) => globalScope.set.get(m))
      .filter(utils.isDef)
      .flatMap((v) => v.references)
    for (const ref of globalScope.through) {
      if (REF_MACROS.includes(ref.identifier.name)) {
        yield ref
      }
    }
  }
}

/**
 *  Iterate the call expressions that the escape hint values.
 * @param {import('eslint').Scope.Scope} globalScope
 * @returns {Iterable<CallExpression>}
 */
function* iterateEscapeHintValueRefs(globalScope) {
  for (const { identifier } of iterateEscapeHintReferences()) {
    if (
      identifier.parent.type === 'CallExpression' &&
      identifier.parent.callee === identifier
    ) {
      yield identifier.parent
    }
  }

  /**
   * Iterate escape hint reference.
   * @returns {Iterable<Reference>}
   */
  function* iterateEscapeHintReferences() {
    const escapeHint = globalScope.set.get('$$')
    if (escapeHint) {
      yield* escapeHint.references
    }
    for (const ref of globalScope.through) {
      if (ref.identifier.name === '$$') {
        yield ref
      }
    }
  }
}

/**
 * Extract identifier from given pattern node.
 * @param {Pattern} node
 * @returns {Iterable<Identifier>}
 */
function* extractIdentifier(node) {
  switch (node.type) {
    case 'Identifier': {
      yield node
      break
    }
    case 'ObjectPattern': {
      for (const property of node.properties) {
        if (property.type === 'Property') {
          yield* extractIdentifier(property.value)
        } else if (property.type === 'RestElement') {
          yield* extractIdentifier(property)
        }
      }
      break
    }
    case 'ArrayPattern': {
      for (const element of node.elements) {
        if (element) {
          yield* extractIdentifier(element)
        }
      }
      break
    }
    case 'AssignmentPattern': {
      yield* extractIdentifier(node.left)
      break
    }
    case 'RestElement': {
      yield* extractIdentifier(node.argument)
      break
    }
    case 'MemberExpression': {
      // can't extract
      break
    }
    // No default
  }
}

/**
 * Iterate references of the given identifier.
 * @param {Identifier} id
 * @param {import('eslint').Scope.Scope} globalScope
 * @returns {Iterable<import('eslint').Scope.Reference>}
 */
function* iterateIdentifierReferences(id, globalScope) {
  const variable = eslintUtils.findVariable(globalScope, id)
  if (!variable) {
    return
  }

  for (const reference of variable.references) {
    yield reference
  }
}

/**
 * @param {RuleContext} context The rule context.
 */
function getGlobalScope(context) {
  const sourceCode = context.getSourceCode()
  return (
    sourceCode.scopeManager.globalScope || sourceCode.scopeManager.scopes[0]
  )
}

module.exports = {
  iterateDefineRefs,
  extractRefObjectReferences,
  extractReactiveVariableReferences
}

/**
 * @typedef {object} RefObjectReferenceContext
 * @property {string} method
 * @property {CallExpression} define
 * @property {(CallExpression | Identifier | MemberExpression)[]} defineChain Holds the initialization path for assignment of ref objects.
 */

/**
 * @implements {RefObjectReferences}
 */
class RefObjectReferenceExtractor {
  /**
   * @param {RuleContext} context The rule context.
   */
  constructor(context) {
    this.context = context
    /** @type {Map<Identifier | MemberExpression | CallExpression | ObjectPattern, RefObjectReference>} */
    this.references = new Map()

    /** @type {Set<Identifier>} */
    this._processedIds = new Set()
  }

  /**
   * @template {Identifier | Expression | Pattern | Super} T
   * @param {T} node
   * @returns {T extends Identifier ?
   *     RefObjectReferenceForIdentifier | null :
   *   T extends Expression ?
   *     RefObjectReferenceForExpression | null :
   *   T extends Pattern ?
   *     RefObjectReferenceForPattern | null :
   *   null}
   */
  get(node) {
    return /** @type {never} */ (
      this.references.get(/** @type {never} */ (node)) || null
    )
  }

  /**
   * @param {CallExpression} node
   * @param {string} method
   */
  processDefineRef(node, method) {
    const parent = node.parent
    /** @type {Pattern | null} */
    let pattern = null
    if (parent.type === 'VariableDeclarator') {
      pattern = parent.id
    } else if (
      parent.type === 'AssignmentExpression' &&
      parent.operator === '='
    ) {
      pattern = parent.left
    } else {
      if (method !== 'toRefs') {
        this.references.set(node, {
          type: 'expression',
          node,
          method,
          define: node,
          defineChain: [node]
        })
      }
      return
    }

    const ctx = {
      method,
      define: node,
      defineChain: [node]
    }

    if (method === 'toRefs') {
      const propertyReferenceExtractor = definePropertyReferenceExtractor(
        this.context
      )
      const propertyReferences =
        propertyReferenceExtractor.extractFromPattern(pattern)
      for (const name of propertyReferences.allProperties().keys()) {
        for (const nest of propertyReferences.getNestNodes(name)) {
          if (nest.type === 'expression') {
            this.processMemberExpression(nest.node, ctx)
          } else if (nest.type === 'pattern') {
            this.processPattern(nest.node, ctx)
          }
        }
      }
    } else {
      this.processPattern(pattern, ctx)
    }
  }

  /**
   * @param {CallExpression} node
   */
  processDefineModel(node) {
    const parent = node.parent
    /** @type {Pattern | null} */
    let pattern = null
    if (parent.type === 'VariableDeclarator') {
      pattern = parent.id
    } else if (
      parent.type === 'AssignmentExpression' &&
      parent.operator === '='
    ) {
      pattern = parent.left
    } else {
      return
    }

    const ctx = {
      method: 'defineModel',
      define: node,
      defineChain: [node]
    }

    if (pattern.type === 'ArrayPattern' && pattern.elements[0]) {
      pattern = pattern.elements[0]
    }
    this.processPattern(pattern, ctx)
  }

  /**
   * @param {MemberExpression | Identifier} node
   * @param {RefObjectReferenceContext} ctx
   */
  processExpression(node, ctx) {
    const parent = node.parent
    if (parent.type === 'AssignmentExpression') {
      if (parent.operator === '=' && parent.right === node) {
        // `(foo = obj.mem)`
        this.processPattern(parent.left, {
          ...ctx,
          defineChain: [node, ...ctx.defineChain]
        })
        return true
      }
    } else if (parent.type === 'VariableDeclarator' && parent.init === node) {
      // `const foo = obj.mem`
      this.processPattern(parent.id, {
        ...ctx,
        defineChain: [node, ...ctx.defineChain]
      })
      return true
    }
    return false
  }
  /**
   * @param {MemberExpression} node
   * @param {RefObjectReferenceContext} ctx
   */
  processMemberExpression(node, ctx) {
    if (this.processExpression(node, ctx)) {
      return
    }
    this.references.set(node, {
      type: 'expression',
      node,
      ...ctx
    })
  }

  /**
   * @param {Pattern} node
   * @param {RefObjectReferenceContext} ctx
   */
  processPattern(node, ctx) {
    switch (node.type) {
      case 'Identifier': {
        this.processIdentifierPattern(node, ctx)
        break
      }
      case 'ArrayPattern':
      case 'RestElement':
      case 'MemberExpression': {
        return
      }
      case 'ObjectPattern': {
        this.references.set(node, {
          type: 'pattern',
          node,
          ...ctx
        })
        return
      }
      case 'AssignmentPattern': {
        this.processPattern(node.left, ctx)
        return
      }
      // No default
    }
  }

  /**
   * @param {Identifier} node
   * @param {RefObjectReferenceContext} ctx
   */
  processIdentifierPattern(node, ctx) {
    if (this._processedIds.has(node)) {
      return
    }
    this._processedIds.add(node)

    for (const reference of iterateIdentifierReferences(
      node,
      getGlobalScope(this.context)
    )) {
      const def =
        reference.resolved &&
        reference.resolved.defs.length === 1 &&
        reference.resolved.defs[0].type === 'Variable'
          ? reference.resolved.defs[0]
          : null
      if (def && def.name === reference.identifier) {
        continue
      }
      if (
        reference.isRead() &&
        this.processExpression(reference.identifier, ctx)
      ) {
        continue
      }
      this.references.set(reference.identifier, {
        type: reference.isWrite() ? 'pattern' : 'expression',
        node: reference.identifier,
        variableDeclarator: def ? def.node : null,
        variableDeclaration: def ? def.parent : null,
        ...ctx
      })
    }
  }
}

/**
 * Extracts references of all ref objects.
 * @param {RuleContext} context The rule context.
 * @returns {RefObjectReferences}
 */
function extractRefObjectReferences(context) {
  const sourceCode = context.getSourceCode()
  const cachedReferences = cacheForRefObjectReferences.get(sourceCode.ast)
  if (cachedReferences) {
    return cachedReferences
  }
  const references = new RefObjectReferenceExtractor(context)

  const globalScope = getGlobalScope(context)
  for (const { node, name } of iterateDefineRefs(globalScope)) {
    references.processDefineRef(node, name)
  }
  for (const { node } of iterateDefineModels(globalScope)) {
    references.processDefineModel(node)
  }

  cacheForRefObjectReferences.set(sourceCode.ast, references)

  return references
}

/**
 * @implements {ReactiveVariableReferences}
 */
class ReactiveVariableReferenceExtractor {
  /**
   * @param {RuleContext} context The rule context.
   */
  constructor(context) {
    this.context = context
    /** @type {Map<Identifier, ReactiveVariableReference>} */
    this.references = new Map()

    /** @type {Set<Identifier>} */
    this._processedIds = new Set()

    /** @type {Set<CallExpression>} */
    this._escapeHintValueRefs = new Set(
      iterateEscapeHintValueRefs(getGlobalScope(context))
    )
  }

  /**
   * @param {Identifier} node
   * @returns {ReactiveVariableReference | null}
   */
  get(node) {
    return this.references.get(node) || null
  }

  /**
   * @param {CallExpression} node
   * @param {string} method
   */
  processDefineReactiveVariable(node, method) {
    const parent = node.parent
    if (parent.type !== 'VariableDeclarator') {
      return
    }
    /** @type {Pattern | null} */
    const pattern = parent.id

    if (method === '$') {
      for (const id of extractIdentifier(pattern)) {
        this.processIdentifierPattern(id, method, node)
      }
    } else {
      if (pattern.type === 'Identifier') {
        this.processIdentifierPattern(pattern, method, node)
      }
    }
  }

  /**
   * @param {Identifier} node
   * @param {string} method
   * @param {CallExpression} define
   */
  processIdentifierPattern(node, method, define) {
    if (this._processedIds.has(node)) {
      return
    }
    this._processedIds.add(node)

    for (const reference of iterateIdentifierReferences(
      node,
      getGlobalScope(this.context)
    )) {
      const def =
        reference.resolved &&
        reference.resolved.defs.length === 1 &&
        reference.resolved.defs[0].type === 'Variable'
          ? reference.resolved.defs[0]
          : null
      if (!def || def.name === reference.identifier) {
        continue
      }
      this.references.set(reference.identifier, {
        node: reference.identifier,
        escape: this.withinEscapeHint(reference.identifier),
        method,
        define,
        variableDeclaration: def.parent
      })
    }
  }

  /**
   * Checks whether the given identifier node within the escape hints (`$$()`) or not.
   * @param {Identifier} node
   */
  withinEscapeHint(node) {
    /** @type {Identifier | ObjectExpression | ArrayExpression | SpreadElement | Property | AssignmentProperty} */
    let target = node
    /** @type {ASTNode | null} */
    let parent = target.parent
    while (parent) {
      if (parent.type === 'CallExpression') {
        if (
          parent.arguments.includes(/** @type {any} */ (target)) &&
          this._escapeHintValueRefs.has(parent)
        ) {
          return true
        }
        return false
      }
      if (
        (parent.type === 'Property' && parent.value === target) ||
        (parent.type === 'ObjectExpression' &&
          parent.properties.includes(/** @type {any} */ (target))) ||
        parent.type === 'ArrayExpression' ||
        parent.type === 'SpreadElement'
      ) {
        target = parent
        parent = target.parent
      } else {
        return false
      }
    }
    return false
  }
}

/**
 * Extracts references of all reactive variables.
 * @param {RuleContext} context The rule context.
 * @returns {ReactiveVariableReferences}
 */
function extractReactiveVariableReferences(context) {
  const sourceCode = context.getSourceCode()
  const cachedReferences = cacheForReactiveVariableReferences.get(
    sourceCode.ast
  )
  if (cachedReferences) {
    return cachedReferences
  }

  const references = new ReactiveVariableReferenceExtractor(context)

  for (const { node, name } of iterateDefineReactiveVariables(
    getGlobalScope(context)
  )) {
    references.processDefineReactiveVariable(node, name)
  }

  cacheForReactiveVariableReferences.set(sourceCode.ast, references)

  return references
}


code:
const RE_REGEXP_CHAR = /[\\^$.*+?()[\]{}|]/gu
const RE_HAS_REGEXP_CHAR = new RegExp(RE_REGEXP_CHAR.source)

const RE_REGEXP_STR = /^\/(.+)\/(.*)$/u

/**
 * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
 * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
 *
 * @param {string} string The string to escape.
 * @returns {string} Returns the escaped string.
 */
function escape(string) {
  return string && RE_HAS_REGEXP_CHAR.test(string)
    ? string.replace(RE_REGEXP_CHAR, String.raw`\$&`)
    : string
}

/**
 * Convert a string to the `RegExp`.
 * Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`.
 * Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
 *
 * @param {string} string The string to convert.
 * @returns {RegExp} Returns the `RegExp`.
 */
function toRegExp(string) {
  const parts = RE_REGEXP_STR.exec(string)
  if (parts) {
    return new RegExp(parts[1], parts[2])
  }
  return new RegExp(`^${escape(string)}$`)
}

/**
 * Checks whether given string is regexp string
 * @param {string} string
 * @returns {boolean}
 */
function isRegExp(string) {
  return RE_REGEXP_STR.test(string)
}

module.exports = {
  escape,
  toRegExp,
  isRegExp
}


code:
module.exports = {
  getScope
}

/**
 * Gets the scope for the current node
 * @param {RuleContext} context The rule context
 * @param {ESNode} currentNode The node to get the scope of
 * @returns { import('eslint').Scope.Scope } The scope information for this node
 */
function getScope(context, currentNode) {
  // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
  const inner = currentNode.type !== 'Program'
  const scopeManager = context.getSourceCode().scopeManager

  /** @type {ESNode | null} */
  let node = currentNode
  for (; node; node = /** @type {ESNode | null} */ (node.parent)) {
    const scope = scopeManager.acquire(node, inner)

    if (scope) {
      if (scope.type === 'function-expression-name') {
        return scope.childScopes[0]
      }
      return scope
    }
  }

  return scopeManager.scopes[0]
}


code:
'use strict'

const parser = require('postcss-selector-parser')
const { default: nthCheck } = require('nth-check')
const { getAttribute, isVElement } = require('.')

/**
 * @typedef {object} VElementSelector
 * @property {(element: VElement)=>boolean} test
 */

module.exports = {
  parseSelector
}

/**
 * Parses CSS selectors and returns an object with a function that tests VElement.
 * @param {string} selector CSS selector
 * @param {RuleContext} context - The rule context.
 * @returns {VElementSelector}
 */
function parseSelector(selector, context) {
  let astSelector
  try {
    astSelector = parser().astSync(selector)
  } catch (error) {
    context.report({
      loc: { line: 0, column: 0 },
      message: `Cannot parse selector: ${selector}.`
    })
    return {
      test: () => false
    }
  }

  try {
    const test = selectorsToVElementMatcher(astSelector.nodes)

    return {
      test(element) {
        return test(element, null)
      }
    }
  } catch (error) {
    if (error instanceof SelectorError) {
      context.report({
        loc: { line: 0, column: 0 },
        message: error.message
      })
      return {
        test: () => false
      }
    }
    throw error
  }
}

class SelectorError extends Error {}

/**
 * @typedef {(element: VElement, subject: VElement | null )=>boolean} VElementMatcher
 * @typedef {Exclude<parser.Selector['nodes'][number], {type:'comment'|'root'}>} ChildNode
 */

/**
 * Convert nodes to VElementMatcher
 * @param {parser.Selector[]} selectorNodes
 * @returns {VElementMatcher}
 */
function selectorsToVElementMatcher(selectorNodes) {
  const selectors = selectorNodes.map((n) =>
    selectorToVElementMatcher(cleanSelectorChildren(n))
  )
  return (element, subject) => selectors.some((sel) => sel(element, subject))
}

/**
 * @param {parser.Node|null} node
 * @returns {node is parser.Combinator}
 */
function isDescendantCombinator(node) {
  return Boolean(node && node.type === 'combinator' && !node.value.trim())
}

/**
 * Clean and get the selector child nodes.
 * @param {parser.Selector} selector
 * @returns {ChildNode[]}
 */
function cleanSelectorChildren(selector) {
  /** @type {ChildNode[]} */
  const nodes = []
  /** @type {ChildNode|null} */
  let last = null
  for (const node of selector.nodes) {
    if (node.type === 'root') {
      throw new SelectorError('Unexpected state type=root')
    }
    if (node.type === 'comment') {
      continue
    }
    if (
      (last == null || last.type === 'combinator') &&
      isDescendantCombinator(node)
    ) {
      // Ignore descendant combinator
      continue
    }
    if (isDescendantCombinator(last) && node.type === 'combinator') {
      // Replace combinator
      nodes.pop()
    }
    nodes.push(node)
    last = node
  }
  if (isDescendantCombinator(last)) {
    nodes.pop()
  }
  return nodes
}
/**
 * Convert Selector child nodes to VElementMatcher
 * @param {ChildNode[]} selectorChildren
 * @returns {VElementMatcher}
 */
function selectorToVElementMatcher(selectorChildren) {
  const nodes = [...selectorChildren]
  let node = nodes.shift()
  /**
   * @type {VElementMatcher | null}
   */
  let result = null
  while (node) {
    if (node.type === 'combinator') {
      const combinator = node.value
      node = nodes.shift()
      if (!node) {
        throw new SelectorError(`Expected selector after '${combinator}'.`)
      }
      if (node.type === 'combinator') {
        throw new SelectorError(`Unexpected combinator '${node.value}'.`)
      }
      const right = nodeToVElementMatcher(node)
      result = combination(
        result ||
          // for :has()
          ((element, subject) => element === subject),
        combinator,
        right
      )
    } else {
      const sel = nodeToVElementMatcher(node)
      result = result ? compound(result, sel) : sel
    }
    node = nodes.shift()
  }
  if (!result) {
    throw new SelectorError(`Unexpected empty selector.`)
  }
  return result
}

/**
 * @param {VElementMatcher} left
 * @param {string} combinator
 * @param {VElementMatcher} right
 * @returns {VElementMatcher}
 */
function combination(left, combinator, right) {
  switch (combinator.trim()) {
    case '': {
      // descendant
      return (element, subject) => {
        if (right(element, null)) {
          let parent = element.parent
          while (parent.type === 'VElement') {
            if (left(parent, subject)) {
              return true
            }
            parent = parent.parent
          }
        }
        return false
      }
    }
    case '>': {
      // child
      return (element, subject) => {
        if (right(element, null)) {
          const parent = element.parent
          if (parent.type === 'VElement') {
            return left(parent, subject)
          }
        }
        return false
      }
    }
    case '+': {
      // adjacent
      return (element, subject) => {
        if (right(element, null)) {
          const before = getBeforeElement(element)
          if (before) {
            return left(before, subject)
          }
        }
        return false
      }
    }
    case '~': {
      // sibling
      return (element, subject) => {
        if (right(element, null)) {
          for (const before of getBeforeElements(element)) {
            if (left(before, subject)) {
              return true
            }
          }
        }
        return false
      }
    }
    default: {
      throw new SelectorError(`Unknown combinator: ${combinator}.`)
    }
  }
}

/**
 * Convert node to VElementMatcher
 * @param {Exclude<parser.Node, {type:'combinator'|'comment'|'root'|'selector'}>} selector
 * @returns {VElementMatcher}
 */
function nodeToVElementMatcher(selector) {
  switch (selector.type) {
    case 'attribute': {
      return attributeNodeToVElementMatcher(selector)
    }
    case 'class': {
      return classNameNodeToVElementMatcher(selector)
    }
    case 'id': {
      return identifierNodeToVElementMatcher(selector)
    }
    case 'tag': {
      return tagNodeToVElementMatcher(selector)
    }
    case 'universal': {
      return universalNodeToVElementMatcher(selector)
    }
    case 'pseudo': {
      return pseudoNodeToVElementMatcher(selector)
    }
    case 'nesting': {
      throw new SelectorError('Unsupported nesting selector.')
    }
    case 'string': {
      throw new SelectorError(`Unknown selector: ${selector.value}.`)
    }
    default: {
      throw new SelectorError(
        `Unknown selector: ${/** @type {any}*/ (selector).value}.`
      )
    }
  }
}

/**
 * Convert Attribute node to VElementMatcher
 * @param {parser.Attribute} selector
 * @returns {VElementMatcher}
 */
function attributeNodeToVElementMatcher(selector) {
  const key = selector.attribute
  if (!selector.operator) {
    return (element) => getAttributeValue(element, key) != null
  }
  const value = selector.value || ''

  switch (selector.operator) {
    case '=': {
      return buildVElementMatcher(value, (attr, val) => attr === val)
    }
    case '~=': {
      // words
      return buildVElementMatcher(value, (attr, val) =>
        attr.split(/\s+/gu).includes(val)
      )
    }
    case '|=': {
      // immediately followed by hyphen
      return buildVElementMatcher(
        value,
        (attr, val) => attr === val || attr.startsWith(`${val}-`)
      )
    }
    case '^=': {
      // prefixed
      return buildVElementMatcher(value, (attr, val) => attr.startsWith(val))
    }
    case '$=': {
      // suffixed
      return buildVElementMatcher(value, (attr, val) => attr.endsWith(val))
    }
    case '*=': {
      // contains
      return buildVElementMatcher(value, (attr, val) => attr.includes(val))
    }
    default: {
      throw new SelectorError(`Unsupported operator: ${selector.operator}.`)
    }
  }

  /**
   * @param {string} selectorValue
   * @param {(attrValue:string, selectorValue: string)=>boolean} test
   * @returns {VElementMatcher}
   */
  function buildVElementMatcher(selectorValue, test) {
    const val = selector.insensitive
      ? selectorValue.toLowerCase()
      : selectorValue
    return (element) => {
      const attrValue = getAttributeValue(element, key)
      if (attrValue == null) {
        return false
      }
      return test(
        selector.insensitive ? attrValue.toLowerCase() : attrValue,
        val
      )
    }
  }
}

/**
 * Convert ClassName node to VElementMatcher
 * @param {parser.ClassName} selector
 * @returns {VElementMatcher}
 */
function classNameNodeToVElementMatcher(selector) {
  const className = selector.value
  return (element) => {
    const attrValue = getAttributeValue(element, 'class')
    if (attrValue == null) {
      return false
    }
    return attrValue.split(/\s+/gu).includes(className)
  }
}

/**
 * Convert Identifier node to VElementMatcher
 * @param {parser.Identifier} selector
 * @returns {VElementMatcher}
 */
function identifierNodeToVElementMatcher(selector) {
  const id = selector.value
  return (element) => {
    const attrValue = getAttributeValue(element, 'id')
    if (attrValue == null) {
      return false
    }
    return attrValue === id
  }
}

/**
 * Convert Tag node to VElementMatcher
 * @param {parser.Tag} selector
 * @returns {VElementMatcher}
 */
function tagNodeToVElementMatcher(selector) {
  const name = selector.value
  return (element) => element.rawName === name
}

/**
 * Convert Universal node to VElementMatcher
 * @param {parser.Universal} _selector
 * @returns {VElementMatcher}
 */
function universalNodeToVElementMatcher(_selector) {
  return () => true
}
/**
 * Convert Pseudo node to VElementMatcher
 * @param {parser.Pseudo} selector
 * @returns {VElementMatcher}
 */
function pseudoNodeToVElementMatcher(selector) {
  const pseudo = selector.value
  switch (pseudo) {
    case ':not': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:not
      const selectors = selectorsToVElementMatcher(selector.nodes)
      return (element, subject) => !selectors(element, subject)
    }
    case ':is':
    case ':where': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:is
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:where
      return selectorsToVElementMatcher(selector.nodes)
    }
    case ':has': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:has
      return pseudoHasSelectorsToVElementMatcher(selector.nodes)
    }
    case ':empty': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:empty
      return (element) =>
        element.children.every(
          (child) => child.type === 'VText' && !child.value.trim()
        )
    }
    case ':nth-child': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child
      const nth = parseNth(selector)
      return buildPseudoNthVElementMatcher(nth)
    }
    case ':nth-last-child': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-child
      const nth = parseNth(selector)
      return buildPseudoNthVElementMatcher((index, length) =>
        nth(length - index - 1)
      )
    }
    case ':first-child': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:first-child
      return buildPseudoNthVElementMatcher((index) => index === 0)
    }
    case ':last-child': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child
      return buildPseudoNthVElementMatcher(
        (index, length) => index === length - 1
      )
    }
    case ':only-child': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:only-child
      return buildPseudoNthVElementMatcher(
        (index, length) => index === 0 && length === 1
      )
    }
    case ':nth-of-type': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type
      const nth = parseNth(selector)
      return buildPseudoNthOfTypeVElementMatcher(nth)
    }
    case ':nth-last-of-type': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-of-type
      const nth = parseNth(selector)
      return buildPseudoNthOfTypeVElementMatcher((index, length) =>
        nth(length - index - 1)
      )
    }
    case ':first-of-type': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:first-of-type
      return buildPseudoNthOfTypeVElementMatcher((index) => index === 0)
    }
    case ':last-of-type': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:last-of-type
      return buildPseudoNthOfTypeVElementMatcher(
        (index, length) => index === length - 1
      )
    }
    case ':only-of-type': {
      // https://developer.mozilla.org/en-US/docs/Web/CSS/:only-of-type
      return buildPseudoNthOfTypeVElementMatcher(
        (index, length) => index === 0 && length === 1
      )
    }
    default: {
      throw new SelectorError(`Unsupported pseudo selector: ${pseudo}.`)
    }
  }
}

/**
 * Convert :has() selector nodes to VElementMatcher
 * @param {parser.Selector[]} selectorNodes
 * @returns {VElementMatcher}
 */
function pseudoHasSelectorsToVElementMatcher(selectorNodes) {
  const selectors = selectorNodes.map((n) =>
    pseudoHasSelectorToVElementMatcher(n)
  )
  return (element, subject) => selectors.some((sel) => sel(element, subject))
}
/**
 * Convert :has() selector node to VElementMatcher
 * @param {parser.Selector} selector
 * @returns {VElementMatcher}
 */
function pseudoHasSelectorToVElementMatcher(selector) {
  const nodes = cleanSelectorChildren(selector)
  const selectors = selectorToVElementMatcher(nodes)
  const firstNode = nodes[0]
  if (
    firstNode.type === 'combinator' &&
    (firstNode.value === '+' || firstNode.value === '~')
  ) {
    // adjacent or sibling
    return buildVElementMatcher(selectors, (element) =>
      getAfterElements(element)
    )
  }
  // descendant or child
  return buildVElementMatcher(selectors, (element) =>
    element.children.filter(isVElement)
  )
}

/**
 * @param {VElementMatcher} selectors
 * @param {(element: VElement) => VElement[]} getStartElements
 * @returns {VElementMatcher}
 */
function buildVElementMatcher(selectors, getStartElements) {
  return (element) => {
    const elements = [...getStartElements(element)]
    /** @type {VElement|undefined} */
    let curr
    while ((curr = elements.shift())) {
      const el = curr
      if (selectors(el, element)) {
        return true
      }
      elements.push(...el.children.filter(isVElement))
    }
    return false
  }
}

/**
 * Parse <nth>
 * @param {parser.Pseudo} pseudoNode
 * @returns {(index: number)=>boolean}
 */
function parseNth(pseudoNode) {
  const argumentsText = pseudoNode
    .toString()
    .slice(pseudoNode.value.length)
    .toLowerCase()
  const openParenIndex = argumentsText.indexOf('(')
  const closeParenIndex = argumentsText.lastIndexOf(')')
  if (openParenIndex < 0 || closeParenIndex < 0) {
    throw new SelectorError(
      `Cannot parse An+B micro syntax (:nth-xxx() argument): ${argumentsText}.`
    )
  }

  const argument = argumentsText
    .slice(openParenIndex + 1, closeParenIndex)
    .trim()
  try {
    return nthCheck(argument)
  } catch (error) {
    throw new SelectorError(
      `Cannot parse An+B micro syntax (:nth-xxx() argument): '${argument}'.`
    )
  }
}

/**
 * Build VElementMatcher for :nth-xxx()
 * @param {(index: number, length: number)=>boolean} testIndex
 * @returns {VElementMatcher}
 */
function buildPseudoNthVElementMatcher(testIndex) {
  return (element) => {
    const elements = element.parent.children.filter(isVElement)
    return testIndex(elements.indexOf(element), elements.length)
  }
}

/**
 * Build VElementMatcher for :nth-xxx-of-type()
 * @param {(index: number, length: number)=>boolean} testIndex
 * @returns {VElementMatcher}
 */
function buildPseudoNthOfTypeVElementMatcher(testIndex) {
  return (element) => {
    const elements = element.parent.children.filter(
      /** @returns {e is VElement} */
      (e) => isVElement(e) && e.rawName === element.rawName
    )
    return testIndex(elements.indexOf(element), elements.length)
  }
}

/**
 * @param {VElement} element
 */
function getBeforeElement(element) {
  return getBeforeElements(element).pop() || null
}
/**
 * @param {VElement} element
 */
function getBeforeElements(element) {
  const parent = element.parent
  const index = parent.children.indexOf(element)
  return parent.children.slice(0, index).filter(isVElement)
}

/**
 * @param {VElement} element
 */
function getAfterElements(element) {
  const parent = element.parent
  const index = parent.children.indexOf(element)
  return parent.children.slice(index + 1).filter(isVElement)
}

/**
 * @param {VElementMatcher} a
 * @param {VElementMatcher} b
 * @returns {VElementMatcher}
 */
function compound(a, b) {
  return (element, subject) => a(element, subject) && b(element, subject)
}

/**
 * Get attribute value from given element.
 * @param {VElement} element The element node.
 * @param {string} attribute The attribute name.
 */
function getAttributeValue(element, attribute) {
  const attr = getAttribute(element, attribute)
  if (attr) {
    return (attr.value && attr.value.value) || ''
  }
  return null
}


code:
const { isVElement } = require('..')

class StyleVariablesContext {
  /**
   * @param {RuleContext} context
   * @param {VElement[]} styles
   */
  constructor(context, styles) {
    this.context = context
    this.styles = styles
    /** @type {VReference[]} */
    this.references = []
    /** @type {VExpressionContainer[]} */
    this.vBinds = []
    for (const style of styles) {
      for (const node of style.children) {
        if (node.type === 'VExpressionContainer') {
          this.vBinds.push(node)
          for (const ref of node.references.filter(
            (ref) => ref.variable == null
          )) {
            this.references.push(ref)
          }
        }
      }
    }
  }
}

module.exports = {
  getStyleVariablesContext,
  StyleVariablesContext
}

/** @type {WeakMap<VElement, StyleVariablesContext>} */
const cache = new WeakMap()
/**
 * Get the style vars context
 * @param {RuleContext} context
 * @returns {StyleVariablesContext | null}
 */
function getStyleVariablesContext(context) {
  const sourceCode = context.getSourceCode()
  const df =
    sourceCode.parserServices.getDocumentFragment &&
    sourceCode.parserServices.getDocumentFragment()
  if (!df) {
    return null
  }
  const styles = df.children.filter(
    /** @returns {e is VElement} */
    (e) => isVElement(e) && e.name === 'style'
  )
  if (styles.length === 0) {
    return null
  }
  let ctx = cache.get(styles[0])
  if (ctx) {
    return ctx
  }
  ctx = new StyleVariablesContext(context, styles)
  cache.set(styles[0], ctx)
  return ctx
}


code: accent-height alignment-baseline arabic-form attributeName attributeType baseFrequency baseline-shift baseProfile calcMode cap-height clipPathUnits clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering contentScriptType contentStyleType diffuseConstant dominant-baseline edgeMode enable-background externalResourcesRequired fill-opacity fill-rule filterRes filterUnits flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical glyphRef gradientTransform gradientUnits horiz-adv-x horiz-origin-x image-rendering kernelMatrix kernelUnitLength keyPoints keySplines keyTimes lengthAdjust letter-spacing lighting-color limitingConeAngle marker-end marker-mid marker-start markerHeight markerUnits markerWidth maskContentUnits maskUnits numOctaves overline-position overline-thickness panose-1 paint-order pathLength patternContentUnits patternTransform patternUnits pointer-events pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits referrerPolicy refX refY rendering-intent repeatCount repeatDur requiredExtensions requiredFeatures shape-rendering specularConstant specularExponent spreadMethod startOffset stdDeviation stitchTiles stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width surfaceScale systemLanguage tableValues targetX targetY text-anchor text-decoration text-rendering textLength transform-origin underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y viewBox viewTarget word-spacing writing-mode x-height xChannelSelector yChannelSelector zoomAndPan


code: a animate animateMotion animateTransform audio canvas circle clipPath defs desc discard ellipse feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feDropShadow feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter foreignObject g iframe image line linearGradient marker mask metadata mpath path pattern polygon polyline radialGradient rect script set stop style svg switch symbol text textPath title tspan unknown use video view


code:
const {
  isTypeNode,
  extractRuntimeProps,
  isTSTypeLiteral,
  isTSTypeLiteralOrTSFunctionType,
  extractRuntimeEmits,
  flattenTypeNodes,
  isTSInterfaceBody
} = require('./ts-ast')
const {
  getComponentPropsFromTypeDefineTypes,
  getComponentEmitsFromTypeDefineTypes
} = require('./ts-types')

/**
 * @typedef {import('@typescript-eslint/types').TSESTree.TypeNode} TSESTreeTypeNode
 */
/**
 * @typedef {import('../index').ComponentTypeProp} ComponentTypeProp
 * @typedef {import('../index').ComponentInferTypeProp} ComponentInferTypeProp
 * @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp
 * @typedef {import('../index').ComponentTypeEmit} ComponentTypeEmit
 * @typedef {import('../index').ComponentInferTypeEmit} ComponentInferTypeEmit
 * @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit
 */

module.exports = {
  isTypeNode,
  getComponentPropsFromTypeDefine,
  getComponentEmitsFromTypeDefine
}

/**
 * Get all props by looking at all component's properties
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TypeNode} propsNode Type with props definition
 * @return {(ComponentTypeProp|ComponentInferTypeProp|ComponentUnknownProp)[]} Array of component props
 */
function getComponentPropsFromTypeDefine(context, propsNode) {
  /** @type {(ComponentTypeProp|ComponentInferTypeProp|ComponentUnknownProp)[]} */
  const result = []
  for (const defNode of flattenTypeNodes(
    context,
    /** @type {TSESTreeTypeNode} */ (propsNode)
  )) {
    if (isTSInterfaceBody(defNode) || isTSTypeLiteral(defNode)) {
      result.push(...extractRuntimeProps(context, defNode))
    } else {
      result.push(
        ...getComponentPropsFromTypeDefineTypes(
          context,
          /** @type {TypeNode} */ (defNode)
        )
      )
    }
  }
  return result
}

/**
 * Get all emits by looking at all component's properties
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TypeNode} emitsNode Type with emits definition
 * @return {(ComponentTypeEmit|ComponentInferTypeEmit|ComponentUnknownEmit)[]} Array of component emits
 */
function getComponentEmitsFromTypeDefine(context, emitsNode) {
  /** @type {(ComponentTypeEmit|ComponentInferTypeEmit|ComponentUnknownEmit)[]} */
  const result = []
  for (const defNode of flattenTypeNodes(
    context,
    /** @type {TSESTreeTypeNode} */ (emitsNode)
  )) {
    if (
      isTSInterfaceBody(defNode) ||
      isTSTypeLiteralOrTSFunctionType(defNode)
    ) {
      result.push(...extractRuntimeEmits(defNode))
    } else {
      result.push(
        ...getComponentEmitsFromTypeDefineTypes(
          context,
          /** @type {TypeNode} */ (defNode)
        )
      )
    }
  }
  return result
}


code:
const { getScope } = require('../scope')
const { findVariable } = require('@eslint-community/eslint-utils')
const { inferRuntimeTypeFromTypeNode } = require('./ts-types')
/**
 * @typedef {import('@typescript-eslint/types').TSESTree.TypeNode} TSESTreeTypeNode
 * @typedef {import('@typescript-eslint/types').TSESTree.TSInterfaceBody} TSESTreeTSInterfaceBody
 * @typedef {import('@typescript-eslint/types').TSESTree.TSTypeLiteral} TSESTreeTSTypeLiteral
 * @typedef {import('@typescript-eslint/types').TSESTree.TSFunctionType} TSESTreeTSFunctionType
 * @typedef {import('@typescript-eslint/types').TSESTree.Parameter} TSESTreeParameter
 * @typedef {import('@typescript-eslint/types').TSESTree.Node} TSESTreeNode
 *
 */
/**
 * @typedef {import('../index').ComponentTypeProp} ComponentTypeProp
 * @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp
 * @typedef {import('../index').ComponentTypeEmit} ComponentTypeEmit
 * @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit
 */

const noop = Function.prototype

module.exports = {
  isTypeNode,
  flattenTypeNodes,
  isTSInterfaceBody,
  isTSTypeLiteral,
  isTSTypeLiteralOrTSFunctionType,
  extractRuntimeProps,
  extractRuntimeEmits
}

/**
 * @param {ASTNode} node
 * @returns {node is TypeNode}
 */
function isTypeNode(node) {
  if (
    node.type === 'TSAbstractKeyword' ||
    node.type === 'TSAnyKeyword' ||
    node.type === 'TSAsyncKeyword' ||
    node.type === 'TSArrayType' ||
    node.type === 'TSBigIntKeyword' ||
    node.type === 'TSBooleanKeyword' ||
    node.type === 'TSConditionalType' ||
    node.type === 'TSConstructorType' ||
    node.type === 'TSDeclareKeyword' ||
    node.type === 'TSExportKeyword' ||
    node.type === 'TSFunctionType' ||
    node.type === 'TSImportType' ||
    node.type === 'TSIndexedAccessType' ||
    node.type === 'TSInferType' ||
    node.type === 'TSIntersectionType' ||
    node.type === 'TSIntrinsicKeyword' ||
    node.type === 'TSLiteralType' ||
    node.type === 'TSMappedType' ||
    node.type === 'TSNamedTupleMember' ||
    node.type === 'TSNeverKeyword' ||
    node.type === 'TSNullKeyword' ||
    node.type === 'TSNumberKeyword' ||
    node.type === 'TSObjectKeyword' ||
    node.type === 'TSOptionalType' ||
    node.type === 'TSQualifiedName' ||
    node.type === 'TSPrivateKeyword' ||
    node.type === 'TSProtectedKeyword' ||
    node.type === 'TSPublicKeyword' ||
    node.type === 'TSReadonlyKeyword' ||
    node.type === 'TSRestType' ||
    node.type === 'TSStaticKeyword' ||
    node.type === 'TSStringKeyword' ||
    node.type === 'TSSymbolKeyword' ||
    node.type === 'TSTemplateLiteralType' ||
    node.type === 'TSThisType' ||
    node.type === 'TSTupleType' ||
    node.type === 'TSTypeLiteral' ||
    node.type === 'TSTypeOperator' ||
    node.type === 'TSTypePredicate' ||
    node.type === 'TSTypeQuery' ||
    node.type === 'TSTypeReference' ||
    node.type === 'TSUndefinedKeyword' ||
    node.type === 'TSUnionType' ||
    node.type === 'TSUnknownKeyword' ||
    node.type === 'TSVoidKeyword'
  ) {
    /** @type {TypeNode['type']} for type check */
    const type = node.type
    noop(type)
    return true
  }
  /** @type {Exclude<ASTNode['type'], TypeNode['type']>} for type check */
  const type = node.type
  noop(type)
  return false
}

/**
 * @param {TSESTreeTypeNode|TSESTreeTSInterfaceBody} node
 * @returns {node is TSESTreeTSInterfaceBody}
 */
function isTSInterfaceBody(node) {
  return node.type === 'TSInterfaceBody'
}
/**
 * @param {TSESTreeTypeNode} node
 * @returns {node is TSESTreeTSTypeLiteral}
 */
function isTSTypeLiteral(node) {
  return node.type === 'TSTypeLiteral'
}
/**
 * @param {TSESTreeTypeNode} node
 * @returns {node is TSESTreeTSFunctionType}
 */
function isTSFunctionType(node) {
  return node.type === 'TSFunctionType'
}
/**
 * @param {TSESTreeTypeNode} node
 * @returns {node is TSESTreeTSTypeLiteral | TSESTreeTSFunctionType}
 */
function isTSTypeLiteralOrTSFunctionType(node) {
  return isTSTypeLiteral(node) || isTSFunctionType(node)
}

/**
 * @see https://github.com/vuejs/vue-next/blob/253ca2729d808fc051215876aa4af986e4caa43c/packages/compiler-sfc/src/compileScript.ts#L1512
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TSESTreeTSTypeLiteral | TSESTreeTSInterfaceBody} node
 * @returns {IterableIterator<ComponentTypeProp | ComponentUnknownProp>}
 */
function* extractRuntimeProps(context, node) {
  const members = node.type === 'TSTypeLiteral' ? node.members : node.body
  for (const member of members) {
    if (
      member.type === 'TSPropertySignature' ||
      member.type === 'TSMethodSignature'
    ) {
      if (member.key.type !== 'Identifier' && member.key.type !== 'Literal') {
        yield {
          type: 'unknown',
          propName: null,
          node: /** @type {Expression} */ (member.key)
        }
        continue
      }
      /** @type {string[]|undefined} */
      let types
      if (member.type === 'TSMethodSignature') {
        types = ['Function']
      } else if (member.typeAnnotation) {
        types = inferRuntimeType(context, member.typeAnnotation.typeAnnotation)
      }
      yield {
        type: 'type',
        key: /** @type {Identifier | Literal} */ (member.key),
        propName:
          member.key.type === 'Identifier'
            ? member.key.name
            : `${member.key.value}`,
        node: /** @type {TSPropertySignature | TSMethodSignature} */ (member),

        required: !member.optional,
        types: types || [`null`]
      }
    }
  }
}

/**
 * @param {TSESTreeTSTypeLiteral | TSESTreeTSInterfaceBody | TSESTreeTSFunctionType} node
 * @returns {IterableIterator<ComponentTypeEmit | ComponentUnknownEmit>}
 */
function* extractRuntimeEmits(node) {
  if (node.type === 'TSFunctionType') {
    yield* extractEventNames(
      node.params[0],
      /** @type {TSFunctionType} */ (node)
    )
    return
  }
  const members = node.type === 'TSTypeLiteral' ? node.members : node.body
  for (const member of members) {
    if (member.type === 'TSCallSignatureDeclaration') {
      yield* extractEventNames(
        member.params[0],
        /** @type {TSCallSignatureDeclaration} */ (member)
      )
    } else if (
      member.type === 'TSPropertySignature' ||
      member.type === 'TSMethodSignature'
    ) {
      if (member.key.type !== 'Identifier' && member.key.type !== 'Literal') {
        yield {
          type: 'unknown',
          emitName: null,
          node: /** @type {Expression} */ (member.key)
        }
        continue
      }
      yield {
        type: 'type',
        key: /** @type {Identifier | Literal} */ (member.key),
        emitName:
          member.key.type === 'Identifier'
            ? member.key.name
            : `${member.key.value}`,
        node: /** @type {TSPropertySignature | TSMethodSignature} */ (member)
      }
    }
  }
}

/**
 * @param {TSESTreeParameter} eventName
 * @param {TSCallSignatureDeclaration | TSFunctionType} member
 * @returns {IterableIterator<ComponentTypeEmit>}
 */
function* extractEventNames(eventName, member) {
  if (
    eventName &&
    eventName.type === 'Identifier' &&
    eventName.typeAnnotation &&
    eventName.typeAnnotation.type === 'TSTypeAnnotation'
  ) {
    const typeNode = eventName.typeAnnotation.typeAnnotation
    if (
      typeNode.type === 'TSLiteralType' &&
      typeNode.literal.type === 'Literal'
    ) {
      const emitName = String(typeNode.literal.value)
      yield {
        type: 'type',
        key: /** @type {TSLiteralType} */ (typeNode),
        emitName,
        node: member
      }
    } else if (typeNode.type === 'TSUnionType') {
      for (const t of typeNode.types) {
        if (t.type === 'TSLiteralType' && t.literal.type === 'Literal') {
          const emitName = String(t.literal.value)
          yield {
            type: 'type',
            key: /** @type {TSLiteralType} */ (t),
            emitName,
            node: member
          }
        }
      }
    }
  }
}

/**
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TSESTreeTypeNode} node
 * @returns {(TSESTreeTypeNode|TSESTreeTSInterfaceBody)[]}
 */
function flattenTypeNodes(context, node) {
  /**
   * @typedef {object} TraversedData
   * @property {Set<TSESTreeTypeNode|TSESTreeTSInterfaceBody>} nodes
   * @property {boolean} finished
   */
  /** @type {Map<TSESTreeTypeNode,TraversedData>} */
  const traversed = new Map()

  return [...flattenImpl(node)]
  /**
   * @param {TSESTreeTypeNode} node
   * @returns {Iterable<TSESTreeTypeNode|TSESTreeTSInterfaceBody>}
   */
  function* flattenImpl(node) {
    if (node.type === 'TSUnionType' || node.type === 'TSIntersectionType') {
      for (const typeNode of node.types) {
        yield* flattenImpl(typeNode)
      }
      return
    }
    if (
      node.type === 'TSTypeReference' &&
      node.typeName.type === 'Identifier'
    ) {
      const refName = node.typeName.name
      const variable = findVariable(
        getScope(context, /** @type {any} */ (node)),
        refName
      )
      if (variable && variable.defs.length === 1) {
        const defNode = /** @type {TSESTreeNode} */ (variable.defs[0].node)
        if (defNode.type === 'TSInterfaceDeclaration') {
          yield defNode.body
          return
        } else if (defNode.type === 'TSTypeAliasDeclaration') {
          const typeAnnotation = defNode.typeAnnotation
          let traversedData = traversed.get(typeAnnotation)
          if (traversedData) {
            const copy = [...traversedData.nodes]
            yield* copy
            if (!traversedData.finished) {
              // Include the node because it will probably be referenced recursively.
              yield typeAnnotation
            }
            return
          }
          traversedData = { nodes: new Set(), finished: false }
          traversed.set(typeAnnotation, traversedData)
          for (const e of flattenImpl(typeAnnotation)) {
            traversedData.nodes.add(e)
          }
          traversedData.finished = true
          yield* traversedData.nodes
          return
        }
      }
    }
    yield node
  }
}

/**
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TSESTreeTypeNode} node
 * @param {Set<TSESTreeTypeNode>} [checked]
 * @returns {string[]}
 */
function inferRuntimeType(context, node, checked = new Set()) {
  switch (node.type) {
    case 'TSStringKeyword':
    case 'TSTemplateLiteralType': {
      return ['String']
    }
    case 'TSNumberKeyword': {
      return ['Number']
    }
    case 'TSBooleanKeyword': {
      return ['Boolean']
    }
    case 'TSObjectKeyword': {
      return ['Object']
    }
    case 'TSTypeLiteral': {
      return inferTypeLiteralType(node)
    }
    case 'TSFunctionType': {
      return ['Function']
    }
    case 'TSArrayType':
    case 'TSTupleType': {
      return ['Array']
    }
    case 'TSSymbolKeyword': {
      return ['Symbol']
    }

    case 'TSLiteralType': {
      if (node.literal.type === 'Literal') {
        switch (typeof node.literal.value) {
          case 'boolean': {
            return ['Boolean']
          }
          case 'string': {
            return ['String']
          }
          case 'number':
          case 'bigint': {
            return ['Number']
          }
        }
        if (node.literal.value instanceof RegExp) {
          return ['RegExp']
        }
      }
      return inferRuntimeTypeFromTypeNode(
        context,
        /** @type {TypeNode} */ (node)
      )
    }
    case 'TSTypeReference': {
      if (node.typeName.type === 'Identifier') {
        const variable = findVariable(
          getScope(context, /** @type {any} */ (node)),
          node.typeName.name
        )
        if (variable && variable.defs.length === 1) {
          const defNode = /** @type {TSESTreeNode} */ (variable.defs[0].node)
          if (defNode.type === 'TSInterfaceDeclaration') {
            return [`Object`]
          }
          if (defNode.type === 'TSTypeAliasDeclaration') {
            const typeAnnotation = defNode.typeAnnotation
            if (!checked.has(typeAnnotation)) {
              checked.add(typeAnnotation)
              return inferRuntimeType(context, typeAnnotation, checked)
            }
          }
          if (defNode.type === 'TSEnumDeclaration') {
            return inferEnumType(context, defNode)
          }
        }
        for (const name of [
          node.typeName.name,
          ...(node.typeName.name.startsWith('Readonly')
            ? [node.typeName.name.slice(8)]
            : [])
        ]) {
          switch (name) {
            case 'Array':
            case 'Function':
            case 'Object':
            case 'Set':
            case 'Map':
            case 'WeakSet':
            case 'WeakMap':
            case 'Date': {
              return [name]
            }
          }
        }

        switch (node.typeName.name) {
          case 'Record':
          case 'Partial':
          case 'Readonly':
          case 'Pick':
          case 'Omit':
          case 'Required':
          case 'InstanceType': {
            return ['Object']
          }
          case 'Uppercase':
          case 'Lowercase':
          case 'Capitalize':
          case 'Uncapitalize': {
            return ['String']
          }
          case 'Parameters':
          case 'ConstructorParameters': {
            return ['Array']
          }
          case 'NonNullable': {
            const typeArguments =
              'typeArguments' in node
                ? node.typeArguments
                : /** @type {any} typescript-eslint v5 */ (node).typeParameters
            if (typeArguments && typeArguments.params[0]) {
              return inferRuntimeType(
                context,
                typeArguments.params[0],
                checked
              ).filter((t) => t !== 'null')
            }
            break
          }
          case 'Extract': {
            const typeArguments =
              'typeArguments' in node
                ? node.typeArguments
                : /** @type {any} typescript-eslint v5 */ (node).typeParameters
            if (typeArguments && typeArguments.params[1]) {
              return inferRuntimeType(context, typeArguments.params[1], checked)
            }
            break
          }
          case 'Exclude':
          case 'OmitThisParameter': {
            const typeArguments =
              'typeArguments' in node
                ? node.typeArguments
                : /** @type {any} typescript-eslint v5 */ (node).typeParameters
            if (typeArguments && typeArguments.params[0]) {
              return inferRuntimeType(context, typeArguments.params[0], checked)
            }
            break
          }
        }
      }
      return inferRuntimeTypeFromTypeNode(
        context,
        /** @type {TypeNode} */ (node)
      )
    }

    case 'TSUnionType':
    case 'TSIntersectionType': {
      return inferUnionType(node)
    }

    default: {
      return inferRuntimeTypeFromTypeNode(
        context,
        /** @type {TypeNode} */ (node)
      )
    }
  }

  /**
   * @param {import('@typescript-eslint/types').TSESTree.TSUnionType|import('@typescript-eslint/types').TSESTree.TSIntersectionType} node
   * @returns {string[]}
   */
  function inferUnionType(node) {
    const types = new Set()
    for (const t of node.types) {
      for (const tt of inferRuntimeType(context, t, checked)) {
        types.add(tt)
      }
    }
    return [...types]
  }
}

/**
 * @param {import('@typescript-eslint/types').TSESTree.TSTypeLiteral} node
 * @returns {string[]}
 */
function inferTypeLiteralType(node) {
  const types = new Set()
  for (const m of node.members) {
    switch (m.type) {
      case 'TSCallSignatureDeclaration':
      case 'TSConstructSignatureDeclaration': {
        types.add('Function')
        break
      }
      default: {
        types.add('Object')
      }
    }
  }
  return types.size > 0 ? [...types] : ['Object']
}
/**
 * @param {RuleContext} context The ESLint rule context object.
 * @param {import('@typescript-eslint/types').TSESTree.TSEnumDeclaration} node
 * @returns {string[]}
 */
function inferEnumType(context, node) {
  const types = new Set()
  for (const m of node.members) {
    if (m.initializer) {
      if (m.initializer.type === 'Literal') {
        switch (typeof m.initializer.value) {
          case 'string': {
            types.add('String')
            break
          }
          case 'number':
          case 'bigint': {
            // Now it's a syntax error.
            types.add('Number')
            break
          }
          case 'boolean': {
            // Now it's a syntax error.
            types.add('Boolean')
            break
          }
        }
      } else {
        for (const type of inferRuntimeTypeFromTypeNode(
          context,
          /** @type {Expression} */ (m.initializer)
        )) {
          types.add(type)
        }
      }
    }
  }
  return types.size > 0 ? [...types] : ['Number']
}


code:
const {
  getTypeScript,
  isAny,
  isUnknown,
  isNever,
  isNull,
  isObject,
  isFunction,
  isStringLike,
  isNumberLike,
  isBooleanLike,
  isBigIntLike,
  isArrayLikeObject,
  isReferenceObject
} = require('./typescript')
/**
 * @typedef {import('@typescript-eslint/types').TSESTree.Node} TSESTreeNode
 * @typedef {import('typescript').Type} Type
 * @typedef {import('typescript').TypeChecker} TypeChecker
 * @typedef {import('typescript').Node} TypeScriptNode
 */
/**
 * @typedef {import('../index').ComponentInferTypeProp} ComponentInferTypeProp
 * @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp
 * @typedef {import('../index').ComponentInferTypeEmit} ComponentInferTypeEmit
 * @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit
 */

module.exports = {
  getComponentPropsFromTypeDefineTypes,
  getComponentEmitsFromTypeDefineTypes,
  inferRuntimeTypeFromTypeNode
}

/**
 * @typedef {object} Services
 * @property {typeof import("typescript")} ts
 * @property {Map<ESNode | TSNode | TSESTreeNode, TypeScriptNode>} tsNodeMap
 * @property {import('typescript').TypeChecker} checker
 */

/**
 * Get TypeScript parser services.
 * @param {RuleContext} context The ESLint rule context object.
 * @returns {Services|null}
 */
function getTSParserServices(context) {
  const sourceCode = context.getSourceCode()
  const tsNodeMap = sourceCode.parserServices.esTreeNodeToTSNodeMap
  if (!tsNodeMap) return null
  const hasFullTypeInformation =
    sourceCode.parserServices.hasFullTypeInformation !== false
  const checker =
    (hasFullTypeInformation &&
      sourceCode.parserServices.program &&
      sourceCode.parserServices.program.getTypeChecker()) ||
    null
  if (!checker) return null
  const ts = getTypeScript()
  if (!ts) return null

  return {
    ts,
    tsNodeMap,
    checker
  }
}

/**
 * Get all props by looking at all component's properties
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TypeNode} propsNode Type with props definition
 * @return {(ComponentInferTypeProp|ComponentUnknownProp)[]} Array of component props
 */
function getComponentPropsFromTypeDefineTypes(context, propsNode) {
  const services = getTSParserServices(context)
  const tsNode = services && services.tsNodeMap.get(propsNode)
  const type = tsNode && services.checker.getTypeAtLocation(tsNode)
  if (
    !type ||
    isAny(type) ||
    isUnknown(type) ||
    isNever(type) ||
    isNull(type)
  ) {
    return [
      {
        type: 'unknown',
        propName: null,
        node: propsNode
      }
    ]
  }
  return [...extractRuntimeProps(type, tsNode, propsNode, services)]
}

/**
 * Get all emits by looking at all component's properties
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TypeNode} emitsNode Type with emits definition
 * @return {(ComponentInferTypeEmit|ComponentUnknownEmit)[]} Array of component emits
 */
function getComponentEmitsFromTypeDefineTypes(context, emitsNode) {
  const services = getTSParserServices(context)
  const tsNode = services && services.tsNodeMap.get(emitsNode)
  const type = tsNode && services.checker.getTypeAtLocation(tsNode)
  if (
    !type ||
    isAny(type) ||
    isUnknown(type) ||
    isNever(type) ||
    isNull(type)
  ) {
    return [
      {
        type: 'unknown',
        emitName: null,
        node: emitsNode
      }
    ]
  }
  return [...extractRuntimeEmits(type, tsNode, emitsNode, services)]
}

/**
 * @param {RuleContext} context The ESLint rule context object.
 * @param {TypeNode|Expression} node
 * @returns {string[]}
 */
function inferRuntimeTypeFromTypeNode(context, node) {
  const services = getTSParserServices(context)
  const tsNode = services && services.tsNodeMap.get(node)
  const type = tsNode && services.checker.getTypeAtLocation(tsNode)
  if (!type) {
    return ['null']
  }
  return inferRuntimeTypeInternal(type, services)
}

/**
 * @param {Type} type
 * @param {TypeScriptNode} tsNode
 * @param {TypeNode} propsNode Type with props definition
 * @param {Services} services
 * @returns {IterableIterator<ComponentInferTypeProp>}
 */
function* extractRuntimeProps(type, tsNode, propsNode, services) {
  const { ts, checker } = services
  for (const property of type.getProperties()) {
    const isOptional = (property.flags & ts.SymbolFlags.Optional) !== 0
    const name = property.getName()

    const type = checker.getTypeOfSymbolAtLocation(property, tsNode)

    yield {
      type: 'infer-type',
      propName: name,
      required: !isOptional,
      node: propsNode,
      types: inferRuntimeTypeInternal(type, services)
    }
  }
}

/**
 * @param {Type} type
 * @param {Services} services
 * @returns {string[]}
 */
function inferRuntimeTypeInternal(type, services) {
  const { checker } = services
  /** @type {Set<string>} */
  const types = new Set()
  for (const targetType of iterateTypes(checker.getNonNullableType(type))) {
    if (
      isAny(targetType) ||
      isUnknown(targetType) ||
      isNever(targetType) ||
      isNull(targetType)
    ) {
      types.add('null')
    } else if (isStringLike(targetType)) {
      types.add('String')
    } else if (isNumberLike(targetType) || isBigIntLike(targetType)) {
      types.add('Number')
    } else if (isBooleanLike(targetType)) {
      types.add('Boolean')
    } else if (isFunction(targetType)) {
      types.add('Function')
    } else if (
      isArrayLikeObject(targetType) ||
      (targetType.isClassOrInterface() &&
        ['Array', 'ReadonlyArray'].includes(
          checker.getFullyQualifiedName(targetType.symbol)
        ))
    ) {
      types.add('Array')
    } else if (isObject(targetType)) {
      types.add('Object')
    }
  }

  if (types.size <= 0) types.add('null')

  return [...types]
}

/**
 * @param {Type} type
 * @param {TypeScriptNode} tsNode
 * @param {TypeNode} emitsNode Type with emits definition
 * @param {Services} services
 * @returns {IterableIterator<ComponentInferTypeEmit|ComponentUnknownEmit>}
 */
function* extractRuntimeEmits(type, tsNode, emitsNode, services) {
  const { checker } = services
  if (isFunction(type)) {
    for (const signature of type.getCallSignatures()) {
      const param = signature.getParameters()[0]
      if (!param) {
        yield {
          type: 'unknown',
          emitName: null,
          node: emitsNode
        }
        continue
      }
      const type = checker.getTypeOfSymbolAtLocation(param, tsNode)

      for (const targetType of iterateTypes(type)) {
        yield targetType.isStringLiteral()
          ? {
              type: 'infer-type',
              emitName: targetType.value,
              node: emitsNode
            }
          : {
              type: 'unknown',
              emitName: null,
              node: emitsNode
            }
      }
    }
  } else if (isObject(type)) {
    for (const property of type.getProperties()) {
      const name = property.getName()
      yield {
        type: 'infer-type',
        emitName: name,
        node: emitsNode
      }
    }
  } else {
    yield {
      type: 'unknown',
      emitName: null,
      node: emitsNode
    }
  }
}

/**
 * @param {Type} type
 * @returns {Iterable<Type>}
 */
function* iterateTypes(type) {
  if (isReferenceObject(type) && type.target !== type) {
    yield* iterateTypes(type.target)
  } else if (type.isUnion() && !isBooleanLike(type)) {
    for (const t of type.types) {
      yield* iterateTypes(t)
    }
  } else {
    yield type
  }
}