astx
Version:
super powerful structural search and replace for JavaScript and TypeScript to automate your refactoring
648 lines (565 loc) • 16.6 kB
JavaScript
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 || {}
},
}
}