UNPKG

astx

Version:

super powerful structural search and replace for JavaScript and TypeScript to automate your refactoring

648 lines (565 loc) 16.6 kB
'use strict' var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') var _typeof = require('@babel/runtime/helpers/typeof') Object.defineProperty(exports, '__esModule', { value: true, }) exports['default'] = compileGenericArrayMatcher var _defineProperty2 = _interopRequireDefault( require('@babel/runtime/helpers/defineProperty') ) var _slicedToArray2 = _interopRequireDefault( require('@babel/runtime/helpers/slicedToArray') ) var _CompilePathError = _interopRequireDefault( require('../util/CompilePathError') ) var _ = _interopRequireWildcard(require('.')) var _indentDebug = _interopRequireDefault(require('./indentDebug')) function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== 'function') return null var cacheBabelInterop = new WeakMap() var cacheNodeInterop = new WeakMap() return (_getRequireWildcardCache = function _getRequireWildcardCache( nodeInterop ) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop })(nodeInterop) } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj } if ( obj === null || (_typeof(obj) !== 'object' && typeof obj !== 'function') ) { return { default: obj, } } var cache = _getRequireWildcardCache(nodeInterop) if (cache && cache.has(obj)) { return cache.get(obj) } var newObj = {} var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor for (var key in obj) { if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc) } else { newObj[key] = obj[key] } } } newObj['default'] = obj if (cache) { cache.set(obj, newObj) } return newObj } function _createForOfIteratorHelper(o, allowArrayLike) { var it = (typeof Symbol !== 'undefined' && o[Symbol.iterator]) || o['@@iterator'] if (!it) { if ( Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || (allowArrayLike && o && typeof o.length === 'number') ) { if (it) o = it var i = 0 var F = function F() {} return { s: F, n: function n() { if (i >= o.length) return { done: true, } return { done: false, value: o[i++], } }, e: function e(_e) { throw _e }, f: F, } } throw new TypeError( 'Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.' ) } var normalCompletion = true, didErr = false, err return { s: function s() { it = it.call(o) }, n: function n() { var step = it.next() normalCompletion = step.done return step }, e: function e(_e2) { didErr = true err = _e2 }, f: function f() { try { if (!normalCompletion && it['return'] != null) it['return']() } finally { if (didErr) throw err } }, } } function _unsupportedIterableToArray(o, minLen) { if (!o) return if (typeof o === 'string') return _arrayLikeToArray(o, minLen) var n = Object.prototype.toString.call(o).slice(8, -1) if (n === 'Object' && o.constructor) n = o.constructor.name if (n === 'Map' || n === 'Set') return Array.from(o) if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen) } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i] } return arr2 } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object) if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object) enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable })), keys.push.apply(keys, symbols) } return keys } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {} i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { ;(0, _defineProperty2['default'])(target, key, source[key]) }) : Object.getOwnPropertyDescriptors ? Object.defineProperties( target, Object.getOwnPropertyDescriptors(source) ) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty( target, key, Object.getOwnPropertyDescriptor(source, key) ) }) } return target } var defaultUnorderedFields = {} for ( var _i = 0, _arr = [ ['ClassBody', 'body'], ['ClassDeclaration', 'implements'], ['DeclareClass', 'implements'], ['DeclareExportDeclaration', 'specifiers'], ['DeclareInterface', 'extends'], ['EnumDeclaration', 'body'], ['ExportNamedDeclaration', 'specifiers'], ['ImportDeclaration', 'specifiers'], ['InterfaceDeclaration', 'extends'], ['IntersectionTypeAnnotation', 'types'], ['JSXOpeningElement', 'attributes'], ['ObjectExpression', 'properties'], ['ObjectPattern', 'properties'], ['ObjectTypeAnnotation', 'properties'], ['TSEnumDeclaration', 'members'], ['TSInterfaceBody', 'body'], ['TSInterfaceDeclaration', 'extends'], ['TSIntersectionType', 'types'], ['TSTypeLiteral', 'members'], ['TSUnionType', 'types'], ['UnionTypeAnnotation', 'types'], ]; _i < _arr.length; _i++ ) { var _arr$_i = (0, _slicedToArray2['default'])(_arr[_i], 2), type = _arr$_i[0], field = _arr$_i[1] var forType = defaultUnorderedFields[type] || (defaultUnorderedFields[type] = {}) forType[field] = true } function getDefaultUnordered(path) { var _defaultUnorderedFiel if (Array.isArray(path)) { var _path$ var parent = (_path$ = path[0]) === null || _path$ === void 0 ? void 0 : _path$.parentPath if (!parent) return false return getDefaultUnordered(parent) } if (!path.node || !path.name) return false return Boolean( (_defaultUnorderedFiel = defaultUnorderedFields[path.node.type]) === null || _defaultUnorderedFiel === void 0 ? void 0 : _defaultUnorderedFiel[path.name] ) } function compileGenericArrayMatcher(path, compileOptions) { var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, _ref$compileElemMatch = _ref.compileElemMatcher, compileElemMatcher = _ref$compileElemMatch === void 0 ? _['default'] : _ref$compileElemMatch, _ref$defaultUnordered = _ref.defaultUnordered, defaultUnordered = _ref$defaultUnordered === void 0 ? getDefaultUnordered(path) : _ref$defaultUnordered, _ref$skipElement = _ref.skipElement, skipElement = _ref$skipElement === void 0 ? function () { return false } : _ref$skipElement var paths = Array.isArray(path) ? path : path.filter(function () { return true }) var pattern = path.map(function (p) { return p.node }) var debug = compileOptions.debug var elemOptions = _objectSpread( _objectSpread({}, compileOptions), {}, { debug: (0, _indentDebug['default'])(debug, 2), } ) var matchers = pattern.map(function (value, i) { return compileElemMatcher(paths[i], elemOptions) }) assertArrayMatchersValid(matchers) var unordered = matchers.some(function (m) { return m.restPlaceholder || m.placeholder === '$Unordered' }) || (defaultUnordered && !matchers.some(function (m) { return m.placeholder === '$Ordered' || m.arrayPlaceholder })) matchers = matchers.filter(function (m) { return m.placeholder !== '$Ordered' && m.placeholder !== '$Unordered' }) if (unordered) { return compileUnorderedArrayMatcher(paths, compileOptions, { matchers: matchers, }) } if ( matchers.some(function (m) { return m.placeholder || m.arrayPlaceholder }) ) { return compileOrderedArrayMatcher(paths, compileOptions, { matchers: matchers, skipElement: skipElement, }) } return compileExactArrayMatcher(paths, compileOptions, { matchers: matchers, skipElement: skipElement, }) } function assertArrayMatchersValid(matchers) { var otherMatchers = [] var arrayMatcherCount = 0 var restMatcher for (var i = 0; i < matchers.length; i++) { if (matchers[i].restPlaceholder) { if (restMatcher) { throw new _CompilePathError['default']( "can't have two or more rest matchers as siblings", matchers[i].pattern ) } else if (arrayMatcherCount) { throw new _CompilePathError['default']( "can't mix array and rest matchers", matchers[i].pattern ) } else { restMatcher = matchers[i] } } else if (matchers[i].arrayPlaceholder) { if (restMatcher) { throw new _CompilePathError['default']( "can't mix array and rest matchers", matchers[i].pattern ) } arrayMatcherCount++ } else { otherMatchers.push(matchers[i]) } } } function compileOrderedArrayMatcher(paths, compileOptions, _ref2) { var matchers = _ref2.matchers, _ref2$skipElement = _ref2.skipElement, skipElement = _ref2$skipElement === void 0 ? function () { return false } : _ref2$skipElement var debug = compileOptions.debug function remainingElements(matcherIndex) { var count = 0 for (var i = matcherIndex; i < matchers.length; i++) { if (!matchers[i].arrayPlaceholder) count++ } return count } function matchElem(paths, sliceStart, arrayIndex, matcherIndex, matchSoFar) { while (arrayIndex < paths.length && skipElement(paths[arrayIndex])) { arrayIndex++ } if (arrayIndex === paths.length) { return remainingElements(matcherIndex) === 0 ? matchSoFar || {} : null } if (matcherIndex === matchers.length) return null var matcher = matchers[matcherIndex] var arrayPlaceholder = matcher.arrayPlaceholder if (arrayPlaceholder) { if (matcherIndex === matchers.length - 1) { return (0, _.mergeCaptures)(matchSoFar, { arrayCaptures: (0, _defineProperty2['default'])( {}, arrayPlaceholder, paths.slice(sliceStart) ), }) } return matchElem( paths, sliceStart, arrayIndex, matcherIndex + 1, matchSoFar ) } else { var _matchers var origMatchSoFar = matchSoFar var prevArrayPlaceholder = (_matchers = matchers[matcherIndex - 1]) === null || _matchers === void 0 ? void 0 : _matchers.arrayPlaceholder var end = prevArrayPlaceholder ? paths.length - remainingElements(matcherIndex + 1) : arrayIndex + 1 for (var i = arrayIndex; i < end; i++) { var elemPath = paths[i] if (skipElement(elemPath)) continue matchSoFar = matcher.match(elemPath, origMatchSoFar) if (!matchSoFar) continue if (prevArrayPlaceholder) { matchSoFar = (0, _.mergeCaptures)(matchSoFar, { arrayCaptures: (0, _defineProperty2['default'])( {}, prevArrayPlaceholder, paths.slice(sliceStart, i) ), }) } var restMatch = matchElem( paths, i + 1, i + 1, matcherIndex + 1, matchSoFar ) if (restMatch) return restMatch } } return null } return { pattern: paths, match: function match(path, matchSoFar) { debug('Array (ordered)') if (!Array.isArray(path.value)) return null var paths = path.filter(function () { return true }) var result = matchElem(paths, 0, 0, 0, matchSoFar) if (!result) return result // make sure all * captures are present in results // (if there are more than one adjacent *, all captured paths will be in the // last one and the rest will be empty) var _iterator = _createForOfIteratorHelper(matchers), _step try { for (_iterator.s(); !(_step = _iterator.n()).done; ) { var _result, _result$arrayCaptures var matcher = _step.value var arrayPlaceholder = matcher.arrayPlaceholder if (!arrayPlaceholder) continue if ( !( (_result = result) !== null && _result !== void 0 && (_result$arrayCaptures = _result.arrayCaptures) !== null && _result$arrayCaptures !== void 0 && _result$arrayCaptures[arrayPlaceholder] ) ) result = (0, _.mergeCaptures)(result, { arrayCaptures: (0, _defineProperty2['default'])( {}, arrayPlaceholder, [] ), }) } } catch (err) { _iterator.e(err) } finally { _iterator.f() } return result }, } } function compileUnorderedArrayMatcher(paths, compileOptions, _ref3) { var matchers = _ref3.matchers, _ref3$skipElement = _ref3.skipElement, skipElement = _ref3$skipElement === void 0 ? function () { return false } : _ref3$skipElement var debug = compileOptions.debug var restMatcher = matchers.find(function (m) { return m.restPlaceholder }) matchers = matchers.filter(function (m) { return !m.restPlaceholder }) var restPlaceholder = restMatcher === null || restMatcher === void 0 ? void 0 : restMatcher.restPlaceholder return { pattern: paths, match: function match(path, result) { debug('Array (unordered)') if (!Array.isArray(path.value)) return null var paths = path.filter(function () { return true }) var _iterator2 = _createForOfIteratorHelper(matchers), _step2 try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) { var m = _step2.value var i = void 0 var found = false for (i = 0; i < paths.length; i++) { if (skipElement(paths[i])) { i++ continue } var match = m.match(paths[i], result) if (!match) continue result = match paths.splice(i, 1) found = true break } if (!found) { return null } } } catch (err) { _iterator2.e(err) } finally { _iterator2.f() } if (restPlaceholder) { return (0, _.mergeCaptures)(result, { arrayCaptures: (0, _defineProperty2['default'])( {}, restPlaceholder, paths ), }) } else { if (paths.length) { return null } return result || {} } }, } } function compileExactArrayMatcher(paths, compileOptions, _ref4) { var matchers = _ref4.matchers, _ref4$skipElement = _ref4.skipElement, skipElement = _ref4$skipElement === void 0 ? function () { return false } : _ref4$skipElement var debug = compileOptions.debug return { pattern: paths, match: function match(path, matchSoFar) { debug('Array (exact)') if (!Array.isArray(path.value)) return null var paths = path.filter(function (p) { return !skipElement(p) }) var m = 0, i = 0 while (i < paths.length || m < matchers.length) { debug(' [%d]', i) if (i >= paths.length || m >= matchers.length) { debug(' length mismatch') return null } matchSoFar = matchers[m].match(paths[i], matchSoFar) if (!matchSoFar) return null m++ i++ } return matchSoFar || {} }, } }