1
1
mirror of https://github.com/github/semantic.git synced 2024-12-26 00:12:29 +03:00

Merge remote-tracking branch 'origin/master' into what-the-text

This commit is contained in:
Rob Rix 2017-02-10 13:10:46 -05:00
commit d28e0f23ac
22 changed files with 1080 additions and 915 deletions

View File

@ -21,7 +21,6 @@ import Control.Monad.Random
import Control.Monad.State
import Data.Align.Generic
import Data.Array
import Data.Functor.Both hiding (fst, snd)
import Data.Functor.Listable
import Data.Hashable
import qualified Data.IntMap as IntMap
@ -46,17 +45,16 @@ type DiffTerms f fields = Term f (Record fields) -> Term f (Record fields) -> Ma
-- which completes in log-linear time.
--
-- This implementation is based on the paper [_RWS-Diff—Flexible and Efficient Change Detection in Hierarchical Data_](https://github.com/github/semantic-diff/files/325837/RWS-Diff.Flexible.and.Efficient.Change.Detection.in.Hierarchical.Data.pdf).
rws :: forall f fields label.
(GAlign f, Traversable f, Eq (f (Term f Category)), Hashable label, HasField fields Category)
rws :: forall f fields.
(GAlign f, Traversable f, Eq (f (Term f Category)), HasField fields Category, HasField fields (Maybe FeatureVector))
=> DiffTerms f fields -- ^ A function which compares a pair of terms recursively, returning 'Just' their diffed value if appropriate, or 'Nothing' if they should not be compared.
-> Label f fields label
-> [Term f (Record fields)] -- ^ The list of old terms.
-> [Term f (Record fields)] -- ^ The list of new terms.
-> [Diff f (Record fields)] -- ^ The resulting list of similarity-matched diffs.
rws compare getLabel as bs
rws compare as bs
| null as, null bs = []
| null as = inserting <$> bs
| null bs = deleting <$> as
| null as = inserting . eraseFeatureVector <$> bs
| null bs = deleting . eraseFeatureVector <$> as
| otherwise =
-- Construct a State who's final value is a list of (Int, Diff leaf (Record fields))
-- and who's final state is (Int, IntMap UmappedTerm, IntMap UmappedTerm)
@ -70,16 +68,16 @@ rws compare getLabel as bs
where
minimumTermIndex = pred . maybe 0 getMin . getOption . foldMap (Option . Just . Min . termIndex)
sesDiffs = eitherCutoff 1 <$> SES.ses replaceIfEqual cost as bs
sesDiffs = SES.ses replaceIfEqual cost as bs
(featurizedAs, featurizedBs, _, _, countersAndDiffs, allDiffs) =
foldl' (\(as, bs, counterA, counterB, diffs, allDiffs) diff -> case runFree diff of
Pure (Right (Delete term)) ->
Pure (Delete term) ->
(as <> pure (featurize counterA term), bs, succ counterA, counterB, diffs, allDiffs <> pure None)
Pure (Right (Insert term)) ->
Pure (Insert term) ->
(as, bs <> pure (featurize counterB term), counterA, succ counterB, diffs, allDiffs <> pure (Term (featurize counterB term)))
syntax -> let diff' = free syntax >>= either identity pure in
(as, bs, succ counterA, succ counterB, diffs <> pure (These counterA counterB, diff'), allDiffs <> pure (Index counterA))
_ ->
(as, bs, succ counterA, succ counterB, diffs <> pure (These counterA counterB, diff), allDiffs <> pure (Index counterA))
) ([], [], 0, 0, [], []) sesDiffs
findNearestNeighbourToDiff :: TermOrIndexOrNone (UnmappedTerm f fields)
@ -151,23 +149,23 @@ rws compare getLabel as bs
-- Possibly replace terms in a diff.
replaceIfEqual :: Term f (Record fields) -> Term f (Record fields) -> Maybe (Diff f (Record fields))
replaceIfEqual a b
| (category <$> a) == (category <$> b) = hylo wrap runCofree <$> zipTerms a b
| (category <$> a) == (category <$> b) = hylo wrap runCofree <$> zipTerms (eraseFeatureVector a) (eraseFeatureVector b)
| otherwise = Nothing
cost = iter (const 0) . (1 <$)
eitherCutoff :: Integer
-> Diff f (Record fields)
-> Free (TermF f (Both (Record fields)))
(Either (Diff f (Record fields)) (Patch (Term f (Record fields))))
eitherCutoff n diff | n <= 0 = pure (Left diff)
eitherCutoff n diff = free . bimap Right (eitherCutoff (pred n)) $ runFree diff
kdas = KdTree.build (elems . feature) featurizedAs
kdbs = KdTree.build (elems . feature) featurizedBs
featurize :: Int -> Term f (Record fields) -> UnmappedTerm f fields
featurize index term = UnmappedTerm index (rhead . extract $ defaultFeatureVectorDecorator getLabel term) term
featurize index term = UnmappedTerm index (let Just v = getField (extract term) in v) (eraseFeatureVector term)
eraseFeatureVector :: Term f (Record fields) -> Term f (Record fields)
eraseFeatureVector term = let record :< functor = runCofree term in
cofree (setFeatureVector record Nothing :< functor)
setFeatureVector :: Record fields -> Maybe FeatureVector -> Record fields
setFeatureVector = setField
toMap = IntMap.fromList . fmap (termIndex &&& identity)
@ -241,17 +239,17 @@ defaultFeatureVectorDecorator
:: (Hashable label, Traversable f)
=> Label f fields label
-> Term f (Record fields)
-> Term f (Record (FeatureVector ': fields))
-> Term f (Record (Maybe FeatureVector ': fields))
defaultFeatureVectorDecorator getLabel = featureVectorDecorator getLabel defaultP defaultQ defaultD
-- | Annotates a term with a feature vector at each node, parameterized by stem length, base width, and feature vector dimensions.
featureVectorDecorator :: (Hashable label, Traversable f) => Label f fields label -> Int -> Int -> Int -> Term f (Record fields) -> Term f (Record (FeatureVector ': fields))
featureVectorDecorator :: (Hashable label, Traversable f) => Label f fields label -> Int -> Int -> Int -> Term f (Record fields) -> Term f (Record (Maybe FeatureVector ': fields))
featureVectorDecorator getLabel p q d
= cata collect
. pqGramDecorator getLabel p q
where collect ((gram :. rest) :< functor) = cofree ((foldl' addSubtermVector (unitVector d (hash gram)) functor :. rest) :< functor)
addSubtermVector :: FeatureVector -> Term f (Record (FeatureVector ': fields)) -> FeatureVector
addSubtermVector = flip $ addVectors . rhead . headF . runCofree
where collect ((gram :. rest) :< functor) = cofree ((foldl' addSubtermVector (Just (unitVector d (hash gram))) functor :. rest) :< functor)
addSubtermVector :: Functor f => Maybe FeatureVector -> Term f (Record (Maybe FeatureVector ': fields)) -> Maybe FeatureVector
addSubtermVector v term = addVectors <$> v <*> rhead (extract term)
addVectors :: Num a => Array Int a -> Array Int a -> Array Int a
addVectors as bs = listArray (0, d - 1) (fmap (\ i -> as ! i + bs ! i) [0..(d - 1)])
@ -300,7 +298,7 @@ stripDiff
:: (Functor f, Functor g)
=> Free (TermF f (g (Record (h ': t)))) (Patch (Term f (Record (h ': t))))
-> Free (TermF f (g (Record t))) (Patch (Term f (Record t)))
stripDiff = iter (\ (h :< f) -> wrap (fmap rtail h :< f)) . fmap (pure . fmap stripTerm)
stripDiff = mapAnnotations rtail
-- Instances

View File

@ -41,3 +41,20 @@ beforeTerm = mergeMaybe before Both.fst
-- | Recover the after state of a diff.
afterTerm :: Mergeable f => Diff f annotation -> Maybe (Term f annotation)
afterTerm = mergeMaybe after Both.snd
-- | Map a function over the annotations in a diff, whether in diff or term nodes.
--
-- Typed using Free so as to accommodate Free structures derived from diffs that dont fit into the Diff type synonym.
mapAnnotations :: (Functor f, Functor g)
=> (annotation -> annotation')
-> Free (TermF f (g annotation)) (Patch (Term f annotation))
-> Free (TermF f (g annotation')) (Patch (Term f annotation'))
mapAnnotations f = iter (\ (h :< functor) -> wrap (fmap f h :< functor)) . fmap (pure . fmap (fmap f))
-- | Map a function over the annotations of a single diff node, if it is in Free.
modifyAnnotations :: (Functor f, Functor g) => (annotation -> annotation) -> Free (TermF f (g annotation)) a -> Free (TermF f (g annotation)) a
modifyAnnotations f r = case runFree r of
Free (ga :< functor) -> wrap (fmap f ga :< functor)
_ -> r

View File

@ -4,6 +4,7 @@ module Diffing where
import Prologue hiding (fst, snd)
import Category
import Data.Functor.Both
import Data.RandomWalkSimilarity (defaultFeatureVectorDecorator, stripDiff)
import Data.Record
import qualified Data.Text.IO as TextIO
import Data.These
@ -39,15 +40,15 @@ diffFiles :: (HasField fields Category, HasField fields Cost)
-> Both SourceBlob
-> IO Output
diffFiles parse render sourceBlobs = do
terms <- traverse parse sourceBlobs
pure $! render sourceBlobs (diffTerms' terms)
terms <- traverse (fmap (defaultFeatureVectorDecorator getLabel) . parse) sourceBlobs
pure $! render sourceBlobs (stripDiff (diffTerms' terms))
where
diffTerms' terms = case runBothWith areNullOids sourceBlobs of
(True, False) -> pure $ Insert (snd terms)
(False, True) -> pure $ Delete (fst terms)
(_, _) ->
runBothWith (diffTerms construct compareCategoryEq diffCostWithCachedTermCosts getLabel) terms
runBothWith (diffTerms construct compareCategoryEq diffCostWithCachedTermCosts) terms
areNullOids a b = (hasNullOid a, hasNullOid b)
hasNullOid blob = oid blob == nullOid || Source.null (source blob)
construct (info :< syntax) = free (Free ((setCost <$> info <*> sumCost syntax) :< syntax))

View File

@ -23,29 +23,27 @@ type Comparable f annotation = Term f annotation -> Term f annotation -> Bool
type DiffConstructor f annotation = TermF f (Both annotation) (Diff f annotation) -> Diff f annotation
-- | Diff two terms recursively, given functions characterizing the diffing.
diffTerms :: (Eq leaf, HasField fields Category, Hashable label)
diffTerms :: (Eq leaf, HasField fields Category, HasField fields (Maybe FeatureVector))
=> DiffConstructor (Syntax leaf) (Record fields) -- ^ A function to wrap up & possibly annotate every produced diff.
-> Comparable (Syntax leaf) (Record fields) -- ^ A function to determine whether or not two terms should even be compared.
-> SES.Cost (SyntaxDiff leaf fields) -- ^ A function to compute the cost of a given diff node.
-> RWS.Label (Syntax leaf) fields label
-> SyntaxTerm leaf fields -- ^ A term representing the old state.
-> SyntaxTerm leaf fields -- ^ A term representing the new state.
-> SyntaxDiff leaf fields
diffTerms construct comparable cost getLabel a b = fromMaybe (replacing a b) $ diffComparableTerms construct comparable cost getLabel a b
diffTerms construct comparable cost a b = fromMaybe (replacing a b) $ diffComparableTerms construct comparable cost a b
-- | Diff two terms recursively, given functions characterizing the diffing. If the terms are incomparable, returns 'Nothing'.
diffComparableTerms :: (Eq leaf, HasField fields Category, Hashable label)
diffComparableTerms :: (Eq leaf, HasField fields Category, HasField fields (Maybe FeatureVector))
=> DiffConstructor (Syntax leaf) (Record fields)
-> Comparable (Syntax leaf) (Record fields)
-> SES.Cost (SyntaxDiff leaf fields)
-> RWS.Label (Syntax leaf) fields label
-> SyntaxTerm leaf fields
-> SyntaxTerm leaf fields
-> Maybe (SyntaxDiff leaf fields)
diffComparableTerms construct comparable cost getLabel = recur
diffComparableTerms construct comparable cost = recur
where recur a b
| (category <$> a) == (category <$> b) = hylo construct runCofree <$> zipTerms a b
| comparable a b = runAlgorithm construct recur cost getLabel (Just <$> algorithmWithTerms construct a b)
| comparable a b = runAlgorithm construct recur cost (Just <$> algorithmWithTerms construct a b)
| otherwise = Nothing
-- | Construct an algorithm to diff a pair of terms.
@ -101,16 +99,15 @@ algorithmWithTerms construct t1 t2 = maybe (recursively t1 t2) (fmap annotate) $
(Nothing, Nothing) -> Nothing
-- | Run an algorithm, given functions characterizing the evaluation.
runAlgorithm :: (GAlign f, HasField fields Category, Eq (f (Cofree f Category)), Traversable f, Hashable label)
runAlgorithm :: (GAlign f, HasField fields Category, Eq (f (Cofree f Category)), Traversable f, HasField fields (Maybe FeatureVector))
=> (CofreeF f (Both (Record fields)) (Free (CofreeF f (Both (Record fields))) (Patch (Cofree f (Record fields)))) -> Free (CofreeF f (Both (Record fields))) (Patch (Cofree f (Record fields)))) -- ^ A function to wrap up & possibly annotate every produced diff.
-> (Cofree f (Record fields) -> Cofree f (Record fields) -> Maybe (Free (CofreeF f (Both (Record fields))) (Patch (Cofree f (Record fields))))) -- ^ A function to diff two subterms recursively, if they are comparable, or else return 'Nothing'.
-> SES.Cost (Free (CofreeF f (Both (Record fields))) (Patch (Cofree f (Record fields)))) -- ^ A function to compute the cost of a given diff node.
-> RWS.Label f fields label
-> Algorithm (Cofree f (Record fields)) (Free (CofreeF f (Both (Record fields))) (Patch (Cofree f (Record fields)))) a -- ^ The algorithm to run.
-> a
runAlgorithm construct recur cost getLabel = iterAp $ \case
runAlgorithm construct recur cost = iterAp $ \case
Recursive a b f -> f (maybe (replacing a b) (construct . (both (extract a) (extract b) :<)) $ do
aligned <- galign (unwrap a) (unwrap b)
traverse (these (Just . deleting) (Just . inserting) recur) aligned)
ByIndex as bs f -> f (ses recur cost as bs)
BySimilarity as bs f -> f (rws recur getLabel as bs)
BySimilarity as bs f -> f (rws recur as bs)

View File

@ -13,7 +13,6 @@ import Patch
import Prologue
import Syntax
import Term
import Diffing (getLabel)
import Test.Hspec
import Test.Hspec.LeanCheck
@ -36,17 +35,17 @@ spec = parallel $ do
\ (as, bs) -> let tas = decorate <$> (unListableF <$> as :: [SyntaxTerm String '[Category]])
tbs = decorate <$> (unListableF <$> bs :: [SyntaxTerm String '[Category]])
root = cofree . ((Program :. Nil) :<) . Indexed
diff = wrap (pure (Program :. Nil) :< Indexed (stripDiff <$> rws compare getLabel tas tbs)) in
diff = wrap (pure (Program :. Nil) :< Indexed (stripDiff <$> rws compare tas tbs)) in
(beforeTerm diff, afterTerm diff) `shouldBe` (Just (root (stripTerm <$> tas)), Just (root (stripTerm <$> tbs)))
it "produces unbiased insertions within branches" $
let (a, b) = (decorate (cofree ((StringLiteral :. Nil) :< Indexed [ cofree ((StringLiteral :. Nil) :< Leaf ("a" :: Text)) ])), decorate (cofree ((StringLiteral :. Nil) :< Indexed [ cofree ((StringLiteral :. Nil) :< Leaf "b") ]))) in
fmap stripDiff (rws compare getLabel [ b ] [ a, b ]) `shouldBe` fmap stripDiff [ inserting a, copying b ]
fmap stripDiff (rws compare [ b ] [ a, b ]) `shouldBe` fmap stripDiff [ inserting a, copying b ]
where compare :: (HasField fields Category, Functor f, Eq (Cofree f Category)) => Term f (Record fields) -> Term f (Record fields) -> Maybe (Diff f (Record fields))
compare a b | (category <$> a) == (category <$> b) = Just (copying b)
| otherwise = if ((==) `on` category . extract) a b then Just (replacing a b) else Nothing
copying :: Functor f => Cofree f (Record fields) -> Free (CofreeF f (Both (Record fields))) (Patch (Cofree f (Record fields)))
copying = cata wrap . fmap pure
decorate :: SyntaxTerm leaf '[Category] -> SyntaxTerm leaf '[FeatureVector, Category]
decorate :: SyntaxTerm leaf '[Category] -> SyntaxTerm leaf '[Maybe FeatureVector, Category]
decorate = defaultFeatureVectorDecorator (category . headF)

View File

@ -4,9 +4,10 @@ module Diff.Spec where
import Category
import Data.Bifunctor.Join
import Data.Functor.Listable
import Data.RandomWalkSimilarity
import Data.String
import Diff
import Diffing (getLabel)
import Info
import Interpreter
import Patch
import Prologue
@ -16,22 +17,23 @@ import Test.Hspec.LeanCheck
spec :: Spec
spec = parallel $ do
let decorate = defaultFeatureVectorDecorator (category . headF)
prop "equality is reflexive" $
\ a -> let diff = unListableDiff a :: SyntaxDiff String '[Category] in
diff `shouldBe` diff
prop "equal terms produce identity diffs" $
\ a -> let term = unListableF a :: SyntaxTerm String '[Category] in
diffCost (diffTerms wrap (==) diffCost getLabel term term) `shouldBe` 0
\ a -> let term = decorate (unListableF a :: SyntaxTerm String '[Category]) in
diffCost (diffTerms wrap (==) diffCost term term) `shouldBe` 0
describe "beforeTerm" $ do
prop "recovers the before term" $
\ a b -> let diff = diffTerms wrap (==) diffCost getLabel (unListableF a) (unListableF b :: SyntaxTerm String '[Category]) in
\ a b -> let diff = stripDiff $ diffTerms wrap (==) diffCost (decorate (unListableF a)) (decorate (unListableF b :: SyntaxTerm String '[Category])) in
beforeTerm diff `shouldBe` Just (unListableF a)
describe "afterTerm" $ do
prop "recovers the after term" $
\ a b -> let diff = diffTerms wrap (==) diffCost getLabel (unListableF a) (unListableF b :: SyntaxTerm String '[Category]) in
\ a b -> let diff = stripDiff $ diffTerms wrap (==) diffCost (decorate (unListableF a)) (decorate (unListableF b :: SyntaxTerm String '[Category])) in
afterTerm diff `shouldBe` Just (unListableF b)
unListableDiff :: Functor f => ListableF (Free (TermF f (ListableF (Join (,)) annotation))) (Patch (ListableF (Term f) annotation)) -> Diff f annotation

View File

@ -21,7 +21,6 @@ import Test.Hspec (Spec, describe, it, parallel)
import Test.Hspec.Expectations.Pretty
import Test.Hspec.LeanCheck
import Data.These
import Diffing (getLabel)
sourceSpanBetween :: (Int, Int) -> (Int, Int) -> SourceSpan
sourceSpanBetween (s1, e1) (s2, e2) = SourceSpan (SourcePos s1 e1) (SourcePos s2 e2)
@ -47,12 +46,12 @@ blobs = both (SourceBlob (fromText "[]") nullOid "a.js" (Just defaultPlainBlob))
spec :: Spec
spec = parallel $ do
describe "diffSummaries" $ do
it "outputs a diff summary" $ do
it "outputs a diff summary" $
diffSummaries blobs testDiff `shouldBe` [ JSONSummary "Added the \"a\" string" (SourceSpans . That $ sourceSpanBetween (1, 2) (1, 4)) ]
prop "equal terms produce identity diffs" $
\ a -> let term = defaultFeatureVectorDecorator (category . headF) (unListableF a :: SyntaxTerm String '[Category, Range, SourceSpan]) in
diffSummaries blobs (diffTerms wrap (==) diffCost getLabel term term) `shouldBe` []
diffSummaries blobs (diffTerms wrap (==) diffCost term term) `shouldBe` []
describe "DiffInfo" $ do
prop "patches in summaries match the patches in diffs" $

View File

@ -9,7 +9,6 @@ import Data.RandomWalkSimilarity
import Data.Record
import Data.String
import Diff
import Diffing
import Info
import Interpreter
import Patch
@ -28,18 +27,18 @@ spec = parallel $ do
it "returns a replacement when comparing two unicode equivalent terms" $
let termA = cofree $ (StringLiteral :. Nil) :< Leaf ("t\776" :: String)
termB = cofree $ (StringLiteral :. Nil) :< Leaf "\7831" in
stripDiff (diffTerms wrap compare diffCost getLabel (decorate termA) (decorate termB)) `shouldBe` replacing termA termB
stripDiff (diffTerms wrap compare diffCost (decorate termA) (decorate termB)) `shouldBe` replacing termA termB
prop "produces correct diffs" $
\ a b -> let diff = stripDiff $ diffTerms wrap compare diffCost getLabel (decorate (unListableF a)) (decorate (unListableF b :: SyntaxTerm String '[Category])) in
\ a b -> let diff = stripDiff $ diffTerms wrap compare diffCost (decorate (unListableF a)) (decorate (unListableF b :: SyntaxTerm String '[Category])) in
(beforeTerm diff, afterTerm diff) `shouldBe` (Just (unListableF a), Just (unListableF b))
prop "constructs zero-cost diffs of equal terms" $
\ a -> let term = decorate (unListableF a :: SyntaxTerm String '[Category])
diff = diffTerms wrap compare diffCost getLabel term term in
diff = diffTerms wrap compare diffCost term term in
diffCost diff `shouldBe` 0
it "produces unbiased insertions within branches" $
let term s = decorate (cofree ((StringLiteral :. Nil) :< Indexed [ cofree ((StringLiteral :. Nil) :< Leaf s) ]))
root = cofree . ((listArray (0, 0) [0] :. Program :. Nil) :<) . Indexed in
stripDiff (diffTerms wrap compare diffCost getLabel (root [ term "b" ]) (root [ term "a", term "b" ])) `shouldBe` wrap (pure (Program :. Nil) :< Indexed [ inserting (stripTerm (term "a")), cata wrap (fmap pure (stripTerm (term "b"))) ])
root = cofree . ((Just (listArray (0, defaultD) (repeat 0)) :. Program :. Nil) :<) . Indexed in
stripDiff (diffTerms wrap compare diffCost (root [ term "b" ]) (root [ term "a", term "b" ])) `shouldBe` wrap (pure (Program :. Nil) :< Indexed [ inserting (stripTerm (term "a")), cata wrap (fmap pure (stripTerm (term "b"))) ])

View File

@ -118,6 +118,21 @@
},
"summary": "Added '4' in the [...]int composite_literal of the 'main' function"
},
{
"span": {
"insert": {
"start": [
4,
23
],
"end": [
4,
24
]
}
},
"summary": "Added '5' in the [...]int composite_literal of the 'main' function"
},
{
"span": {
"replace": [
@ -131,33 +146,6 @@
22
]
},
{
"start": [
4,
23
],
"end": [
4,
24
]
}
]
},
"summary": "Replaced '1' with '5' in the [...]int composite_literal of the 'main' function"
},
{
"span": {
"replace": [
{
"start": [
4,
24
],
"end": [
4,
25
]
},
{
"start": [
4,
@ -170,7 +158,22 @@
}
]
},
"summary": "Replaced '2' with '6' in the [...]int composite_literal of the 'main' function"
"summary": "Replaced '1' with '6' in the [...]int composite_literal of the 'main' function"
},
{
"span": {
"delete": {
"start": [
4,
24
],
"end": [
4,
25
]
}
},
"summary": "Deleted '2' in the [...]int composite_literal of the 'main' function"
},
{
"span": {

View File

@ -135,21 +135,6 @@
"expectedResult": {
"changes": {
"call-expressions.go": [
{
"span": {
"insert": {
"start": [
4,
1
],
"end": [
4,
11
]
}
},
"summary": "Added the 'a(b, c)' function call in the main function"
},
{
"span": {
"replace": [
@ -163,6 +148,33 @@
2
]
},
{
"start": [
4,
1
],
"end": [
4,
2
]
}
]
},
"summary": "Replaced the 'x' identifier with the 'a' identifier in the a(b, c) function call of the 'main' function"
},
{
"span": {
"replace": [
{
"start": [
5,
1
],
"end": [
5,
2
]
},
{
"start": [
5,
@ -175,52 +187,34 @@
}
]
},
"summary": "Replaced the 'x' identifier with the 'b' identifier in the b(b, c) function call of the 'main' function"
"summary": "Replaced the 'y' identifier with the 'b' identifier in the b(b, c) function call of the 'main' function"
},
{
"span": {
"insert": {
"start": [
6,
1
],
"end": [
6,
11
]
}
"replace": [
{
"start": [
6,
1
],
"end": [
6,
2
]
},
{
"start": [
6,
1
],
"end": [
6,
2
]
}
]
},
"summary": "Added the 'c(b, c)' function call in the main function"
},
{
"span": {
"delete": {
"start": [
5,
1
],
"end": [
5,
9
]
}
},
"summary": "Deleted the 'y(b, c)' function call in the main function"
},
{
"span": {
"delete": {
"start": [
6,
1
],
"end": [
6,
11
]
}
},
"summary": "Deleted the 'z(b, c)' function call in the main function"
"summary": "Replaced the 'z' identifier with the 'c' identifier in the c(b, c) function call of the 'main' function"
}
]
},
@ -254,21 +248,6 @@
"expectedResult": {
"changes": {
"call-expressions.go": [
{
"span": {
"insert": {
"start": [
4,
1
],
"end": [
4,
11
]
}
},
"summary": "Added the 'x(b, c)' function call in the main function"
},
{
"span": {
"replace": [
@ -282,6 +261,33 @@
2
]
},
{
"start": [
4,
1
],
"end": [
4,
2
]
}
]
},
"summary": "Replaced the 'a' identifier with the 'x' identifier in the x(b, c) function call of the 'main' function"
},
{
"span": {
"replace": [
{
"start": [
5,
1
],
"end": [
5,
2
]
},
{
"start": [
5,
@ -294,52 +300,34 @@
}
]
},
"summary": "Replaced the 'a' identifier with the 'y' identifier in the y(b, c) function call of the 'main' function"
"summary": "Replaced the 'b' identifier with the 'y' identifier in the y(b, c) function call of the 'main' function"
},
{
"span": {
"insert": {
"start": [
6,
1
],
"end": [
6,
11
]
}
"replace": [
{
"start": [
6,
1
],
"end": [
6,
2
]
},
{
"start": [
6,
1
],
"end": [
6,
2
]
}
]
},
"summary": "Added the 'z(b, c)' function call in the main function"
},
{
"span": {
"delete": {
"start": [
5,
1
],
"end": [
5,
9
]
}
},
"summary": "Deleted the 'b(b, c)' function call in the main function"
},
{
"span": {
"delete": {
"start": [
6,
1
],
"end": [
6,
11
]
}
},
"summary": "Deleted the 'c(b, c)' function call in the main function"
"summary": "Replaced the 'c' identifier with the 'z' identifier in the z(b, c) function call of the 'main' function"
}
]
},

View File

@ -139,93 +139,138 @@
"channel-types.go": [
{
"span": {
"insert": {
"start": [
5,
1
],
"end": [
5,
22
]
}
"replace": [
{
"start": [
5,
1
],
"end": [
5,
3
]
},
{
"start": [
5,
1
],
"end": [
5,
3
]
}
]
},
"summary": "Added the 'c2' type declaration in the main function"
"summary": "Replaced the 'c1' identifier with the 'c2' identifier in the 'c2' type declaration of the 'main' function"
},
{
"span": {
"insert": {
"start": [
6,
1
],
"end": [
6,
26
]
}
"replace": [
{
"start": [
5,
16
],
"end": [
5,
19
]
},
{
"start": [
5,
16
],
"end": [
5,
22
]
}
]
},
"summary": "Added the 'c3' type declaration in the main function"
"summary": "Replaced the 'int' identifier with the 'string' identifier in the chan string channel type of the 'main' function"
},
{
"span": {
"insert": {
"start": [
7,
1
],
"end": [
7,
24
]
}
"replace": [
{
"start": [
6,
1
],
"end": [
6,
3
]
},
{
"start": [
6,
1
],
"end": [
6,
3
]
}
]
},
"summary": "Added the 'c4' type declaration in the main function"
"summary": "Replaced the 'c2' identifier with the 'c3' identifier in the 'c3' type declaration of the 'main' function"
},
{
"span": {
"delete": {
"start": [
5,
1
],
"end": [
5,
19
]
}
"replace": [
{
"start": [
7,
1
],
"end": [
7,
3
]
},
{
"start": [
7,
1
],
"end": [
7,
3
]
}
]
},
"summary": "Deleted the 'c1' type declaration in the main function"
"summary": "Replaced the 'c3' identifier with the 'c4' identifier in the 'c4' type declaration of the 'main' function"
},
{
"span": {
"delete": {
"start": [
6,
1
],
"end": [
6,
26
]
}
"replace": [
{
"start": [
7,
18
],
"end": [
7,
21
]
},
{
"start": [
7,
18
],
"end": [
7,
24
]
}
]
},
"summary": "Deleted the 'c2' type declaration in the main function"
},
{
"span": {
"delete": {
"start": [
7,
1
],
"end": [
7,
21
]
}
},
"summary": "Deleted the 'c3' type declaration in the main function"
"summary": "Replaced the 'int' identifier with the 'string' identifier in the <-chan string channel type of the 'main' function"
}
]
},
@ -262,18 +307,30 @@
"channel-types.go": [
{
"span": {
"insert": {
"start": [
5,
1
],
"end": [
5,
19
]
}
"replace": [
{
"start": [
5,
1
],
"end": [
5,
3
]
},
{
"start": [
5,
1
],
"end": [
5,
3
]
}
]
},
"summary": "Added the 'c1' type declaration in the main function"
"summary": "Replaced the 'c2' identifier with the 'c1' identifier in the 'c1' type declaration of the 'main' function"
},
{
"span": {
@ -281,7 +338,7 @@
{
"start": [
5,
11
16
],
"end": [
5,
@ -290,17 +347,17 @@
},
{
"start": [
6,
11
5,
16
],
"end": [
6,
26
5,
19
]
}
]
},
"summary": "Replaced the 'chan string' channel type with the 'chan<- struct{}' channel type in the chan<- chan<- struct{} channel type of the 'main' function"
"summary": "Replaced the 'string' identifier with the 'int' identifier in the chan int channel type of the 'main' function"
},
{
"span": {
@ -308,17 +365,71 @@
{
"start": [
6,
11
1
],
"end": [
6,
26
3
]
},
{
"start": [
6,
1
],
"end": [
6,
3
]
}
]
},
"summary": "Replaced the 'c3' identifier with the 'c2' identifier in the 'c2' type declaration of the 'main' function"
},
{
"span": {
"replace": [
{
"start": [
7,
1
],
"end": [
7,
3
]
},
{
"start": [
7,
11
1
],
"end": [
7,
3
]
}
]
},
"summary": "Replaced the 'c4' identifier with the 'c3' identifier in the 'c3' type declaration of the 'main' function"
},
{
"span": {
"replace": [
{
"start": [
7,
18
],
"end": [
7,
24
]
},
{
"start": [
7,
18
],
"end": [
7,
@ -327,22 +438,7 @@
}
]
},
"summary": "Replaced the 'chan<- struct{}' channel type with the '<-chan int' channel type in the chan<- <-chan int channel type of the 'main' function"
},
{
"span": {
"delete": {
"start": [
7,
1
],
"end": [
7,
24
]
}
},
"summary": "Deleted the 'c4' type declaration in the main function"
"summary": "Replaced the 'string' identifier with the 'int' identifier in the <-chan int channel type of the 'main' function"
}
]
},

View File

@ -427,21 +427,6 @@
},
"summary": "Added the 'a[1]' index expression in the main function"
},
{
"span": {
"insert": {
"start": [
5,
2
],
"end": [
5,
3
]
}
},
"summary": "Added the 'b' identifier in the main function"
},
{
"span": {
"replace": [
@ -452,49 +437,37 @@
],
"end": [
4,
2
6
]
},
{
"start": [
6,
5,
2
],
"end": [
6,
5,
3
]
}
]
},
"summary": "Replaced the 'z' identifier with the 'c' identifier in the c[1] slice literal of the 'main' function"
"summary": "Replaced the 'z[2]' slice literal with the 'b' identifier in the main function"
},
{
"span": {
"replace": [
{
"start": [
4,
4
],
"end": [
4,
5
]
},
{
"start": [
6,
4
],
"end": [
6,
5
]
}
]
"insert": {
"start": [
6,
2
],
"end": [
6,
7
]
}
},
"summary": "Replaced '2' with '1' in the c[1] slice literal of the 'main' function"
"summary": "Added the 'c[1]' slice literal in the main function"
},
{
"span": {

View File

@ -436,33 +436,84 @@
"import.js": [
{
"span": {
"insert": {
"start": [
1,
1
],
"end": [
1,
33
]
}
"replace": [
{
"start": [
1,
27
],
"end": [
1,
37
]
},
{
"start": [
1,
27
],
"end": [
1,
32
]
}
]
},
"summary": "Added the defaultMember from \"foo\" import statement"
"summary": "Replaced the \"babirusa\" string with the \"foo\" string in the defaultMember from \"foo\" import statement"
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
34
]
}
"replace": [
{
"start": [
2,
28
],
"end": [
2,
36
]
},
{
"start": [
2,
23
],
"end": [
2,
33
]
}
]
},
"summary": "Added the * as name from \"aardvark\" import statement"
"summary": "Replaced the \"baboon\" string with the \"aardvark\" string in the * as name from \"aardvark\" import statement"
},
{
"span": {
"replace": [
{
"start": [
2,
13
],
"end": [
2,
22
]
},
{
"start": [
2,
13
],
"end": [
2,
17
]
}
]
},
"summary": "Replaced the 'otherName' identifier with the 'name' identifier in the * as name from \"aardvark\" import statement"
},
{
"span": {
@ -524,92 +575,47 @@
},
"summary": "Added the defaultMember, { member1, member2 as alias2 } from \"anaconda\" import statement"
},
{
"span": {
"insert": {
"start": [
7,
1
],
"end": [
7,
50
]
}
},
"summary": "Added the defaultMember, * as name from \"alligator\" import statement"
},
{
"span": {
"replace": [
{
"start": [
1,
27
3,
1
],
"end": [
1,
37
3,
34
]
},
{
"start": [
8,
8
7,
1
],
"end": [
8,
21
7,
50
]
}
]
},
"summary": "Replaced the \"babirusa\" string with the \"arctic-tern\" string in the \"arctic-tern\" import statement"
"summary": "Replaced the { element } from \"badger\" import statement with the defaultMember, * as name from \"alligator\" import statement"
},
{
"span": {
"delete": {
"insert": {
"start": [
1,
8
],
"end": [
1,
21
]
}
},
"summary": "Deleted the 'defaultMember' identifier in the \"arctic-tern\" import statement"
},
{
"span": {
"delete": {
"start": [
2,
8,
1
],
"end": [
2,
37
8,
22
]
}
},
"summary": "Deleted the * as otherName from \"baboon\" import statement"
},
{
"span": {
"delete": {
"start": [
3,
1
],
"end": [
3,
34
]
}
},
"summary": "Deleted the { element } from \"badger\" import statement"
"summary": "Added the \"arctic-tern\" import statement"
},
{
"span": {
@ -729,33 +735,84 @@
"import.js": [
{
"span": {
"insert": {
"start": [
1,
1
],
"end": [
1,
38
]
}
"replace": [
{
"start": [
1,
27
],
"end": [
1,
32
]
},
{
"start": [
1,
27
],
"end": [
1,
37
]
}
]
},
"summary": "Added the defaultMember from \"babirusa\" import statement"
"summary": "Replaced the \"foo\" string with the \"babirusa\" string in the defaultMember from \"babirusa\" import statement"
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
37
]
}
"replace": [
{
"start": [
2,
23
],
"end": [
2,
33
]
},
{
"start": [
2,
28
],
"end": [
2,
36
]
}
]
},
"summary": "Added the * as otherName from \"baboon\" import statement"
"summary": "Replaced the \"aardvark\" string with the \"baboon\" string in the * as otherName from \"baboon\" import statement"
},
{
"span": {
"replace": [
{
"start": [
2,
13
],
"end": [
2,
17
]
},
{
"start": [
2,
13
],
"end": [
2,
22
]
}
]
},
"summary": "Replaced the 'name' identifier with the 'otherName' identifier in the * as otherName from \"baboon\" import statement"
},
{
"span": {
@ -817,92 +874,47 @@
},
"summary": "Added the defaultMember, { element1, element2 as elementAlias2 } from \"banteng\" import statement"
},
{
"span": {
"insert": {
"start": [
7,
1
],
"end": [
7,
50
]
}
},
"summary": "Added the defaultMember, * as element from \"barbet\" import statement"
},
{
"span": {
"replace": [
{
"start": [
1,
27
3,
1
],
"end": [
1,
32
3,
30
]
},
{
"start": [
8,
8
7,
1
],
"end": [
8,
18
7,
50
]
}
]
},
"summary": "Replaced the \"foo\" string with the \"basilisk\" string in the \"basilisk\" import statement"
"summary": "Replaced the { member } from \"ant\" import statement with the defaultMember, * as element from \"barbet\" import statement"
},
{
"span": {
"delete": {
"insert": {
"start": [
1,
8
],
"end": [
1,
21
]
}
},
"summary": "Deleted the 'defaultMember' identifier in the \"basilisk\" import statement"
},
{
"span": {
"delete": {
"start": [
2,
8,
1
],
"end": [
2,
34
8,
19
]
}
},
"summary": "Deleted the * as name from \"aardvark\" import statement"
},
{
"span": {
"delete": {
"start": [
3,
1
],
"end": [
3,
30
]
}
},
"summary": "Deleted the { member } from \"ant\" import statement"
"summary": "Added the \"basilisk\" import statement"
},
{
"span": {

View File

@ -128,33 +128,30 @@
"var-declaration.js": [
{
"span": {
"insert": {
"start": [
1,
5
],
"end": [
1,
10
]
}
"replace": [
{
"start": [
1,
5
],
"end": [
1,
6
]
},
{
"start": [
1,
5
],
"end": [
1,
10
]
}
]
},
"summary": "Added the 'x' variable"
},
{
"span": {
"delete": {
"start": [
1,
5
],
"end": [
1,
6
]
}
},
"summary": "Deleted the 'x' variable"
"summary": "Replaced the 'x' variable with the 'x' variable"
},
{
"span": {
@ -212,21 +209,6 @@
"expectedResult": {
"changes": {
"var-declaration.js": [
{
"span": {
"insert": {
"start": [
1,
5
],
"end": [
1,
6
]
}
},
"summary": "Added the 'x' variable"
},
{
"span": {
"replace": [
@ -243,16 +225,31 @@
{
"start": [
1,
8
5
],
"end": [
1,
14
6
]
}
]
},
"summary": "Replaced the 'x' var assignment with the 'y' var assignment"
"summary": "Replaced the 'x' variable with the 'x' variable"
},
{
"span": {
"insert": {
"start": [
1,
8
],
"end": [
1,
14
]
}
},
"summary": "Added the 'y' variable"
},
{
"span": {

View File

@ -205,21 +205,6 @@
},
"summary": "Replaced the 'a & b' binary statement with the 'a | b' binary statement"
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
7
]
}
},
"summary": "Added the 'a >> b' binary statement"
},
{
"span": {
"replace": [
@ -235,17 +220,32 @@
},
{
"start": [
3,
2,
1
],
"end": [
3,
6
2,
7
]
}
]
},
"summary": "Replaced the 'a << b' binary statement with the 'a ^ b' binary statement"
"summary": "Replaced the 'a << b' binary statement with the 'a >> b' binary statement"
},
{
"span": {
"insert": {
"start": [
3,
1
],
"end": [
3,
6
]
}
},
"summary": "Added the 'a ^ b' binary statement"
}
]
},
@ -306,33 +306,30 @@
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
7
]
}
"replace": [
{
"start": [
2,
1
],
"end": [
2,
7
]
},
{
"start": [
2,
1
],
"end": [
2,
7
]
}
]
},
"summary": "Added the 'a << b' binary statement"
},
{
"span": {
"delete": {
"start": [
2,
1
],
"end": [
2,
7
]
}
},
"summary": "Deleted the 'a >> b' binary statement"
"summary": "Replaced the 'a >> b' binary statement with the 'a << b' binary statement"
},
{
"span": {

View File

@ -355,18 +355,30 @@
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
10
]
}
"replace": [
{
"start": [
1,
1
],
"end": [
1,
6
]
},
{
"start": [
2,
1
],
"end": [
2,
10
]
}
]
},
"summary": "Added the %q<a<b>c> string"
"summary": "Replaced the %q/b/ string with the %q<a<b>c> string"
},
{
"span": {
@ -388,12 +400,12 @@
"replace": [
{
"start": [
1,
2,
1
],
"end": [
1,
6
2,
10
]
},
{
@ -408,7 +420,7 @@
}
]
},
"summary": "Replaced the %q/b/ string with the %Q#a# string"
"summary": "Replaced the %q{d{e}f} string with the %Q#a# string"
},
{
"span": {
@ -427,30 +439,18 @@
},
{
"span": {
"replace": [
{
"start": [
2,
1
],
"end": [
2,
10
]
},
{
"start": [
6,
1
],
"end": [
6,
10
]
}
]
"insert": {
"start": [
6,
1
],
"end": [
6,
10
]
}
},
"summary": "Replaced the %q{d{e}f} string with the %Q<a<b>c> string"
"summary": "Added the %Q<a<b>c> string"
},
{
"span": {
@ -579,21 +579,6 @@
},
"summary": "Added the %q{d{e}f} string"
},
{
"span": {
"insert": {
"start": [
3,
1
],
"end": [
3,
5
]
}
},
"summary": "Added the %/b/ string"
},
{
"span": {
"replace": [
@ -609,17 +594,32 @@
},
{
"start": [
4,
3,
1
],
"end": [
4,
6
3,
5
]
}
]
},
"summary": "Replaced the %q#a# string with the %Q/b/ string"
"summary": "Replaced the %q#a# string with the %/b/ string"
},
{
"span": {
"insert": {
"start": [
4,
1
],
"end": [
4,
6
]
}
},
"summary": "Added the %Q/b/ string"
},
{
"span": {

View File

@ -140,18 +140,30 @@
},
{
"span": {
"insert": {
"start": [
1,
33
],
"end": [
1,
48
]
}
"replace": [
{
"start": [
1,
26
],
"end": [
1,
33
]
},
{
"start": [
1,
33
],
"end": [
1,
48
]
}
]
},
"summary": "Added the '\"key3\": false' pair"
"summary": "Replaced the 'key2: 2' pair with the '\"key3\": false' pair"
},
{
"span": {
@ -168,21 +180,6 @@
},
"summary": "Added the ':\"symbol_key\" => 10' pair"
},
{
"span": {
"delete": {
"start": [
1,
26
],
"end": [
1,
33
]
}
},
"summary": "Deleted the 'key2: 2' pair"
},
{
"span": {
"delete": {

View File

@ -484,6 +484,93 @@
"expectedResult": {
"changes": {
"method-invocation.rb": [
{
"span": {
"insert": {
"start": [
1,
1
],
"end": [
1,
6
]
}
},
"summary": "Added the 'print' identifier"
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
8
]
}
},
"summary": "Added the 'foo.bar' member access"
},
{
"span": {
"replace": [
{
"start": [
5,
1
],
"end": [
5,
6
]
},
{
"start": [
3,
1
],
"end": [
3,
4
]
}
]
},
"summary": "Replaced the 'print' identifier with the 'bar' identifier"
},
{
"span": {
"delete": {
"start": [
6,
1
],
"end": [
6,
8
]
}
},
"summary": "Deleted the 'foo.bar' member access"
},
{
"span": {
"delete": {
"start": [
7,
1
],
"end": [
7,
4
]
}
},
"summary": "Deleted the 'bar' identifier"
},
{
"span": {
"delete": {

View File

@ -434,6 +434,21 @@
},
"summary": "Added '0d1_234'"
},
{
"span": {
"insert": {
"start": [
4,
1
],
"end": [
4,
24
]
}
},
"summary": "Added '0xa_bcd_ef0_123_456_789'"
},
{
"span": {
"replace": [
@ -449,32 +464,17 @@
},
{
"start": [
4,
5,
1
],
"end": [
4,
24
5,
10
]
}
]
},
"summary": "Replaced '1235' with '0xa_bcd_ef0_123_456_789'"
},
{
"span": {
"insert": {
"start": [
5,
1
],
"end": [
5,
10
]
}
},
"summary": "Added '0o1234567'"
"summary": "Replaced '1235' with '0o1234567'"
},
{
"span": {
@ -649,30 +649,18 @@
},
{
"span": {
"replace": [
{
"start": [
1,
1
],
"end": [
1,
5
]
},
{
"start": [
2,
1
],
"end": [
2,
6
]
}
]
"insert": {
"start": [
2,
1
],
"end": [
2,
6
]
}
},
"summary": "Replaced '1234' with '1_235'"
"summary": "Added '1_235'"
},
{
"span": {
@ -689,47 +677,47 @@
},
"summary": "Added '0d1_235'"
},
{
"span": {
"insert": {
"start": [
4,
1
],
"end": [
4,
24
]
}
},
"summary": "Added '0xa_bcd_ef0_123_456_788'"
},
{
"span": {
"replace": [
{
"start": [
2,
1,
1
],
"end": [
2,
6
1,
5
]
},
{
"start": [
4,
5,
1
],
"end": [
4,
24
5,
10
]
}
]
},
"summary": "Replaced '1_234' with '0xa_bcd_ef0_123_456_788'"
},
{
"span": {
"insert": {
"start": [
5,
1
],
"end": [
5,
10
]
}
},
"summary": "Added '0o1234576'"
"summary": "Replaced '1234' with '0o1234576'"
},
{
"span": {
@ -761,6 +749,21 @@
},
"summary": "Added '1.234_5e678_91'"
},
{
"span": {
"delete": {
"start": [
2,
1
],
"end": [
2,
6
]
}
},
"summary": "Deleted '1_234'"
},
{
"span": {
"delete": {

View File

@ -244,30 +244,18 @@
"pseudo-variables.rb": [
{
"span": {
"replace": [
{
"start": [
2,
1
],
"end": [
2,
4
]
},
{
"start": [
1,
1
],
"end": [
1,
4
]
}
]
"insert": {
"start": [
1,
1
],
"end": [
1,
4
]
}
},
"summary": "Replaced the 'NIL' identifier with the 'nil' identifier"
"summary": "Added the 'nil' identifier"
},
{
"span": {
@ -299,6 +287,21 @@
},
"summary": "Added 'true'"
},
{
"span": {
"delete": {
"start": [
2,
1
],
"end": [
2,
4
]
}
},
"summary": "Deleted the 'NIL' identifier"
},
{
"span": {
"delete": {
@ -419,31 +422,34 @@
"summary": "Replaced 'false' with 'TRUE'"
},
{
"span": {
"replace": [
{
"start": [
4,
1
],
"end": [
4,
5
]
},
{
"start": [
4,
1
],
"end": [
4,
6
]
}
]
},
"summary": "Replaced 'true' with 'FALSE'"
"span": {
"insert": {
"start": [
4,
1
],
"end": [
4,
6
]
}
},
"summary": "Added 'FALSE'"
},
{
"span": {
"delete": {
"start": [
4,
1
],
"end": [
4,
5
]
}
},
"summary": "Deleted 'true'"
}
]
},

View File

@ -194,74 +194,74 @@
"expectedResult": {
"changes": {
"relational-operator.rb": [
{
"span": {
"replace": [
{
"start": [
1,
1
],
"end": [
1,
8
]
},
{
"start": [
1,
1
],
"end": [
1,
7
]
}
]
},
"summary": "Replaced the 'x <=> y' binary statement with the 'x == y' binary statement"
},
{
"span": {
"replace": [
{
"start": [
2,
1
],
"end": [
2,
7
]
},
{
"start": [
2,
1
],
"end": [
2,
7
]
}
]
},
"summary": "Replaced the 'x =~ y' binary statement with the 'x != y' binary statement"
},
{
"span": {
"insert": {
"start": [
1,
3,
1
],
"end": [
1,
7
3,
8
]
}
},
"summary": "Added the 'x == y' binary statement"
},
{
"span": {
"replace": [
{
"start": [
1,
1
],
"end": [
1,
8
]
},
{
"start": [
2,
1
],
"end": [
2,
7
]
}
]
},
"summary": "Replaced the 'x <=> y' binary statement with the 'x != y' binary statement"
},
{
"span": {
"replace": [
{
"start": [
2,
1
],
"end": [
2,
7
]
},
{
"start": [
3,
1
],
"end": [
3,
8
]
}
]
},
"summary": "Replaced the 'x =~ y' binary statement with the 'x === y' binary statement"
"summary": "Added the 'x === y' binary statement"
},
{
"span": {
@ -309,21 +309,6 @@
"expectedResult": {
"changes": {
"relational-operator.rb": [
{
"span": {
"insert": {
"start": [
1,
1
],
"end": [
1,
8
]
}
},
"summary": "Added the 'x <=> y' binary statement"
},
{
"span": {
"replace": [
@ -337,6 +322,33 @@
7
]
},
{
"start": [
1,
1
],
"end": [
1,
8
]
}
]
},
"summary": "Replaced the 'x == y' binary statement with the 'x <=> y' binary statement"
},
{
"span": {
"replace": [
{
"start": [
2,
1
],
"end": [
2,
7
]
},
{
"start": [
2,
@ -349,7 +361,7 @@
}
]
},
"summary": "Replaced the 'x == y' binary statement with the 'x =~ y' binary statement"
"summary": "Replaced the 'x != y' binary statement with the 'x =~ y' binary statement"
},
{
"span": {
@ -366,21 +378,6 @@
},
"summary": "Added the 'x' assignment"
},
{
"span": {
"delete": {
"start": [
2,
1
],
"end": [
2,
7
]
}
},
"summary": "Deleted the 'x != y' binary statement"
},
{
"span": {
"delete": {

View File

@ -209,21 +209,6 @@
},
"summary": "Added the ':foo' symbol"
},
{
"span": {
"insert": {
"start": [
2,
1
],
"end": [
2,
7
]
}
},
"summary": "Added the ':'foo'' symbol"
},
{
"span": {
"replace": [
@ -237,6 +222,33 @@
5
]
},
{
"start": [
2,
1
],
"end": [
2,
7
]
}
]
},
"summary": "Replaced the ':bar' symbol with the ':'foo'' symbol"
},
{
"span": {
"replace": [
{
"start": [
2,
1
],
"end": [
2,
7
]
},
{
"start": [
3,
@ -249,22 +261,7 @@
}
]
},
"summary": "Replaced the ':bar' symbol with the ':\"foo\"' symbol"
},
{
"span": {
"delete": {
"start": [
2,
1
],
"end": [
2,
7
]
}
},
"summary": "Deleted the ':'bar'' symbol"
"summary": "Replaced the ':'bar'' symbol with the ':\"foo\"' symbol"
},
{
"span": {