astx
Version:
super powerful structural search and replace for JavaScript and TypeScript to automate your refactoring
525 lines (450 loc) • 13.5 kB
JavaScript
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault')
var _typeof = require('@babel/runtime/helpers/typeof')
Object.defineProperty(exports, '__esModule', {
value: true,
})
exports.convertWithCaptures = convertWithCaptures
exports.createMatch = createMatch
exports['default'] = find
var _slicedToArray2 = _interopRequireDefault(
require('@babel/runtime/helpers/slicedToArray')
)
var _defineProperty2 = _interopRequireDefault(
require('@babel/runtime/helpers/defineProperty')
)
var _toConsumableArray2 = _interopRequireDefault(
require('@babel/runtime/helpers/toConsumableArray')
)
var _lodash = require('lodash')
var _compileMatcher = _interopRequireWildcard(require('./compileMatcher'))
var _ensureArray = _interopRequireDefault(require('./util/ensureArray'))
var _forEachNode = _interopRequireDefault(require('./util/forEachNode'))
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 convertWithCaptures(matches) {
return _compileMatcher.mergeCaptures.apply(
void 0,
(0, _toConsumableArray2['default'])(
(0, _ensureArray['default'])(matches).map(function (_ref) {
var pathCaptures = _ref.pathCaptures,
arrayPathCaptures = _ref.arrayPathCaptures,
stringCaptures = _ref.stringCaptures
return {
captures: pathCaptures,
arrayCaptures: arrayPathCaptures,
stringCaptures: stringCaptures,
}
})
)
)
}
function createMatch(paths, result) {
var _paths$
if (!result) {
throw new Error('result must be defined')
}
var captures = result.captures,
arrayCaptures = result.arrayCaptures,
stringCaptures = result.stringCaptures
var match = Array.isArray(paths)
? {
type: 'nodes',
node:
(_paths$ = paths[0]) === null || _paths$ === void 0
? void 0
: _paths$.node,
path: paths[0],
nodes: paths.map(function (p) {
return p.node
}),
paths: paths,
}
: {
type: 'node',
node: paths.node,
path: paths,
nodes: [paths.node],
paths: [paths],
}
if (captures) {
match.pathCaptures = captures
match.captures = (0, _lodash.mapValues)(captures, function (path) {
return path.node
})
}
if (arrayCaptures) {
match.arrayPathCaptures = arrayCaptures
match.arrayCaptures = (0, _lodash.mapValues)(
arrayCaptures,
function (paths) {
return paths.map(function (path) {
return path.node
})
}
)
}
if (stringCaptures) match.stringCaptures = stringCaptures
return match
}
function find(paths, pattern, options) {
var t = options.backend.t
var n = t.namedTypes
if (Array.isArray(pattern) && pattern.length === 1) pattern = pattern[0]
if (Array.isArray(pattern)) {
if (!n.Statement.check(pattern[0].value)) {
throw new Error('pattern array must be an array of statements')
}
return findStatements(paths, pattern, options)
}
var matcher = (0, _compileMatcher['default'])(pattern, options)
var matches = []
var nodeTypes = (0, _ensureArray['default'])(matcher.nodeType || 'Node')
;(0, _forEachNode['default'])(
t,
(0, _ensureArray['default'])(paths),
nodeTypes,
function (path) {
var _options$matchSoFar
var result = matcher.match(
path,
(_options$matchSoFar =
options === null || options === void 0
? void 0
: options.matchSoFar) !== null && _options$matchSoFar !== void 0
? _options$matchSoFar
: null
)
if (result) matches.push(createMatch(path, result))
}
)
return matches
}
function findStatements(paths, pattern, options) {
var _options$matchSoFar2
var t = options.backend.t
var matchers = pattern.map(function (queryElem) {
return (0, _compileMatcher['default'])(queryElem, options)
})
var firstNonArrayCaptureIndex = matchers.findIndex(function (m) {
return !m.arrayPlaceholder
})
if (firstNonArrayCaptureIndex < 0) {
throw new Error(
'pattern would match every single array of statements, this is unsupported'
)
}
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) {
if (arrayIndex === paths.length || matcherIndex === matchers.length) {
return remainingElements(matcherIndex) === 0
? [matchSoFar || {}, [arrayIndex, arrayIndex]]
: null
}
var matcher = matchers[matcherIndex]
var arrayPlaceholder = matcher.arrayPlaceholder
if (arrayPlaceholder) {
if (matcherIndex === matchers.length - 1) {
return [
(0, _compileMatcher.mergeCaptures)(matchSoFar, {
arrayCaptures: (0, _defineProperty2['default'])(
{},
arrayPlaceholder,
paths.slice(sliceStart)
),
}),
[sliceStart, paths.length],
]
}
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 && matcherIndex !== firstNonArrayCaptureIndex
? paths.length - remainingElements(matcherIndex + 1)
: arrayIndex + 1
for (var i = arrayIndex; i < end; i++) {
matchSoFar = matcher.match(paths[i], origMatchSoFar)
if (!matchSoFar) continue
if (prevArrayPlaceholder) {
matchSoFar = (0, _compileMatcher.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[0], [i, restMatch[1][1]]]
}
}
return null
}
var blocks = []
;(0, _forEachNode['default'])(
t,
(0, _ensureArray['default'])(paths),
['Block'],
function (path) {
blocks.push(path)
}
)
blocks.reverse()
var matches = []
var initialMatch =
(_options$matchSoFar2 =
options === null || options === void 0 ? void 0 : options.matchSoFar) !==
null && _options$matchSoFar2 !== void 0
? _options$matchSoFar2
: null
for (var _i = 0, _blocks = blocks; _i < _blocks.length; _i++) {
var block = _blocks[_i]
var body = block.get('body').filter(function () {
return true
})
var end = body.length - remainingElements(firstNonArrayCaptureIndex + 1)
var sliceStart = 0
for (var arrayIndex = 0; arrayIndex < end; arrayIndex++) {
var match = matchElem(
body,
sliceStart,
arrayIndex,
firstNonArrayCaptureIndex,
initialMatch
)
if (match) {
var _result, _result2, _result3
var result = match[0]
var start = firstNonArrayCaptureIndex > 0 ? 0 : match[1][0]
var _match$ = (0, _slicedToArray2['default'])(match[1], 2),
_end = _match$[1] // 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 _result4, _result4$arrayCapture
var matcher = _step.value
var arrayPlaceholder = matcher.arrayPlaceholder
if (!arrayPlaceholder) continue
if (
!(
(_result4 = result) !== null &&
_result4 !== void 0 &&
(_result4$arrayCapture = _result4.arrayCaptures) !== null &&
_result4$arrayCapture !== void 0 &&
_result4$arrayCapture[arrayPlaceholder]
)
)
result = (0, _compileMatcher.mergeCaptures)(result, {
arrayCaptures: (0, _defineProperty2['default'])(
{},
arrayPlaceholder,
[]
),
})
}
} catch (err) {
_iterator.e(err)
} finally {
_iterator.f()
}
var _paths = body.slice(start, _end)
var finalMatch = {
type: 'nodes',
path: _paths[0],
node: _paths[0].node,
paths: _paths,
nodes: _paths.map(function (p) {
return p.node
}),
}
if (
(_result = result) !== null &&
_result !== void 0 &&
_result.captures
) {
finalMatch.pathCaptures = result.captures
finalMatch.captures = (0, _lodash.mapValues)(
result.captures,
function (p) {
return p.node
}
)
}
if (
(_result2 = result) !== null &&
_result2 !== void 0 &&
_result2.arrayCaptures
) {
finalMatch.arrayPathCaptures = result.arrayCaptures
finalMatch.arrayCaptures = (0, _lodash.mapValues)(
result.arrayCaptures,
function (paths) {
return paths.map(function (p) {
return p.node
})
}
)
}
if (
(_result3 = result) !== null &&
_result3 !== void 0 &&
_result3.stringCaptures
) {
finalMatch.stringCaptures = result.stringCaptures
}
matches.push(finalMatch) // prevent overlapping matches
sliceStart = _end
arrayIndex = _end - 1
}
}
}
return matches
}