index.js
function extract(pattern, part) {
  if (!pattern) throw new Error('missing pattern');
  // no match
  if (!part) return STOP;

  let term = matchTerm(pattern);
  if (term) {
    // if single __any
    if (term.type === ANY) {
      if (term.name) {
        // if __any_foo
        // get result {foo: astNode}
        let r = {};
        r[term.name] = part;
        return r;
      }
      // always match
      return {};

    // if single __str_foo
    } else if (term.type === STR) {
      if (part.type === 'Literal') {
        if (term.name) {
          // get result {foo: value}
          let r = {};
          r[term.name] = part.value;
          return r;
        }
        // always match
        return {};
      }
      // no match
      return STOP;
    }
  }


  if (Array.isArray(pattern)) {
    // no match
    if (!Array.isArray(part)) return STOP;

    if (pattern.length === 1) {
      let arrTerm = matchTerm(pattern[0]);
      if (arrTerm) {
        // if single __arr_foo
        if (arrTerm.type === ARR) {
          // find all or partial Literals in an array
          let arr = part.filter(function(it) { return it.type === 'Literal'; })
                        .map(function(it) { return it.value; });
          if (arr.length) {
            if (arrTerm.name) {
              // get result {foo: array}
              let r = {};
              r[arrTerm.name] = arr;
              return r;
            }
            // always match
            return {};
          }
          // no match
          return STOP;
        } else if (arrTerm.type === ANL) {
          if (arrTerm.name) {
            // get result {foo: nodes array}
            let r = {};
            r[arrTerm.name] = part;
            return r;
          }

          // always match
          return {};
        }
      }
    }

    if (pattern.length !== part.length) {
      // no match
      return STOP;
    }
  }

  let allResult = {};

  for (let i = 0, keys = Object.keys(pattern); i < keys.length; i++) {
    let key = keys[i];
    if (IGNORED_KEYS.indexOf(key) !== -1) continue;

    let nextPattern = pattern[key];
    let nextPart = part[key];

    if (!nextPattern || typeof nextPattern !== 'object') {
      // primitive value. string or null
      if (nextPattern === nextPart) continue;

      // no match
      return STOP;
    }

    const result = extract(nextPattern, nextPart);
    // no match
    if (result === STOP) return STOP;
    if (result) Object.assign(allResult, result);
  }

  return allResult;
}
function extract(pattern, part) {
  if (!pattern) throw new Error('missing pattern');
  // no match
  if (!part) return STOP;

  let term = matchTerm(pattern);
  if (term) {
    // if single __any
    if (term.type === ANY) {
      if (term.name) {
        // if __any_foo
        // get result {foo: astNode}
        let r = {};
        r[term.name] = part;
        return r;
      }
      // always match
      return {};

    // if single __str_foo
    } else if (term.type === STR) {
      if (part.type === 'Literal') {
        if (term.name) {
          // get result {foo: value}
          let r = {};
          r[term.name] = part.value;
          return r;
        }
        // always match
        return {};
      }
      // no match
      return STOP;
    }
  }


  if (Array.isArray(pattern)) {
    // no match
    if (!Array.isArray(part)) return STOP;

    if (pattern.length === 1) {
      let arrTerm = matchTerm(pattern[0]);
      if (arrTerm) {
        // if single __arr_foo
        if (arrTerm.type === ARR) {
          // find all or partial Literals in an array
          let arr = part.filter(function(it) { return it.type === 'Literal'; })
                        .map(function(it) { return it.value; });
          if (arr.length) {
            if (arrTerm.name) {
              // get result {foo: array}
              let r = {};
              r[arrTerm.name] = arr;
              return r;
            }
            // always match
            return {};
          }
          // no match
          return STOP;
        } else if (arrTerm.type === ANL) {
          if (arrTerm.name) {
            // get result {foo: nodes array}
            let r = {};
            r[arrTerm.name] = part;
            return r;
          }

          // always match
          return {};
        }
      }
    }

    if (pattern.length !== part.length) {
      // no match
      return STOP;
    }
  }

  let allResult = {};

  for (let i = 0, keys = Object.keys(pattern); i < keys.length; i++) {
    let key = keys[i];
    if (IGNORED_KEYS.indexOf(key) !== -1) continue;

    let nextPattern = pattern[key];
    let nextPart = part[key];

    if (!nextPattern || typeof nextPattern !== 'object') {
      // primitive value. string or null
      if (nextPattern === nextPart) continue;

      // no match
      return STOP;
    }

    const result = extract(nextPattern, nextPart);
    // no match
    if (result === STOP) return STOP;
    if (result) Object.assign(allResult, result);
  }

  return allResult;
}
function extract ( pattern , part ) { if ( ! pattern ) throw new Error ( 'missing pattern' ) ; // no match if ( ! part ) return STOP ; let term = matchTerm ( pattern ) ; if ( term ) { // if single __any if ( term . type === ANY ) { if ( term . name ) { // if __any_foo // get result {foo: astNode} let r = { } ; r [ term . name ] = part ; return r ; } // always match return { } ; // if single __str_foo } else if ( term . type === STR ) { if ( part . type === 'Literal' ) { if ( term . name ) { // get result {foo: value} let r = { } ; r [ term . name ] = part . value ; return r ; } // always match return { } ; } // no match return STOP ; } } if ( Array . isArray ( pattern ) ) { // no match if ( ! Array . isArray ( part ) ) return STOP ; if ( pattern . length === 1 ) { let arrTerm = matchTerm ( pattern [ 0 ] ) ; if ( arrTerm ) { // if single __arr_foo if ( arrTerm . type === ARR ) { // find all or partial Literals in an array let arr = part . filter ( function ( it ) { return it . type === 'Literal' ; } ) . map ( function ( it ) { return it . value ; } ) ; if ( arr . length ) { if ( arrTerm . name ) { // get result {foo: array} let r = { } ; r [ arrTerm . name ] = arr ; return r ; } // always match return { } ; } // no match return STOP ; } else if ( arrTerm . type === ANL ) { if ( arrTerm . name ) { // get result {foo: nodes array} let r = { } ; r [ arrTerm . name ] = part ; return r ; } // always match return { } ; } } } if ( pattern . length !== part . length ) { // no match return STOP ; } } let allResult = { } ; for ( let i = 0 , keys = Object . keys ( pattern ) ; i < keys . length ; i ++ ) { let key = keys [ i ] ; if ( IGNORED_KEYS . indexOf ( key ) !== - 1 ) continue ; let nextPattern = pattern [ key ] ; let nextPart = part [ key ] ; if ( ! nextPattern || typeof nextPattern !== 'object' ) { // primitive value. string or null if ( nextPattern === nextPart ) continue ; // no match return STOP ; } const result = extract ( nextPattern , nextPart ) ; // no match if ( result === STOP ) return STOP ; if ( result ) Object . assign ( allResult , result ) ; } return allResult ; }
Extract info from a partial estree syntax tree, see astMatcher for pattern format
@param pattern The pattern used on matching
@param part The target partial syntax tree
@return Returns named matches, or false.
Extract info from a partial estree syntax tree see astMatcher for pattern format