From 506f67b6399076b31fbe0a0f3574a8d013406588 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 11:02:17 +0200 Subject: [PATCH 01/35] Cover how a JBFL pattern matches a cursor The rule lookup is about to become a trie, and nothing pinned the two things that change would have to preserve: that a pattern matches only once consumed whole, with leftover breadcrumbs allowed under PrefixMatch alone, and which of the two modes each property is read in. Moving AutoPad across left every fixture green. --- test/Formatting/RulesSpec.hs | 49 +++++++++++++++++++++++++++++++ test/FormattingSpec.hs | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index a40c7565..b2baa9ce 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -1,6 +1,8 @@ module Formatting.RulesSpec (spec) where import GHC.IsList (fromList) +import JbeamEdit.Core.NodeCursor (NodeBreadcrumb (..), NodeCursor (..)) +import JbeamEdit.Core.NodePath qualified as NP import JbeamEdit.Formatting import JbeamEdit.Formatting.Rules import SpecHelper @@ -34,3 +36,50 @@ spec = do ] it "applies PadAmount and PadDecimals" $ applyPadLogic (formatScalarNode False) ruleSet fakeNode `shouldBe` "123.50 " + + -- A pattern matches only once it has been consumed whole, and leftover + -- breadcrumbs are allowed under PrefixMatch alone. A lookup that answers at + -- the wrong depth silently changes formatting everywhere, since every + -- property the formatter reads comes through one of the two modes. + describe "matching a pattern against a cursor" $ do + let cursorAt crumbs = NodeCursor (fromList crumbs) + nodesCursor = + cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "nodes"] + ruleSetFor p = + RuleSet + ( fromList + [ + ( NodePattern (fromList p) + , fromList [(SomeKey PadAmount, SomeProperty PadAmount 7)] + ) + ] + ) + found mode p = lookupPropertyForCursor mode PadAmount (ruleSetFor p) + + it "matches a pattern of the same length in both modes" $ do + let p = [AnyObjectKey, Selector (NP.ObjectKey "nodes")] + found PrefixMatch p nodesCursor `shouldBe` Just 7 + found ExactMatch p nodesCursor `shouldBe` Just 7 + + it "matches a shorter pattern only as a prefix" $ do + let p = [AnyObjectKey] + found PrefixMatch p nodesCursor `shouldBe` Just 7 + found ExactMatch p nodesCursor `shouldBe` Nothing + + it "never matches a pattern longer than the cursor" $ do + let p = + [ AnyObjectKey + , Selector (NP.ObjectKey "nodes") + , AnyArrayIndex + ] + found PrefixMatch p nodesCursor `shouldBe` Nothing + found ExactMatch p nodesCursor `shouldBe` Nothing + + it "keeps the two wildcards apart" $ do + let atArray = cursorAt [ObjectIndexAndKey 0 "part", ArrayIndex 0] + atKey = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "k"] + anyKeyThen w = [AnyObjectKey, w] + found ExactMatch (anyKeyThen AnyArrayIndex) atArray `shouldBe` Just 7 + found ExactMatch (anyKeyThen AnyObjectKey) atArray `shouldBe` Nothing + found ExactMatch (anyKeyThen AnyObjectKey) atKey `shouldBe` Just 7 + found ExactMatch (anyKeyThen AnyArrayIndex) atKey `shouldBe` Nothing diff --git a/test/FormattingSpec.hs b/test/FormattingSpec.hs index 20dd571d..9e4c0310 100644 --- a/test/FormattingSpec.hs +++ b/test/FormattingSpec.hs @@ -7,7 +7,10 @@ import Data.Text (Text) import Data.Text qualified as T import GHC.IsList (fromList) import JbeamEdit.Core.NodeCursor (newCursor) +import JbeamEdit.Core.NodePath qualified as NP import JbeamEdit.Formatting +import JbeamEdit.Formatting.Rules +import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL import SpecHelper import System.FilePath (takeBaseName, ()) @@ -83,9 +86,63 @@ dynamicJbflTests = do expected <- T.pack <$> readFile outFile pure (outFile, formatted, expected) +{- | Which mode a property is read in is hardcoded in `doFormatNode`: AutoPad, +AlignObjectKeys and AutoPadSubObjects come from an exact match, ComplexNewLine +and TrailingComma from a prefix match. Moving one across changes formatting and +no fixture notices. This pins the split as it stands before `>` (see #187), which +is meant to replace it, so expect to rewrite this when that lands. +-} +matchModeSpec :: Spec +matchModeSpec = do + let row cells = mkArray (fromList cells) + -- The first column has to vary in width for AutoPad to show, since + -- trailing spaces on the last one are trimmed either way. + rows = + row + [ row [String "a_long_name", Number (mkNumberValue "1" 1)] + , row [String "n1", Number (mkNumberValue "2" 2)] + ] + topNode = + mkObject + ( fromList + [ ObjectKey + ( String "part" + , mkObject (fromList [ObjectKey (String "rows", rows)]) + ) + ] + ) + -- The rows array sits two breadcrumbs deep, so a one-selector pattern is + -- a prefix of its cursor and a two-selector one matches it exactly. + ruleAt p k v = + RuleSet + (fromList [(NodePattern (fromList p), fromList [(SomeKey k, SomeProperty k v)])]) + shortPattern = [AnyObjectKey] + exactPattern = [AnyObjectKey, Selector (NP.ObjectKey "rows")] + formatWith rs = formatNode rs topNode + + -- The only difference is the run of spaces before the 2, which is the + -- second column padded out to the width of the first row. + wrap body = "{\"part\" : {\n \"rows\" : [\n" <> body <> "\n ]\n}}\n" + baseline = wrap " [\"a_long_name\", 1],\n [\"n1\", 2]" + padded = wrap " [\"a_long_name\", 1],\n [\"n1\", 2]" + + describe "which match mode a property is read in" $ do + it "reads AutoPad from an exact match only" $ do + formatWith (ruleAt exactPattern AutoPad True) `shouldBe` padded + -- Without this line the assertion below also passes for a shortPattern + -- that matches nothing at all, which is not what is being claimed. + formatWith (ruleAt shortPattern ComplexNewLine CNL.Force) + `shouldNotBe` baseline + formatWith (ruleAt shortPattern AutoPad True) `shouldBe` baseline + + it "reads ComplexNewLine from a prefix match" $ + formatWith (ruleAt shortPattern ComplexNewLine CNL.Force) + `shouldNotBe` baseline + spec :: Spec spec = do mapM_ formatNodeSpec specs + matchModeSpec dynamicTests <- runIO dynamicJbflTests forM_ dynamicTests $ \(outFile, formatted, expected) -> From e4f6ef8ae898d34b281b3745ad85bf928bb1e57d Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 11:08:15 +0200 Subject: [PATCH 02/35] Cover prefix keys in the same pattern group `.test*` is documented JBFL and shipped, so the trie has to solve it rather than decide whether to keep it. It is also the one selector that cannot be keyed on directly, since the stored key is a prefix of the breadcrumb rather than the same text. --- test/Formatting/RulesSpec.hs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index b2baa9ce..0d9ef88f 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -75,6 +75,20 @@ spec = do found PrefixMatch p nodesCursor `shouldBe` Nothing found ExactMatch p nodesCursor `shouldBe` Nothing + -- `.test*` is documented JBFL (JBFL_DOCS.md) and cannot be looked up by + -- equality, since the stored key is a prefix of the breadcrumb rather than + -- the same text. It is the one selector a trie has to solve rather than + -- key on directly. + it "matches a prefix key against the rest of the breadcrumb" $ do + let p k = [AnyObjectKey, Selector (NP.ObjectPrefixKey k)] + atDeformGroups = + cursorAt + [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "deformGroups"] + found ExactMatch (p "deform") atDeformGroups `shouldBe` Just 7 + found ExactMatch (p "deformGroups") atDeformGroups `shouldBe` Just 7 + found ExactMatch (p "deformGroupsAndMore") atDeformGroups `shouldBe` Nothing + found ExactMatch (p "eform") atDeformGroups `shouldBe` Nothing + it "keeps the two wildcards apart" $ do let atArray = cursorAt [ObjectIndexAndKey 0 "part", ArrayIndex 0] atKey = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "k"] From 92e116676814c5b65156c5d164ae7da8e16617c1 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 12:19:49 +0200 Subject: [PATCH 03/35] Decide which of several matching patterns wins Precedence was whatever fell out of Ord NodePattern, and part of it was plainly wrong: against the key deformGroups the pattern .de* beat .deform*, so the less specific rule won. The rule is now specificity, meaning how many nodes a selector can match, and these specs state it. Two of them fail until rank stops delegating to the derived Ord on NodeSelector. Also pinned: a less specific pattern still supplies properties the winner does not set. Every shipped ruleset depends on it, since .* carries Indent and TrailingComma for the whole file. --- test/FormattingSpec.hs | 77 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/test/FormattingSpec.hs b/test/FormattingSpec.hs index 9e4c0310..2d8b67ed 100644 --- a/test/FormattingSpec.hs +++ b/test/FormattingSpec.hs @@ -11,6 +11,7 @@ import JbeamEdit.Core.NodePath qualified as NP import JbeamEdit.Formatting import JbeamEdit.Formatting.Rules import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL +import JbeamEdit.Parsing.DSL (parseDSL) import SpecHelper import System.FilePath (takeBaseName, ()) @@ -86,11 +87,15 @@ dynamicJbflTests = do expected <- T.pack <$> readFile outFile pure (outFile, formatted, expected) -{- | Which mode a property is read in is hardcoded in `doFormatNode`: AutoPad, -AlignObjectKeys and AutoPadSubObjects come from an exact match, ComplexNewLine -and TrailingComma from a prefix match. Moving one across changes formatting and -no fixture notices. This pins the split as it stands before `>` (see #187), which -is meant to replace it, so expect to rewrite this when that lands. +{- | Which mode a property is read in is hardcoded in the formatter. Three come +from an exact match, AutoPad, AlignObjectKeys and AutoPadSubObjects, and they +are the ones about how a container lays out its own children. The other six +cascade and come from a prefix match: ComplexNewLine, TrailingComma, Indent, +PreserveNumberFormat, PadAmount and PadDecimals. + +Moving one across changes formatting and no fixture notices. This pins the split +as it stands before `>` (see #187), which is meant to replace it, so expect to +rewrite this when that lands. -} matchModeSpec :: Spec matchModeSpec = do @@ -139,10 +144,72 @@ matchModeSpec = do formatWith (ruleAt shortPattern ComplexNewLine CNL.Force) `shouldNotBe` baseline +{- | When several patterns match the same node, the more specific one supplies +the property. Specificity is how many nodes a selector can match at that level: +a named key first, then a positional index, then a prefix key with the longer +prefix winning, then the wildcards. + +Written as JBFL source and formatted output on purpose. Both ends survive the +rule lookup becoming a trie, while `NodePattern` and `MatchMode` do not. +-} +precedenceSpec :: Spec +precedenceSpec = do + let cell n = Number (mkNumberValue (T.pack (show n)) (fromIntegral n)) + -- Complex enough to be broken across lines, so Indent shows in the output. + topNode = + mkObject + ( fromList + [ ObjectKey + ( String "deformGroups" + , mkArray + ( fromList + [ mkArray (fromList [cell 1, cell 2]) + , mkArray (fromList [cell 3, cell 4]) + ] + ) + ) + ] + ) + rulesFrom src = + case parseDSL (textToLazyByteString src) of + Right rs -> rs + Left err -> error ("bad JBFL in spec: " ++ T.unpack err) + formatWith = flip formatNode topNode . rulesFrom + -- The second assertion is what stops the first passing for two rules that + -- happen to format the same way. + beats winner loser = do + formatWith (winner <> "\n" <> loser) `shouldBe` formatWith winner + formatWith winner `shouldNotBe` formatWith loser + named = ".deformGroups { Indent : 1; }" + positional = ".0 { Indent : 2; }" + longPrefix = ".deform* { Indent : 3; }" + shortPrefix = ".de* { Indent : 5; }" + wildcard = ".* { Indent : 6; }" + + describe "which of several matching patterns supplies a property" $ do + it "prefers a named key over a positional index" $ named `beats` positional + it "prefers a positional index over a prefix key" $ + positional `beats` longPrefix + it "prefers the longer of two prefix keys" $ longPrefix `beats` shortPrefix + it "prefers a prefix key over a wildcard" $ shortPrefix `beats` wildcard + + -- Precedence settles one property at a time. Every shipped ruleset is + -- written this way: `.*` carries Indent and TrailingComma for the whole + -- file and narrower patterns add to it, so a winner that supplied its + -- properties wholesale would strip the broad ones off every node it matched. + it "still takes properties the winner does not set from the loser" $ do + let winnerOnly = ".deformGroups { Indent : 1; }" + loserOnly = ".de* { TrailingComma : Force; }" + formatWith (winnerOnly <> "\n" <> loserOnly) + `shouldNotBe` formatWith winnerOnly + formatWith (winnerOnly <> "\n" <> loserOnly) + `shouldNotBe` formatWith loserOnly + spec :: Spec spec = do mapM_ formatNodeSpec specs matchModeSpec + precedenceSpec dynamicTests <- runIO dynamicJbflTests forM_ dynamicTests $ \(outFile, formatted, expected) -> From 471c4ae73ec95a61d29ed5eb866fd13e96074f28 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 12:43:07 +0200 Subject: [PATCH 04/35] Cover the literal array index and the ruleset merge `[4]` is the last row of the selector table that no shipped ruleset uses, so nothing else would notice it going away. The merge is how every configured install resolves its rules: a user's file is laid over the shipped one with a union that is left-biased per pattern and per property. --- test/FormattingSpec.hs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/test/FormattingSpec.hs b/test/FormattingSpec.hs index 2d8b67ed..03fa0a4c 100644 --- a/test/FormattingSpec.hs +++ b/test/FormattingSpec.hs @@ -155,6 +155,8 @@ rule lookup becoming a trie, while `NodePattern` and `MatchMode` do not. precedenceSpec :: Spec precedenceSpec = do let cell n = Number (mkNumberValue (T.pack (show n)) (fromIntegral n)) + -- Three levels deep, so Indent set two breadcrumbs down still shows. + pair a b = mkArray (fromList [mkArray (fromList [a, b]), mkArray (fromList [b, a])]) -- Complex enough to be broken across lines, so Indent shows in the output. topNode = mkObject @@ -163,8 +165,8 @@ precedenceSpec = do ( String "deformGroups" , mkArray ( fromList - [ mkArray (fromList [cell 1, cell 2]) - , mkArray (fromList [cell 3, cell 4]) + [ pair (cell 1) (cell 2) + , pair (cell 3) (cell 4) ] ) ) @@ -197,6 +199,11 @@ precedenceSpec = do -- written this way: `.*` carries Indent and TrailingComma for the whole -- file and narrower patterns add to it, so a winner that supplied its -- properties wholesale would strip the broad ones off every node it matched. + -- `[4]` is the last row of the selector table in JBFL_DOCS.md, and the only + -- one no shipped ruleset uses, so nothing else would notice it going away. + it "matches a literal array index and prefers it over the wildcard" $ + ".deformGroups[0] { Indent : 1; }" `beats` ".deformGroups[*] { Indent : 4; }" + it "still takes properties the winner does not set from the loser" $ do let winnerOnly = ".deformGroups { Indent : 1; }" loserOnly = ".de* { TrailingComma : Force; }" @@ -205,6 +212,23 @@ precedenceSpec = do formatWith (winnerOnly <> "\n" <> loserOnly) `shouldNotBe` formatWith loserOnly + -- A user's rules.jbfl is laid over the shipped one with `rs <> defaultRs` + -- (`Formatting/Config.hs`), so this is how every configured install resolves + -- its rules. The union is left-biased twice over, per pattern and per + -- property, and a trie has to reproduce both. + describe "combining a user ruleset with the shipped one" $ do + let user = rulesFrom ".deformGroups { Indent : 1; }" + shipped = rulesFrom ".deformGroups { Indent : 7; TrailingComma : Force; }" + format = flip formatNode topNode + + it "takes the user's value and keeps the rest of the shipped one" $ do + let merged = rulesFrom ".deformGroups { Indent : 1; TrailingComma : Force; }" + format (user <> shipped) `shouldBe` format merged + -- Guards the line above: without these the two rulesets could be + -- indistinguishable and the merge would prove nothing. + format user `shouldNotBe` format shipped + format merged `shouldNotBe` format user + spec :: Spec spec = do mapM_ formatNodeSpec specs From 3b0c3ef2a7447330a0e947e82404fa4498f39949 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 13:07:36 +0200 Subject: [PATCH 05/35] Put the rule semantics specs under Formatting.Rules Precedence and combining two rulesets are properties of RuleSet, not of the formatter; the formatter was only the instrument they were observed through. Adds the two that were missing: a prefix key reaches below the node it names, and length settles before specificity. matchModeSpec now builds its rules from JBFL source too, so nothing here constructs a RuleSet by hand. --- test/Formatting/RulesSpec.hs | 107 +++++++++++++++++++++++++++++++++ test/FormattingSpec.hs | 113 +++-------------------------------- test/SpecHelper.hs | 9 +++ 3 files changed, 125 insertions(+), 104 deletions(-) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index 0d9ef88f..d0e23448 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -1,5 +1,6 @@ module Formatting.RulesSpec (spec) where +import Data.Text qualified as T import GHC.IsList (fromList) import JbeamEdit.Core.NodeCursor (NodeBreadcrumb (..), NodeCursor (..)) import JbeamEdit.Core.NodePath qualified as NP @@ -9,6 +10,8 @@ import SpecHelper spec :: Spec spec = do + precedenceSpec + describe "SomeKey & SomeProperty" $ do it "Eq works for same PropertyKey" $ SomeKey PadAmount == SomeKey PadAmount `shouldBe` True @@ -97,3 +100,107 @@ spec = do found ExactMatch (anyKeyThen AnyObjectKey) atArray `shouldBe` Nothing found ExactMatch (anyKeyThen AnyObjectKey) atKey `shouldBe` Just 7 found ExactMatch (anyKeyThen AnyArrayIndex) atKey `shouldBe` Nothing + +{- | When several patterns match the same node, the more specific one supplies +the property. Specificity is how many nodes a selector can match at that level: +a named key first, then a positional index, then a prefix key with the longer +prefix winning, then the wildcards. + +Written as JBFL source and formatted output on purpose. Both ends survive the +rule lookup becoming a trie, while `NodePattern` and `MatchMode` do not. +-} +precedenceSpec :: Spec +precedenceSpec = do + let cell :: Int -> Node + cell n = Number (mkNumberValue (T.pack (show n)) (fromIntegral n)) + -- Three levels deep, so Indent set two breadcrumbs down still shows. + pair a b = mkArray (fromList [mkArray (fromList [a, b]), mkArray (fromList [b, a])]) + -- Complex enough to be broken across lines, so Indent shows in the output. + topNode = + mkObject + ( fromList + [ ObjectKey + ( String "deformGroups" + , mkArray + ( fromList + [ pair (cell 1) (cell 2) + , pair (cell 3) (cell 4) + ] + ) + ) + ] + ) + rulesFrom = rulesFromSource + formatWith = flip formatNode topNode . rulesFrom + -- The second assertion is what stops the first passing for two rules that + -- happen to format the same way. + beats winner loser = do + formatWith (winner <> "\n" <> loser) `shouldBe` formatWith winner + formatWith winner `shouldNotBe` formatWith loser + named = ".deformGroups { Indent : 1; }" + positional = ".0 { Indent : 2; }" + longPrefix = ".deform* { Indent : 3; }" + shortPrefix = ".de* { Indent : 5; }" + wildcard = ".* { Indent : 6; }" + + describe "which of several matching patterns supplies a property" $ do + it "prefers a named key over a positional index" $ named `beats` positional + it "prefers a positional index over a prefix key" $ + positional `beats` longPrefix + it "prefers the longer of two prefix keys" $ longPrefix `beats` shortPrefix + it "prefers a prefix key over a wildcard" $ shortPrefix `beats` wildcard + + -- Precedence settles one property at a time. Every shipped ruleset is + -- written this way: `.*` carries Indent and TrailingComma for the whole + -- file and narrower patterns add to it, so a winner that supplied its + -- properties wholesale would strip the broad ones off every node it matched. + -- `[4]` is the last row of the selector table in JBFL_DOCS.md, and the only + -- one no shipped ruleset uses, so nothing else would notice it going away. + -- A prefix key has to reach below the node it names, like any other + -- selector under a prefix match. It is also the one a trie cannot key on + -- directly, so it is the likeliest of them to lose that reach. + it "cascades from a prefix key the same way a named key does" $ do + let byPrefix = formatWith ".deform* { Indent : 1; }" + byPrefix `shouldBe` formatWith ".deformGroups { Indent : 1; }" + byPrefix `shouldNotBe` formatWith ".deformGroups { Indent : 6; }" + + -- Length is settled before specificity, and it is the one rung with no + -- shorthand: the two patterns reach different sets of nodes, so the winner + -- alone cannot be the expected value. The outer array is indented by the + -- shorter rule, the inner ones by the longer. + it "settles length before specificity" $ do + let shorter = ".deformGroups { Indent : 7; }" + longer = ".deformGroups[*] { Indent : 1; }" + both = shorter <> "\n" <> longer + formatWith both + `shouldBe` "{\n \"deformGroups\" : [\n [\n [1, 2],\n [2, 1]\n ],\n [\n [3, 4],\n [4, 3]\n ]\n ]\n}\n" + formatWith both `shouldNotBe` formatWith shorter + formatWith both `shouldNotBe` formatWith longer + + it "matches a literal array index and prefers it over the wildcard" $ + ".deformGroups[0] { Indent : 1; }" `beats` ".deformGroups[*] { Indent : 4; }" + + it "still takes properties the winner does not set from the loser" $ do + let winnerOnly = ".deformGroups { Indent : 1; }" + loserOnly = ".de* { TrailingComma : Force; }" + formatWith (winnerOnly <> "\n" <> loserOnly) + `shouldNotBe` formatWith winnerOnly + formatWith (winnerOnly <> "\n" <> loserOnly) + `shouldNotBe` formatWith loserOnly + + -- A user's rules.jbfl is laid over the shipped one with `rs <> defaultRs` + -- (`Formatting/Config.hs`), so this is how every configured install resolves + -- its rules. The union is left-biased twice over, per pattern and per + -- property, and a trie has to reproduce both. + describe "combining a user ruleset with the shipped one" $ do + let user = rulesFrom ".deformGroups { Indent : 1; }" + shipped = rulesFrom ".deformGroups { Indent : 7; TrailingComma : Force; }" + format = flip formatNode topNode + + it "takes the user's value and keeps the rest of the shipped one" $ do + let merged = rulesFrom ".deformGroups { Indent : 1; TrailingComma : Force; }" + format (user <> shipped) `shouldBe` format merged + -- Guards the line above: without these the two rulesets could be + -- indistinguishable and the merge would prove nothing. + format user `shouldNotBe` format shipped + format merged `shouldNotBe` format user diff --git a/test/FormattingSpec.hs b/test/FormattingSpec.hs index 03fa0a4c..1b91a984 100644 --- a/test/FormattingSpec.hs +++ b/test/FormattingSpec.hs @@ -7,11 +7,7 @@ import Data.Text (Text) import Data.Text qualified as T import GHC.IsList (fromList) import JbeamEdit.Core.NodeCursor (newCursor) -import JbeamEdit.Core.NodePath qualified as NP import JbeamEdit.Formatting -import JbeamEdit.Formatting.Rules -import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL -import JbeamEdit.Parsing.DSL (parseDSL) import SpecHelper import System.FilePath (takeBaseName, ()) @@ -116,14 +112,11 @@ matchModeSpec = do ) ] ) - -- The rows array sits two breadcrumbs deep, so a one-selector pattern is - -- a prefix of its cursor and a two-selector one matches it exactly. - ruleAt p k v = - RuleSet - (fromList [(NodePattern (fromList p), fromList [(SomeKey k, SomeProperty k v)])]) - shortPattern = [AnyObjectKey] - exactPattern = [AnyObjectKey, Selector (NP.ObjectKey "rows")] - formatWith rs = formatNode rs topNode + -- The rows array sits two breadcrumbs deep, so `.*` is a prefix of its + -- cursor and `.*.rows` matches it exactly. + formatWith src = formatNode (rulesFromSource src) topNode + shortPattern prop = ".* { " <> prop <> " }" + exactPattern prop = ".*.rows { " <> prop <> " }" -- The only difference is the run of spaces before the 2, which is the -- second column padded out to the width of the first row. @@ -133,107 +126,19 @@ matchModeSpec = do describe "which match mode a property is read in" $ do it "reads AutoPad from an exact match only" $ do - formatWith (ruleAt exactPattern AutoPad True) `shouldBe` padded + formatWith (exactPattern "AutoPad : true;") `shouldBe` padded -- Without this line the assertion below also passes for a shortPattern -- that matches nothing at all, which is not what is being claimed. - formatWith (ruleAt shortPattern ComplexNewLine CNL.Force) - `shouldNotBe` baseline - formatWith (ruleAt shortPattern AutoPad True) `shouldBe` baseline + formatWith (shortPattern "ComplexNewLine : Force;") `shouldNotBe` baseline + formatWith (shortPattern "AutoPad : true;") `shouldBe` baseline it "reads ComplexNewLine from a prefix match" $ - formatWith (ruleAt shortPattern ComplexNewLine CNL.Force) - `shouldNotBe` baseline - -{- | When several patterns match the same node, the more specific one supplies -the property. Specificity is how many nodes a selector can match at that level: -a named key first, then a positional index, then a prefix key with the longer -prefix winning, then the wildcards. - -Written as JBFL source and formatted output on purpose. Both ends survive the -rule lookup becoming a trie, while `NodePattern` and `MatchMode` do not. --} -precedenceSpec :: Spec -precedenceSpec = do - let cell n = Number (mkNumberValue (T.pack (show n)) (fromIntegral n)) - -- Three levels deep, so Indent set two breadcrumbs down still shows. - pair a b = mkArray (fromList [mkArray (fromList [a, b]), mkArray (fromList [b, a])]) - -- Complex enough to be broken across lines, so Indent shows in the output. - topNode = - mkObject - ( fromList - [ ObjectKey - ( String "deformGroups" - , mkArray - ( fromList - [ pair (cell 1) (cell 2) - , pair (cell 3) (cell 4) - ] - ) - ) - ] - ) - rulesFrom src = - case parseDSL (textToLazyByteString src) of - Right rs -> rs - Left err -> error ("bad JBFL in spec: " ++ T.unpack err) - formatWith = flip formatNode topNode . rulesFrom - -- The second assertion is what stops the first passing for two rules that - -- happen to format the same way. - beats winner loser = do - formatWith (winner <> "\n" <> loser) `shouldBe` formatWith winner - formatWith winner `shouldNotBe` formatWith loser - named = ".deformGroups { Indent : 1; }" - positional = ".0 { Indent : 2; }" - longPrefix = ".deform* { Indent : 3; }" - shortPrefix = ".de* { Indent : 5; }" - wildcard = ".* { Indent : 6; }" - - describe "which of several matching patterns supplies a property" $ do - it "prefers a named key over a positional index" $ named `beats` positional - it "prefers a positional index over a prefix key" $ - positional `beats` longPrefix - it "prefers the longer of two prefix keys" $ longPrefix `beats` shortPrefix - it "prefers a prefix key over a wildcard" $ shortPrefix `beats` wildcard - - -- Precedence settles one property at a time. Every shipped ruleset is - -- written this way: `.*` carries Indent and TrailingComma for the whole - -- file and narrower patterns add to it, so a winner that supplied its - -- properties wholesale would strip the broad ones off every node it matched. - -- `[4]` is the last row of the selector table in JBFL_DOCS.md, and the only - -- one no shipped ruleset uses, so nothing else would notice it going away. - it "matches a literal array index and prefers it over the wildcard" $ - ".deformGroups[0] { Indent : 1; }" `beats` ".deformGroups[*] { Indent : 4; }" - - it "still takes properties the winner does not set from the loser" $ do - let winnerOnly = ".deformGroups { Indent : 1; }" - loserOnly = ".de* { TrailingComma : Force; }" - formatWith (winnerOnly <> "\n" <> loserOnly) - `shouldNotBe` formatWith winnerOnly - formatWith (winnerOnly <> "\n" <> loserOnly) - `shouldNotBe` formatWith loserOnly - - -- A user's rules.jbfl is laid over the shipped one with `rs <> defaultRs` - -- (`Formatting/Config.hs`), so this is how every configured install resolves - -- its rules. The union is left-biased twice over, per pattern and per - -- property, and a trie has to reproduce both. - describe "combining a user ruleset with the shipped one" $ do - let user = rulesFrom ".deformGroups { Indent : 1; }" - shipped = rulesFrom ".deformGroups { Indent : 7; TrailingComma : Force; }" - format = flip formatNode topNode - - it "takes the user's value and keeps the rest of the shipped one" $ do - let merged = rulesFrom ".deformGroups { Indent : 1; TrailingComma : Force; }" - format (user <> shipped) `shouldBe` format merged - -- Guards the line above: without these the two rulesets could be - -- indistinguishable and the merge would prove nothing. - format user `shouldNotBe` format shipped - format merged `shouldNotBe` format user + formatWith (shortPattern "ComplexNewLine : Force;") `shouldNotBe` baseline spec :: Spec spec = do mapM_ formatNodeSpec specs matchModeSpec - precedenceSpec dynamicTests <- runIO dynamicJbflTests forM_ dynamicTests $ \(outFile, formatted, expected) -> diff --git a/test/SpecHelper.hs b/test/SpecHelper.hs index 483f95ef..8b257671 100644 --- a/test/SpecHelper.hs +++ b/test/SpecHelper.hs @@ -1,5 +1,6 @@ module SpecHelper ( textToLazyByteString, + rulesFromSource, applySpecOnInput, works, listFilesInDir, @@ -15,6 +16,8 @@ import Data.List (isPrefixOf, isSuffixOf) import Data.Text qualified as T import Data.Text.Encoding (encodeUtf8) import JbeamEdit.Core.Node +import JbeamEdit.Formatting.Rules (RuleSet) +import JbeamEdit.Parsing.DSL (parseDSL) import System.Directory (getDirectoryContents) import Test.Hspec @@ -45,3 +48,9 @@ works = it "works" textToLazyByteString :: String -> ByteString textToLazyByteString = BS.fromStrict . encodeUtf8 . T.pack + +rulesFromSource :: String -> RuleSet +rulesFromSource src = + case parseDSL (textToLazyByteString src) of + Right rs -> rs + Left err -> error ("bad JBFL in spec: " ++ T.unpack err) From c299d8f4be82805b726e920068252c2d9e822bfe Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:10:52 +0200 Subject: [PATCH 06/35] Updated Ord instance for NodePatternSelector --- src/JbeamEdit/Core/NodePath.hs | 2 +- src/JbeamEdit/Formatting/Rules.hs | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/JbeamEdit/Core/NodePath.hs b/src/JbeamEdit/Core/NodePath.hs index 342817b3..ba96c9a8 100644 --- a/src/JbeamEdit/Core/NodePath.hs +++ b/src/JbeamEdit/Core/NodePath.hs @@ -29,7 +29,7 @@ data NodeSelector | ObjectKey Text | ObjectPrefixKey Text | ObjectIndex Int - deriving (Eq, Ord, Read, Show) + deriving (Eq, Read, Show) {- | node path A NodePath is a Sequence of selectors to that point out a certain point in a Node tree, either to point at as something when fetching it from Node or to point to something compare that I at a certain point when doing updates. diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 59f68477..343027b5 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -40,7 +40,7 @@ import Data.Text qualified as T import Data.Type.Equality ((:~:) (Refl)) import JbeamEdit.Core.Node import JbeamEdit.Core.NodeCursor qualified as NC -import JbeamEdit.Core.NodePath (NodeSelector (..)) +import JbeamEdit.Core.NodePath qualified as NP (NodeSelector (..)) import JbeamEdit.Formatting.Rules.ComplexNewLine (ComplexNewLine) import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL import JbeamEdit.Formatting.Rules.TrailingComma (TrailingComma) @@ -49,16 +49,19 @@ import Text.Read qualified as TR data NodePatternSelector = AnyObjectKey | AnyArrayIndex - | Selector NodeSelector + | Selector NP.NodeSelector deriving stock (Eq, Read, Show) instance Ord NodePatternSelector where compare a b = compare (rank a) (rank b) where - rank :: NodePatternSelector -> (Int, Maybe NodeSelector) - rank AnyArrayIndex = (2, Nothing) - rank AnyObjectKey = (1, Nothing) - rank (Selector s) = (0, Just s) + rank :: NodePatternSelector -> (Int, Int, Text) + rank (Selector (NP.ObjectKey key)) = (0, 0, key) + rank (Selector (NP.ArrayIndex index)) = (1, index, "") + rank (Selector (NP.ObjectIndex i)) = (2, i, "") + rank (Selector (NP.ObjectPrefixKey prefix)) = (3, negate (T.length prefix), prefix) + rank AnyObjectKey = (4, 0, "") + rank AnyArrayIndex = (5, 0, "") newtype NodePattern = NodePattern (Seq NodePatternSelector) From c049ac766e1d0e34c1fe66dfd54411d244b6ce26 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 18:24:31 +0200 Subject: [PATCH 07/35] Moved Ord instance --- src/JbeamEdit/Core/NodePath.hs | 12 +++++++++++- src/JbeamEdit/Formatting/Rules.hs | 21 +++++---------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/JbeamEdit/Core/NodePath.hs b/src/JbeamEdit/Core/NodePath.hs index ba96c9a8..c6b214bf 100644 --- a/src/JbeamEdit/Core/NodePath.hs +++ b/src/JbeamEdit/Core/NodePath.hs @@ -9,9 +9,10 @@ module JbeamEdit.Core.NodePath ( ) where import Data.Either.Extra (maybeToEither) +import Data.Function (on) import Data.Sequence (Seq (..)) import Data.Text (Text) -import Data.Text qualified as T (isPrefixOf, show) +import Data.Text qualified as T (isPrefixOf, length, show) import Data.Vector (Vector) import Data.Vector qualified as V import GHC.IsList (IsList (..)) @@ -31,6 +32,15 @@ data NodeSelector | ObjectIndex Int deriving (Eq, Read, Show) +instance Ord NodeSelector where + compare = on compare rank + where + rank :: NodeSelector -> (Int, Int, Text) + rank (ObjectKey key) = (0, 0, key) + rank (ArrayIndex index) = (1, index, "") + rank (ObjectIndex i) = (2, i, "") + rank (ObjectPrefixKey prefix) = (3, negate (T.length prefix), prefix) + {- | node path A NodePath is a Sequence of selectors to that point out a certain point in a Node tree, either to point at as something when fetching it from Node or to point to something compare that I at a certain point when doing updates. -} diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 343027b5..76e81aa0 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -50,28 +50,17 @@ data NodePatternSelector = AnyObjectKey | AnyArrayIndex | Selector NP.NodeSelector - deriving stock (Eq, Read, Show) - -instance Ord NodePatternSelector where - compare a b = compare (rank a) (rank b) - where - rank :: NodePatternSelector -> (Int, Int, Text) - rank (Selector (NP.ObjectKey key)) = (0, 0, key) - rank (Selector (NP.ArrayIndex index)) = (1, index, "") - rank (Selector (NP.ObjectIndex i)) = (2, i, "") - rank (Selector (NP.ObjectPrefixKey prefix)) = (3, negate (T.length prefix), prefix) - rank AnyObjectKey = (4, 0, "") - rank AnyArrayIndex = (5, 0, "") + deriving stock (Eq, Ord, Read, Show) newtype NodePattern = NodePattern (Seq NodePatternSelector) deriving stock (Eq, Read, Show) instance Monoid RuleSet where - mempty = RuleSet M.empty + mempty = RuleSet M.empty [] M.empty M.empty instance Semigroup RuleSet where - (RuleSet rs1) <> (RuleSet rs2) = RuleSet (M.unionWith M.union rs1 rs2) + (RuleSet rs1 ps1 aok1 aai1) <> (RuleSet rs2 ps2 aok2 aai2) = RuleSet (M.unionWith M.union rs1 rs2) (ps1 <> ps2) (aok1 <> aok2) (aai1 <> aai2) instance Ord NodePattern where compare (NodePattern a) (NodePattern b) = @@ -216,8 +205,8 @@ deprecatedAliases = type Rule = Map SomeKey SomeProperty -newtype RuleSet - = RuleSet (Map NodePattern Rule) +data RuleSet + = RuleSet (Map NP.NodeSelector Rule) [(Text,Rule)] Rule Rule deriving stock (Eq, Read, Show) lookupProp :: (Eq a, Read a, Show a) => PropertyKey a -> Rule -> Maybe a From 2a9c631c14033a51cf48df5b20f4d14c6c099c48 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 18:44:36 +0200 Subject: [PATCH 08/35] Added rsHere and rsBelow --- src/JbeamEdit/Formatting/Rules.hs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 76e81aa0..8769a233 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -57,10 +57,17 @@ newtype NodePattern deriving stock (Eq, Read, Show) instance Monoid RuleSet where - mempty = RuleSet M.empty [] M.empty M.empty + mempty = RuleSet M.empty [] M.empty M.empty mempty mempty instance Semigroup RuleSet where - (RuleSet rs1 ps1 aok1 aai1) <> (RuleSet rs2 ps2 aok2 aai2) = RuleSet (M.unionWith M.union rs1 rs2) (ps1 <> ps2) (aok1 <> aok2) (aai1 <> aai2) + (RuleSet rs1 ps1 aok1 aai1 h1 b1) <> (RuleSet rs2 ps2 aok2 aai2 h2 b2) = + RuleSet + (M.union rs1 rs2) + (ps1 <> ps2) + (M.union aok1 aok2) + (M.union aai1 aai2) + (h1 <> h2) + (b1 <> b2) instance Ord NodePattern where compare (NodePattern a) (NodePattern b) = @@ -206,7 +213,14 @@ deprecatedAliases = type Rule = Map SomeKey SomeProperty data RuleSet - = RuleSet (Map NP.NodeSelector Rule) [(Text,Rule)] Rule Rule + = RuleSet + { rsBySelectors :: Map NP.NodeSelector RuleSet + , rsPrefixes :: [(Text, Map NP.NodeSelector RuleSet)] + , rsAnyObjectKey :: Map NP.NodeSelector RuleSet + , rsAnyArrayIndex :: Map NP.NodeSelector RuleSet + , rsHere :: Rule + , rsBelow :: Rule + } deriving stock (Eq, Read, Show) lookupProp :: (Eq a, Read a, Show a) => PropertyKey a -> Rule -> Maybe a @@ -277,5 +291,4 @@ sameBy matchMode f = go -- TODO: when possible upgrade to containers 0.8 and migrate to M.filterKeys findPropertiesForCursor :: MatchMode -> NC.NodeCursor -> RuleSet -> Rule -findPropertiesForCursor matchMode cursor (RuleSet rs) = - fold (M.filterWithKey (const . compareCursorAndPattern matchMode cursor) rs) +findPropertiesForCursor = undefined From 7d46f3861947c08c1127c6a430c1412ffb9ce571 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 18:55:54 +0200 Subject: [PATCH 09/35] Fixed RuleSet type --- src/JbeamEdit/Formatting/Rules.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 8769a233..e15e368b 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -215,9 +215,9 @@ type Rule = Map SomeKey SomeProperty data RuleSet = RuleSet { rsBySelectors :: Map NP.NodeSelector RuleSet - , rsPrefixes :: [(Text, Map NP.NodeSelector RuleSet)] - , rsAnyObjectKey :: Map NP.NodeSelector RuleSet - , rsAnyArrayIndex :: Map NP.NodeSelector RuleSet + , rsPrefixes :: [(Text, RuleSet)] + , rsAnyObjectKey :: RuleSet + , rsAnyArrayIndex :: RuleSet , rsHere :: Rule , rsBelow :: Rule } From 171612afd012e134b77d3b32657b6c7c4f35191f Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sun, 16 Aug 2026 19:21:23 +0200 Subject: [PATCH 10/35] More RuleSet fixes --- src/JbeamEdit/Formatting/Rules.hs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index e15e368b..80c759b1 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -57,17 +57,18 @@ newtype NodePattern deriving stock (Eq, Read, Show) instance Monoid RuleSet where - mempty = RuleSet M.empty [] M.empty M.empty mempty mempty + mempty = RuleSet M.empty [] mempty mempty M.empty M.empty instance Semigroup RuleSet where (RuleSet rs1 ps1 aok1 aai1 h1 b1) <> (RuleSet rs2 ps2 aok2 aai2 h2 b2) = RuleSet (M.union rs1 rs2) (ps1 <> ps2) - (M.union aok1 aok2) - (M.union aai1 aai2) + (liftUnion aok1 aok2) + (liftUnion aai1 aai2) (h1 <> h2) (b1 <> b2) + where liftUnion = liftA2 (<>) instance Ord NodePattern where compare (NodePattern a) (NodePattern b) = @@ -214,10 +215,10 @@ type Rule = Map SomeKey SomeProperty data RuleSet = RuleSet - { rsBySelectors :: Map NP.NodeSelector RuleSet + { rsBySelectors :: Map NP.NodeSelector (Maybe RuleSet) , rsPrefixes :: [(Text, RuleSet)] - , rsAnyObjectKey :: RuleSet - , rsAnyArrayIndex :: RuleSet + , rsAnyObjectKey :: Maybe RuleSet + , rsAnyArrayIndex :: Maybe RuleSet , rsHere :: Rule , rsBelow :: Rule } From f9791b92fbe06cb331e4e174c2477ea73f23fa0d Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Fri, 21 Aug 2026 20:33:09 +0200 Subject: [PATCH 11/35] Implemented new jbfl parsing logic --- src/JbeamEdit/Parsing/DSL.hs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/JbeamEdit/Parsing/DSL.hs b/src/JbeamEdit/Parsing/DSL.hs index 83c70bfe..e16b9f93 100644 --- a/src/JbeamEdit/Parsing/DSL.hs +++ b/src/JbeamEdit/Parsing/DSL.hs @@ -13,18 +13,19 @@ import Data.Bifunctor (first) import Data.ByteString qualified as BS import Data.ByteString.Lazy qualified as LBS import Data.Char (isSpace) +import Data.Foldable (fold) import Data.Functor (void, ($>)) import Data.Functor.Identity (Identity (..)) import Data.List.NonEmpty qualified as NE (fromList) import Data.Map (Map) -import Data.Map qualified as M (fromList, fromListWith, union) -import Data.Sequence qualified as Seq (fromList) +import Data.Map qualified as M (empty, fromList, singleton) import Data.Set qualified as S (fromList) import Data.Text (Text) import Data.Text qualified as T (init, isSuffixOf, unpack) import Data.Text.Encoding (decodeUtf8') import Data.Word (Word8) import JbeamEdit.Core.NodePath +import JbeamEdit.Core.NodePath qualified as NP (NodeSelector (..)) import JbeamEdit.Formatting.Rules import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL import JbeamEdit.Formatting.Rules.TrailingComma qualified as TC @@ -67,7 +68,7 @@ patternSelectorParser = , arrayIndexParser "array index" ] -patternParser :: JbflParser NodePattern +patternParser :: JbflParser [NodePatternSelector] patternParser = do pat <- skipWhiteSpace *> patternSelectors c <- MP.lookAhead B.asciiChar @@ -75,7 +76,7 @@ patternParser = do ',' -> byteChar ',' $> pat _ -> skipWhiteSpace $> pat where - patternSelectors = NodePattern . Seq.fromList <$> MP.some patternSelectorParser + patternSelectors = MP.some patternSelectorParser tryDecodeKey :: [Word8] -> (Text -> Maybe SomeKey) -> Maybe SomeKey tryDecodeKey bs f = @@ -159,7 +160,7 @@ deprecatedBoolPropertyParser sk valTrue valFalse = do separatorParser :: JbflParser () separatorParser = skipWhiteSpace *> void (byteChar ';') <* skipWhiteSpace -ruleParser :: JbflParser ([NodePattern], Map SomeKey SomeProperty) +ruleParser :: JbflParser ([[NodePatternSelector]], Map SomeKey SomeProperty) ruleParser = do pats <- MP.some patternParser skipWhiteSpace @@ -170,11 +171,20 @@ ruleParser = do skipWhiteSpace pure (pats, M.fromList props) -separateRulesets :: [([a], b)] -> [(a, b)] -separateRulesets rs = [(pat, props) | (pats, props) <- rs, pat <- pats] +combineRuleSets + :: ([[NodePatternSelector]], Map SomeKey SomeProperty) -> RuleSet +combineRuleSets (_, props) + | props == M.empty = mempty +combineRuleSets (pats, props) = fold [fold (go pat) | pat <- pats] + where + go [] = Just (mempty {rsHere = props}) + go (AnyObjectKey : pats') = Just (mempty {rsAnyObjectKey = go pats'}) + go (AnyArrayIndex : pats') = Just (mempty {rsAnyArrayIndex = go pats'}) + go (Selector (NP.ObjectPrefixKey p) : pats') = Just (mempty {rsPrefixes = maybe [] (\x -> [(p, x)]) (go pats')}) + go (Selector s : pats') = Just (mempty {rsBySelectors = M.singleton s (go pats')}) ruleSetParser :: JbflParser RuleSet -ruleSetParser = RuleSet . M.fromListWith M.union . separateRulesets <$> MP.some singleRuleSet +ruleSetParser = foldMap combineRuleSets <$> MP.some singleRuleSet where singleRuleSet = skipComment *> ruleParser <* skipComment From 187c0a8bd0466691c0c9987d4cff1008919a3591 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:17:45 +0200 Subject: [PATCH 12/35] Build the matching specs from JBFL source --- test/Formatting/RulesSpec.hs | 46 +++++++++++++----------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index d0e23448..2e52811f 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -3,7 +3,6 @@ module Formatting.RulesSpec (spec) where import Data.Text qualified as T import GHC.IsList (fromList) import JbeamEdit.Core.NodeCursor (NodeBreadcrumb (..), NodeCursor (..)) -import JbeamEdit.Core.NodePath qualified as NP import JbeamEdit.Formatting import JbeamEdit.Formatting.Rules import SpecHelper @@ -48,42 +47,30 @@ spec = do let cursorAt crumbs = NodeCursor (fromList crumbs) nodesCursor = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "nodes"] - ruleSetFor p = - RuleSet - ( fromList - [ - ( NodePattern (fromList p) - , fromList [(SomeKey PadAmount, SomeProperty PadAmount 7)] - ) - ] - ) - found mode p = lookupPropertyForCursor mode PadAmount (ruleSetFor p) + found mode pat = + lookupPropertyForCursor + mode + PadAmount + (rulesFromSource (pat ++ " { PadAmount: 7; }")) it "matches a pattern of the same length in both modes" $ do - let p = [AnyObjectKey, Selector (NP.ObjectKey "nodes")] - found PrefixMatch p nodesCursor `shouldBe` Just 7 - found ExactMatch p nodesCursor `shouldBe` Just 7 + found PrefixMatch ".*.nodes" nodesCursor `shouldBe` Just 7 + found ExactMatch ".*.nodes" nodesCursor `shouldBe` Just 7 it "matches a shorter pattern only as a prefix" $ do - let p = [AnyObjectKey] - found PrefixMatch p nodesCursor `shouldBe` Just 7 - found ExactMatch p nodesCursor `shouldBe` Nothing + found PrefixMatch ".*" nodesCursor `shouldBe` Just 7 + found ExactMatch ".*" nodesCursor `shouldBe` Nothing it "never matches a pattern longer than the cursor" $ do - let p = - [ AnyObjectKey - , Selector (NP.ObjectKey "nodes") - , AnyArrayIndex - ] - found PrefixMatch p nodesCursor `shouldBe` Nothing - found ExactMatch p nodesCursor `shouldBe` Nothing + found PrefixMatch ".*.nodes[*]" nodesCursor `shouldBe` Nothing + found ExactMatch ".*.nodes[*]" nodesCursor `shouldBe` Nothing -- `.test*` is documented JBFL (JBFL_DOCS.md) and cannot be looked up by -- equality, since the stored key is a prefix of the breadcrumb rather than -- the same text. It is the one selector a trie has to solve rather than -- key on directly. it "matches a prefix key against the rest of the breadcrumb" $ do - let p k = [AnyObjectKey, Selector (NP.ObjectPrefixKey k)] + let p k = ".*." ++ k ++ "*" atDeformGroups = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "deformGroups"] @@ -95,11 +82,10 @@ spec = do it "keeps the two wildcards apart" $ do let atArray = cursorAt [ObjectIndexAndKey 0 "part", ArrayIndex 0] atKey = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "k"] - anyKeyThen w = [AnyObjectKey, w] - found ExactMatch (anyKeyThen AnyArrayIndex) atArray `shouldBe` Just 7 - found ExactMatch (anyKeyThen AnyObjectKey) atArray `shouldBe` Nothing - found ExactMatch (anyKeyThen AnyObjectKey) atKey `shouldBe` Just 7 - found ExactMatch (anyKeyThen AnyArrayIndex) atKey `shouldBe` Nothing + found ExactMatch ".*[*]" atArray `shouldBe` Just 7 + found ExactMatch ".*.*" atArray `shouldBe` Nothing + found ExactMatch ".*.*" atKey `shouldBe` Just 7 + found ExactMatch ".*[*]" atKey `shouldBe` Nothing {- | When several patterns match the same node, the more specific one supplies the property. Specificity is how many nodes a selector can match at that level: From 645b9f883540f997cc5fb4a8013999efab0afc51 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:14:08 +0200 Subject: [PATCH 13/35] Drop the pattern comparison the trie replaces --- cabal.project.dev | 2 +- src/JbeamEdit/Formatting/Rules.hs | 32 ++++++------------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/cabal.project.dev b/cabal.project.dev index c083d613..3035df24 100644 --- a/cabal.project.dev +++ b/cabal.project.dev @@ -17,4 +17,4 @@ package jbeam-edit documentation: False tests: True - flags: +dump-ast +transformation -windows-example-paths + flags: -modern-containers +dump-ast +transformation -windows-example-paths diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 4163368e..02734df1 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-} @@ -26,6 +27,7 @@ module JbeamEdit.Formatting.Rules ( findPropertiesForCursor, ) where +import Data.Maybe (fromMaybe) import Data.Bool (bool) import Data.Foldable (fold) import Data.Function (on) @@ -266,30 +268,8 @@ lookupPropertyForCursor => MatchMode -> PropertyKey a -> RuleSet -> NC.NodeCursor -> Maybe a lookupPropertyForCursor matchMode key rs cursor = lookupProp key (findPropertiesForCursor matchMode cursor rs) -comparePC :: NodePatternSelector -> NC.NodeBreadcrumb -> Bool -comparePC AnyObjectKey (NC.ObjectIndexAndKey _ _) = True -comparePC AnyArrayIndex (NC.ArrayIndex _) = True -comparePC (Selector s) bc = NC.compareSB s bc -comparePC _ _ = False - -compareCursorAndPattern :: MatchMode -> NC.NodeCursor -> NodePattern -> Bool -compareCursorAndPattern matchMode (NC.NodeCursor c) (NodePattern p) = sameBy matchMode comparePC p c - -type SelCrumbCompFun = NodePatternSelector -> NC.NodeBreadcrumb -> Bool - -sameBy - :: MatchMode - -> SelCrumbCompFun - -> Seq NodePatternSelector - -> Seq NC.NodeBreadcrumb - -> Bool -sameBy matchMode f = go - where - go (p :<| ps) (b :<| bs) = - let res = f p b - in res && go ps bs - go ps bs = Seq.null ps && (Seq.null bs || PrefixMatch == matchMode) - --- TODO: migrate to M.filterKeys once the stack snapshot ships containers 0.8 findPropertiesForCursor :: MatchMode -> NC.NodeCursor -> RuleSet -> Rule -findPropertiesForCursor = undefined +findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor + where + go (NC.ObjectIndexAndKey i k :<| bs) rs = go bs (fold rs.rsAnyObjectKey) + go _ rs = rs.rsHere From 3c9397ed60439928268bcd52b76a172a3300c822 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:59:42 +0200 Subject: [PATCH 14/35] Walk the trie by breadcrumb in the rule lookup --- src/JbeamEdit/Formatting/Rules.hs | 25 ++++++++++++++++++------- src/JbeamEdit/Parsing/DSL.hs | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 02734df1..eaacf289 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -1,6 +1,6 @@ -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} +{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} @@ -27,13 +27,13 @@ module JbeamEdit.Formatting.Rules ( findPropertiesForCursor, ) where -import Data.Maybe (fromMaybe) import Data.Bool (bool) import Data.Foldable (fold) import Data.Function (on) import Data.List (find) import Data.Map (Map) import Data.Map qualified as M +import Data.Maybe (fromMaybe) import Data.Ord (Down (..)) import Data.Sequence (Seq (..)) import Data.Sequence qualified as Seq (length, null) @@ -70,7 +70,8 @@ instance Semigroup RuleSet where (liftUnion aai1 aai2) (h1 <> h2) (b1 <> b2) - where liftUnion = liftA2 (<>) + where + liftUnion = liftA2 (<>) instance Ord NodePattern where compare (NodePattern a) (NodePattern b) = @@ -217,7 +218,7 @@ type Rule = Map SomeKey SomeProperty data RuleSet = RuleSet - { rsBySelectors :: Map NP.NodeSelector (Maybe RuleSet) + { rsBySelectors :: Map NP.NodeSelector RuleSet , rsPrefixes :: [(Text, RuleSet)] , rsAnyObjectKey :: Maybe RuleSet , rsAnyArrayIndex :: Maybe RuleSet @@ -270,6 +271,16 @@ lookupPropertyForCursor matchMode key rs cursor = lookupProp key (findProperties findPropertiesForCursor :: MatchMode -> NC.NodeCursor -> RuleSet -> Rule findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor - where - go (NC.ObjectIndexAndKey i k :<| bs) rs = go bs (fold rs.rsAnyObjectKey) - go _ rs = rs.rsHere + where + go (NC.ObjectIndexAndKey i k :<| bs) rs = + go + bs + ( fold (M.lookup (NP.ObjectKey k) rs.rsBySelectors) + <> fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) + <> fold rs.rsAnyObjectKey + ) + go (NC.ArrayIndex i :<| bs) rs = + go + bs + (fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) <> fold rs.rsAnyArrayIndex) + go _ rs = rs.rsHere diff --git a/src/JbeamEdit/Parsing/DSL.hs b/src/JbeamEdit/Parsing/DSL.hs index e16b9f93..4601912d 100644 --- a/src/JbeamEdit/Parsing/DSL.hs +++ b/src/JbeamEdit/Parsing/DSL.hs @@ -181,7 +181,7 @@ combineRuleSets (pats, props) = fold [fold (go pat) | pat <- pats] go (AnyObjectKey : pats') = Just (mempty {rsAnyObjectKey = go pats'}) go (AnyArrayIndex : pats') = Just (mempty {rsAnyArrayIndex = go pats'}) go (Selector (NP.ObjectPrefixKey p) : pats') = Just (mempty {rsPrefixes = maybe [] (\x -> [(p, x)]) (go pats')}) - go (Selector s : pats') = Just (mempty {rsBySelectors = M.singleton s (go pats')}) + go (Selector s : pats') = Just (mempty {rsBySelectors = maybe M.empty (M.singleton s) (go pats')}) ruleSetParser :: JbflParser RuleSet ruleSetParser = foldMap combineRuleSets <$> MP.some singleRuleSet From 2e5e57763ad9e72374faf8059b1c96a2c93c9468 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 12:36:53 +0200 Subject: [PATCH 15/35] Fixed lookupPropertyForCursor according to the new RuleSet --- src/JbeamEdit/Formatting/Rules.hs | 49 +++++++++++++++++++++++-------- src/JbeamEdit/Parsing/DSL.hs | 7 +++-- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index eaacf289..178349d7 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -19,6 +19,7 @@ module JbeamEdit.Formatting.Rules ( lookupKey, allProperties, deprecatedAliases, + prefixProperties, keyName, applyPadLogic, complexNewLine, @@ -33,10 +34,9 @@ import Data.Function (on) import Data.List (find) import Data.Map (Map) import Data.Map qualified as M -import Data.Maybe (fromMaybe) import Data.Ord (Down (..)) import Data.Sequence (Seq (..)) -import Data.Sequence qualified as Seq (length, null) +import Data.Sequence qualified as Seq (length) import Data.Text (Text) import Data.Text qualified as T import Data.Type.Equality ((:~:) (Refl)) @@ -52,26 +52,32 @@ data NodePatternSelector = AnyObjectKey | AnyArrayIndex | Selector NP.NodeSelector - deriving stock (Eq, Ord, Read, Show) + deriving stock (Eq, Read, Show) newtype NodePattern = NodePattern (Seq NodePatternSelector) deriving stock (Eq, Read, Show) +instance Ord NodePatternSelector where + compare = on compare rank + where + rank :: NodePatternSelector -> (Int, Maybe NP.NodeSelector) + rank AnyArrayIndex = (2, Nothing) + rank AnyObjectKey = (1, Nothing) + rank (Selector s) = (0, Just s) + instance Monoid RuleSet where mempty = RuleSet M.empty [] mempty mempty M.empty M.empty instance Semigroup RuleSet where (RuleSet rs1 ps1 aok1 aai1 h1 b1) <> (RuleSet rs2 ps2 aok2 aai2 h2 b2) = RuleSet - (M.union rs1 rs2) + (M.unionWith (<>) rs1 rs2) (ps1 <> ps2) - (liftUnion aok1 aok2) - (liftUnion aai1 aai2) + (aok1 <> aok2) + (aai1 <> aai2) (h1 <> h2) (b1 <> b2) - where - liftUnion = liftA2 (<>) instance Ord NodePattern where compare (NodePattern a) (NodePattern b) = @@ -193,6 +199,13 @@ intProperties = map SomeKey [PadAmount, PadDecimals, Indent] allProperties :: [SomeKey] allProperties = boolProperties ++ enumProperties ++ intProperties +prefixProperties :: [SomeKey] +prefixProperties = + map + SomeKey + [ PadAmount + ] + -- | Maps deprecated property names to (key, value-when-true, value-when-false). deprecatedAliases :: [(Text, (SomeKey, SomeProperty, SomeProperty))] deprecatedAliases = @@ -272,15 +285,25 @@ lookupPropertyForCursor matchMode key rs cursor = lookupProp key (findProperties findPropertiesForCursor :: MatchMode -> NC.NodeCursor -> RuleSet -> Rule findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor where + go Empty rs = rs.rsHere <> rs.rsBelow go (NC.ObjectIndexAndKey i k :<| bs) rs = go bs - ( fold (M.lookup (NP.ObjectKey k) rs.rsBySelectors) - <> fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) - <> fold rs.rsAnyObjectKey + ( addBelowProps rs $ + fold (M.lookup (NP.ObjectKey k) rs.rsBySelectors) + <> fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) + <> foldMap snd (find (\(prefix, _) -> T.isPrefixOf prefix k) rs.rsPrefixes) + <> fold rs.rsAnyObjectKey ) go (NC.ArrayIndex i :<| bs) rs = go bs - (fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) <> fold rs.rsAnyArrayIndex) - go _ rs = rs.rsHere + ( addBelowProps rs $ + fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) + <> fold rs.rsAnyArrayIndex + ) + addBelowProps rsAbove rs = + rs + { rsBelow = + bool rs.rsBelow (rs.rsBelow <> rsAbove.rsBelow) (matchMode == PrefixMatch) + } diff --git a/src/JbeamEdit/Parsing/DSL.hs b/src/JbeamEdit/Parsing/DSL.hs index 4601912d..4a755d36 100644 --- a/src/JbeamEdit/Parsing/DSL.hs +++ b/src/JbeamEdit/Parsing/DSL.hs @@ -18,7 +18,7 @@ import Data.Functor (void, ($>)) import Data.Functor.Identity (Identity (..)) import Data.List.NonEmpty qualified as NE (fromList) import Data.Map (Map) -import Data.Map qualified as M (empty, fromList, singleton) +import Data.Map qualified as M (empty, fromList, partitionWithKey, singleton) import Data.Set qualified as S (fromList) import Data.Text (Text) import Data.Text qualified as T (init, isSuffixOf, unpack) @@ -177,7 +177,10 @@ combineRuleSets (_, props) | props == M.empty = mempty combineRuleSets (pats, props) = fold [fold (go pat) | pat <- pats] where - go [] = Just (mempty {rsHere = props}) + go :: [NodePatternSelector] -> Maybe RuleSet + go [] = Just (mempty {rsHere = hereProps, rsBelow = belowProps}) + where + (belowProps, hereProps) = M.partitionWithKey (\k _ -> k `elem` prefixProperties) props go (AnyObjectKey : pats') = Just (mempty {rsAnyObjectKey = go pats'}) go (AnyArrayIndex : pats') = Just (mempty {rsAnyArrayIndex = go pats'}) go (Selector (NP.ObjectPrefixKey p) : pats') = Just (mempty {rsPrefixes = maybe [] (\x -> [(p, x)]) (go pats')}) From b2fa76c539f6b156efe308c56b4c95b2b4e0bc22 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 12:37:55 +0200 Subject: [PATCH 16/35] Enabled -XPartialTypeSignatures in cabal.project.dev --- cabal.project.dev | 1 + 1 file changed, 1 insertion(+) diff --git a/cabal.project.dev b/cabal.project.dev index 3035df24..a4d888e0 100644 --- a/cabal.project.dev +++ b/cabal.project.dev @@ -14,6 +14,7 @@ package jbeam-edit ghc-options: -haddock -Wno-invalid-haddock + -XPartialTypeSignatures documentation: False tests: True From e12ae101cf4e66666595e72b5c496a154be4d0a0 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:05:41 +0200 Subject: [PATCH 17/35] Added all the ComplexNewLine properties to the prefix property list --- src/JbeamEdit/Formatting/Rules.hs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 178349d7..1229946a 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -201,10 +201,7 @@ allProperties = boolProperties ++ enumProperties ++ intProperties prefixProperties :: [SomeKey] prefixProperties = - map - SomeKey - [ PadAmount - ] + SomeKey PadAmount : [SomeKey ComplexNewLine] -- | Maps deprecated property names to (key, value-when-true, value-when-false). deprecatedAliases :: [(Text, (SomeKey, SomeProperty, SomeProperty))] @@ -299,7 +296,7 @@ findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor go bs ( addBelowProps rs $ - fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) + fold (M.lookup (NP.ArrayIndex i) rs.rsBySelectors) <> fold rs.rsAnyArrayIndex ) addBelowProps rsAbove rs = From 1a2738552357b3a5fabb07ab4328e1bace0b6b8e Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:10:02 +0200 Subject: [PATCH 18/35] Added Indent to prefixProperties --- src/JbeamEdit/Formatting/Rules.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 1229946a..d170e96f 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -201,7 +201,9 @@ allProperties = boolProperties ++ enumProperties ++ intProperties prefixProperties :: [SomeKey] prefixProperties = - SomeKey PadAmount : [SomeKey ComplexNewLine] + SomeKey ComplexNewLine + : SomeKey TrailingComma + : map SomeKey [PadAmount, Indent] -- | Maps deprecated property names to (key, value-when-true, value-when-false). deprecatedAliases :: [(Text, (SomeKey, SomeProperty, SomeProperty))] From e6a3a7b605f05bccd7ed3e4c7193c352be28434e Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:11:00 +0200 Subject: [PATCH 19/35] Regenerated JBFL example AST --- examples/ast/jbfl/complex.hs | 693 +++++++++++++++++------------------ examples/ast/jbfl/minimal.hs | 544 +++++++++++++-------------- 2 files changed, 608 insertions(+), 629 deletions(-) diff --git a/examples/ast/jbfl/complex.hs b/examples/ast/jbfl/complex.hs index 05881d91..c03fe1fa 100644 --- a/examples/ast/jbfl/complex.hs +++ b/examples/ast/jbfl/complex.hs @@ -1,364 +1,335 @@ RuleSet - ( fromList - [ - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "beams" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "components" ), Selector - ( ObjectKey "electrics" ), Selector - ( ObjectKey "smoothers" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "flexbodies" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "props" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots2" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "beams" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "flexbodies" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), AnyObjectKey, Selector - ( ObjectKey "off" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 10 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), AnyObjectKey, Selector - ( ObjectKey "on" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 10 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "burnEfficiency" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "torque" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "torqueModIntake" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "torqueModMult" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex, AnyArrayIndex ] ), fromList - [ ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "props" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots2" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "beams" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "controller" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "flexbodies" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "abs" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "battery" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "chassis_gaugelight_warning" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "checkengine" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "dumptruck_gaugelight_warning" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "hazard" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "highbeam" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "lowfuel" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "lowpressure" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "parkingbrake" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "signal_L" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), Selector - ( ObjectKey "signal_R" ) ] ), fromList - [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex ] ), fromList - [ ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "powertrain" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "props" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "rails" ), AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots2" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "triangles" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "variables" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList [ AnyObjectKey, Selector ( ObjectKey "beams" ) ] ), fromList - [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "glowMap" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey AutoPadSubObjects, SomeProperty AutoPadSubObjects True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "information" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "mainEngine" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList [ AnyObjectKey, Selector ( ObjectKey "nodes" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey AutoPad, SomeProperty AutoPad True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "soundConfig" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "soundConfigExhaust" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "sounds" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "triangles" ) ] ), fromList - [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ] ), - ( NodePattern - ( fromList [ AnyObjectKey ] ), fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "beams", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + [ + ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), + ( ObjectKey "components", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "electrics", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "smoothers", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "controller", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "flexbodies", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "glowMap", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "abs", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "battery", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "chassis_gaugelight_warning", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "checkengine", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "dumptruck_gaugelight_warning", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "hazard", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "highbeam", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "lowfuel", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "lowpressure", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "parkingbrake", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "signal_L", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), + ( ObjectKey "signal_R", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ + ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ) ], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "off", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ + ( SomeKey PadAmount, SomeProperty PadAmount 10 ) ] } ), + ( ObjectKey "on", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + [ + ( SomeKey PadAmount, SomeProperty PadAmount 10 ) ] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey AutoPadSubObjects, SomeProperty AutoPadSubObjects True ) ], rsBelow = fromList [] } ), + ( ObjectKey "information", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "mainEngine", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "burnEfficiency", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "torque", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "torqueModIntake", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "torqueModMult", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "nodes", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), + ( ObjectKey "powertrain", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "props", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "rails", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "slots", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "slots2", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "soundConfig", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "soundConfigExhaust", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "sounds", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "triangles", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + [ + ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), + ( ObjectKey "variables", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ ( SomeKey Indent, SomeProperty Indent 2 ), - ( SomeKey TrailingComma, SomeProperty TrailingComma None ) ] ) ] ) \ No newline at end of file + ( SomeKey TrailingComma, SomeProperty TrailingComma None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } diff --git a/examples/ast/jbfl/minimal.hs b/examples/ast/jbfl/minimal.hs index d2c37cd3..a95efa55 100644 --- a/examples/ast/jbfl/minimal.hs +++ b/examples/ast/jbfl/minimal.hs @@ -1,269 +1,277 @@ RuleSet - ( fromList - [ - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "beams" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "components" ), Selector - ( ObjectKey "electrics" ), Selector - ( ObjectKey "smoothers" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "flexbodies" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "props" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots2" ), AnyArrayIndex, AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "beams" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "flexbodies" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "burnEfficiency" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "torque" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "torqueModIntake" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "mainEngine" ), Selector - ( ObjectKey "torqueModMult" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex, AnyArrayIndex ] ), fromList - [ ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "props" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots2" ), AnyArrayIndex, AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "beams" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "controller" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "flexbodies" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "glowMap" ), AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "nodes" ), AnyArrayIndex ] ), fromList - [ ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "powertrain" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "props" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "rails" ), AnyObjectKey ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "slots2" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "triangles" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "variables" ), AnyArrayIndex ] ), fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList [ AnyObjectKey, Selector ( ObjectKey "beams" ) ] ), fromList - [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "glowMap" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey AutoPadSubObjects, SomeProperty AutoPadSubObjects True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "information" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "mainEngine" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList [ AnyObjectKey, Selector ( ObjectKey "nodes" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey AutoPad, SomeProperty AutoPad True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "soundConfig" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector - ( ObjectKey "soundConfigExhaust" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "sounds" ) ] ), fromList - [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] ), - ( NodePattern - ( fromList - [ AnyObjectKey, Selector ( ObjectKey "triangles" ) ] ), fromList - [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ] ) ] ) \ No newline at end of file + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "beams", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + [ + ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), + ( ObjectKey "components", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "electrics", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "smoothers", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "controller", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "flexbodies", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "glowMap", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey AutoPadSubObjects, SomeProperty AutoPadSubObjects True ) ], rsBelow = fromList [] } ), + ( ObjectKey "information", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "mainEngine", RuleSet + { rsBySelectors = fromList + [ + ( ObjectKey "burnEfficiency", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "torque", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "torqueModIntake", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "torqueModMult", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "nodes", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), + ( ObjectKey "powertrain", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "props", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "rails", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "slots", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "slots2", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( ObjectKey "soundConfig", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "soundConfigExhaust", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "sounds", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( ObjectKey "triangles", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + [ + ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), + ( ObjectKey "variables", RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just + ( RuleSet + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + [ + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + [ + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } From e3d41174142cdf950e08339da8087e8b89dc6847 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:23:01 +0200 Subject: [PATCH 20/35] Adapt the matching specs to a lookup without MatchMode --- test/Formatting/RulesSpec.hs | 51 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index 2e52811f..d20e1488 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -39,31 +39,30 @@ spec = do it "applies PadAmount and PadDecimals" $ applyPadLogic (formatScalarNode False) ruleSet fakeNode `shouldBe` "123.50 " - -- A pattern matches only once it has been consumed whole, and leftover - -- breadcrumbs are allowed under PrefixMatch alone. A lookup that answers at - -- the wrong depth silently changes formatting everywhere, since every - -- property the formatter reads comes through one of the two modes. + -- Whether a property reaches below the node its rule names is decided by the + -- property, not by the caller: the parser puts the keys in `prefixProperties` + -- into rsBelow and the rest into rsHere. Every property the formatter reads + -- comes through this one lookup, so a split that answers at the wrong depth + -- changes formatting everywhere. describe "matching a pattern against a cursor" $ do let cursorAt crumbs = NodeCursor (fromList crumbs) nodesCursor = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "nodes"] - found mode pat = - lookupPropertyForCursor - mode - PadAmount - (rulesFromSource (pat ++ " { PadAmount: 7; }")) + rulesFor pat = rulesFromSource (pat ++ " { PadAmount: 7; AutoPad: true; }") + cascading pat = lookupPropertyForCursor PadAmount (rulesFor pat) + hereOnly pat = lookupPropertyForCursor AutoPad (rulesFor pat) - it "matches a pattern of the same length in both modes" $ do - found PrefixMatch ".*.nodes" nodesCursor `shouldBe` Just 7 - found ExactMatch ".*.nodes" nodesCursor `shouldBe` Just 7 + it "answers both kinds at the node the pattern names" $ do + cascading ".*.nodes" nodesCursor `shouldBe` Just 7 + hereOnly ".*.nodes" nodesCursor `shouldBe` Just True - it "matches a shorter pattern only as a prefix" $ do - found PrefixMatch ".*" nodesCursor `shouldBe` Just 7 - found ExactMatch ".*" nodesCursor `shouldBe` Nothing + it "carries a cascading property below that node, and nothing else" $ do + cascading ".*" nodesCursor `shouldBe` Just 7 + hereOnly ".*" nodesCursor `shouldBe` Nothing - it "never matches a pattern longer than the cursor" $ do - found PrefixMatch ".*.nodes[*]" nodesCursor `shouldBe` Nothing - found ExactMatch ".*.nodes[*]" nodesCursor `shouldBe` Nothing + it "never answers for a pattern longer than the cursor" $ do + cascading ".*.nodes[*]" nodesCursor `shouldBe` Nothing + hereOnly ".*.nodes[*]" nodesCursor `shouldBe` Nothing -- `.test*` is documented JBFL (JBFL_DOCS.md) and cannot be looked up by -- equality, since the stored key is a prefix of the breadcrumb rather than @@ -74,18 +73,18 @@ spec = do atDeformGroups = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "deformGroups"] - found ExactMatch (p "deform") atDeformGroups `shouldBe` Just 7 - found ExactMatch (p "deformGroups") atDeformGroups `shouldBe` Just 7 - found ExactMatch (p "deformGroupsAndMore") atDeformGroups `shouldBe` Nothing - found ExactMatch (p "eform") atDeformGroups `shouldBe` Nothing + hereOnly (p "deform") atDeformGroups `shouldBe` Just True + hereOnly (p "deformGroups") atDeformGroups `shouldBe` Just True + hereOnly (p "deformGroupsAndMore") atDeformGroups `shouldBe` Nothing + hereOnly (p "eform") atDeformGroups `shouldBe` Nothing it "keeps the two wildcards apart" $ do let atArray = cursorAt [ObjectIndexAndKey 0 "part", ArrayIndex 0] atKey = cursorAt [ObjectIndexAndKey 0 "part", ObjectIndexAndKey 0 "k"] - found ExactMatch ".*[*]" atArray `shouldBe` Just 7 - found ExactMatch ".*.*" atArray `shouldBe` Nothing - found ExactMatch ".*.*" atKey `shouldBe` Just 7 - found ExactMatch ".*[*]" atKey `shouldBe` Nothing + hereOnly ".*[*]" atArray `shouldBe` Just True + hereOnly ".*.*" atArray `shouldBe` Nothing + hereOnly ".*.*" atKey `shouldBe` Just True + hereOnly ".*[*]" atKey `shouldBe` Nothing {- | When several patterns match the same node, the more specific one supplies the property. Specificity is how many nodes a selector can match at that level: From 9b57afa01e7efa1b2dae01cd24701622d51a32b0 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:29:23 +0200 Subject: [PATCH 21/35] Refactoring, removing redudant `lookupRule` --- src/JbeamEdit/Formatting.hs | 18 +++++++++--------- src/JbeamEdit/Formatting/Rules.hs | 21 ++++++++++----------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/JbeamEdit/Formatting.hs b/src/JbeamEdit/Formatting.hs index 34ebabb2..14058602 100644 --- a/src/JbeamEdit/Formatting.hs +++ b/src/JbeamEdit/Formatting.hs @@ -47,7 +47,7 @@ import JbeamEdit.Formatting.Rules ( applyPadLogic, findPropertiesForCursor, lookupPropertyForCursor, - lookupRule, + lookupProperty ) import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL import JbeamEdit.Formatting.Rules.TrailingComma qualified as TC @@ -238,7 +238,7 @@ addDelimiters rs index rowIdx c complexChildren state acc ns@((node, nodeHadComm ( \childCursor _ -> fromMaybe TC.Preserve - (lookupPropertyForCursor PrefixMatch TrailingComma rs childCursor) + (lookupPropertyForCursor TrailingComma rs childCursor) ) index node @@ -323,14 +323,14 @@ doFormatNode rs cursor state elems = prefixProps = findPropertiesForCursor PrefixMatch cursor rs exactProps = findPropertiesForCursor ExactMatch cursor rs - autoPadEnabled = lookupRule AutoPad exactProps == Just True - alignObjectKeysEnabled = lookupRule AlignObjectKeys exactProps == Just True - autopadSubObjectsEnabled = lookupRule AutoPadSubObjects exactProps == Just True + autoPadEnabled = lookupProperty AutoPad exactProps == Just True + alignObjectKeysEnabled = lookupProperty AlignObjectKeys exactProps == Just True + autopadSubObjectsEnabled = lookupProperty AutoPadSubObjects exactProps == Just True complexChildren = - lookupRule ComplexNewLine prefixProps == Just CNL.Force + lookupProperty ComplexNewLine prefixProps == Just CNL.Force || any (liftA2 (||) isSinglelineComment isComplexNode) nodes - && lookupRule ComplexNewLine prefixProps /= Just CNL.None + && lookupProperty ComplexNewLine prefixProps /= Just CNL.None (colWidths, formattedCache, headerWasExtracted) = maxColumnLengthsWithCache rs cursor nodes @@ -397,7 +397,7 @@ doFormatNode rs cursor state elems = . V.toList $ elems - indentationAmount = fromMaybe 4 (lookupRule Indent prefixProps) + indentationAmount = fromMaybe 4 (lookupProperty Indent prefixProps) in if complexChildren then T.unlines @@ -454,7 +454,7 @@ formatWithCursor rs state cursor (ObjectKey (k, v)) = formatWithCursor _ _ _ (Comment comment) = formatComment comment formatWithCursor rs _ cursor n = let ps = findPropertiesForCursor PrefixMatch cursor rs - preserve = (Just True == lookupRule PreserveNumberFormat ps) + preserve = (Just True == lookupProperty PreserveNumberFormat ps) in applyPadLogic (formatScalarNode preserve) ps n formatNode :: RuleSet -> Node -> Text diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index d170e96f..9432a171 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -23,7 +23,7 @@ module JbeamEdit.Formatting.Rules ( keyName, applyPadLogic, complexNewLine, - lookupRule, + lookupProperty, lookupPropertyForCursor, findPropertiesForCursor, ) where @@ -239,8 +239,8 @@ data RuleSet } deriving stock (Eq, Read, Show) -lookupProp :: (Eq a, Read a, Show a) => PropertyKey a -> Rule -> Maybe a -lookupProp targetKey m = +lookupProperty :: (Eq a, Read a, Show a) => PropertyKey a -> Rule -> Maybe a +lookupProperty targetKey m = case M.lookup (SomeKey targetKey) m of Just (SomeProperty key val) -> case eqKey key targetKey of @@ -248,9 +248,6 @@ lookupProp targetKey m = Nothing -> Nothing Nothing -> Nothing -lookupRule :: (Eq a, Read a, Show a) => PropertyKey a -> Rule -> Maybe a -lookupRule = lookupProp - applyDecimalPadding :: Int -> Text -> Text applyDecimalPadding padDecimals node | padDecimals /= 0 @@ -262,8 +259,8 @@ applyDecimalPadding padDecimals node applyPadLogic :: (Node -> Text) -> Rule -> Node -> Text applyPadLogic f rs n = - let padAmount = sum $ lookupProp PadAmount rs - padDecimals = sum $ lookupProp PadDecimals rs + let padAmount = sum $ lookupProperty PadAmount rs + padDecimals = sum $ lookupProperty PadDecimals rs decimalPaddedText | isNumberNode n = applyDecimalPadding padDecimals (f n) | otherwise = f n @@ -272,14 +269,16 @@ applyPadLogic f rs n = complexNewLine :: RuleSet -> NC.NodeCursor -> Maybe ComplexNewLine complexNewLine rs cursor = let ps = findPropertiesForCursor PrefixMatch cursor rs - in lookupProp ComplexNewLine ps + in lookupProperty ComplexNewLine ps data MatchMode = PrefixMatch | ExactMatch deriving (Eq, Show) lookupPropertyForCursor :: (Eq a, Read a, Show a) - => MatchMode -> PropertyKey a -> RuleSet -> NC.NodeCursor -> Maybe a -lookupPropertyForCursor matchMode key rs cursor = lookupProp key (findPropertiesForCursor matchMode cursor rs) + => PropertyKey a -> RuleSet -> NC.NodeCursor -> Maybe a +lookupPropertyForCursor key rs cursor = lookupProperty key (findPropertiesForCursor matchMode cursor rs) + where + matchMode = bool ExactMatch PrefixMatch (SomeKey key `elem` prefixProperties) findPropertiesForCursor :: MatchMode -> NC.NodeCursor -> RuleSet -> Rule findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor From 9c40072f30d0c77529e7eebbdb03bafd91fdf505 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:30:37 +0200 Subject: [PATCH 22/35] Ran fourmolu --- src/JbeamEdit/Formatting.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JbeamEdit/Formatting.hs b/src/JbeamEdit/Formatting.hs index 14058602..0e46a55b 100644 --- a/src/JbeamEdit/Formatting.hs +++ b/src/JbeamEdit/Formatting.hs @@ -46,8 +46,8 @@ import JbeamEdit.Formatting.Rules ( RuleSet (..), applyPadLogic, findPropertiesForCursor, + lookupProperty, lookupPropertyForCursor, - lookupProperty ) import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL import JbeamEdit.Formatting.Rules.TrailingComma qualified as TC From 2cd00f61ae83dd4afe613d738401771ddc3ebf40 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:47:49 +0200 Subject: [PATCH 23/35] Let PadDecimals and PreserveNumberFormat cascade again --- src/JbeamEdit/Formatting/Rules.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 9432a171..baa574d5 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -203,7 +203,8 @@ prefixProperties :: [SomeKey] prefixProperties = SomeKey ComplexNewLine : SomeKey TrailingComma - : map SomeKey [PadAmount, Indent] + : SomeKey PreserveNumberFormat + : map SomeKey [PadAmount, PadDecimals, Indent] -- | Maps deprecated property names to (key, value-when-true, value-when-false). deprecatedAliases :: [(Text, (SomeKey, SomeProperty, SomeProperty))] From a7b9ceb9f4ac48ea66754b9b0dc0d3995453c046 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:47:49 +0200 Subject: [PATCH 24/35] Document how far each property reaches --- JBFL_DOCS.md | 18 ++++++++++++++++++ test/FormattingSpec.hs | 12 ++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/JBFL_DOCS.md b/JBFL_DOCS.md index 05f255c0..52366575 100644 --- a/JBFL_DOCS.md +++ b/JBFL_DOCS.md @@ -74,6 +74,24 @@ Typical use cases include: - `TrailingComma: None` strips trailing commas. `Force` always adds them. `Preserve` (default) keeps whatever the source file had. - `TrailingComma` is resolved at the child level, so `.* { TrailingComma: None; }` also strips the trailing comma in the root object. +### How far a property reaches + +A pattern names one level. Some properties then apply only to what sits exactly +there, and others also apply to everything nested below it, so a rule on `.*` +can still decide how a value five levels down is printed. + +| Reaches | Properties | +|-----------------------------|-------------------------------------------------------------------------------------------------| +| The matched value only | `AutoPad`, `AlignObjectKeys`, `AutoPadSubObjects` | +| The matched value and below | `PadDecimals`, `PadAmount`, `Indent`, `ComplexNewLine`, `TrailingComma`, `PreserveNumberFormat` | + +The three in the first row all describe how one array or object lays out its own +children, so inheriting them would align structures the rule never mentioned. + +This is why `.* { Indent: 2; }` indents the whole file while `.* { AutoPad: true; }` +only pads the root object, and why the shipped `minimal.jbfl` can set +`PadDecimals` on `.*.nodes[*][*]` or on a parent and get the same result. + ## Detailed Rules Examples ### Pattern: `.*.nodes[*][*]` diff --git a/test/FormattingSpec.hs b/test/FormattingSpec.hs index 1b91a984..9098999a 100644 --- a/test/FormattingSpec.hs +++ b/test/FormattingSpec.hs @@ -93,8 +93,8 @@ Moving one across changes formatting and no fixture notices. This pins the split as it stands before `>` (see #187), which is meant to replace it, so expect to rewrite this when that lands. -} -matchModeSpec :: Spec -matchModeSpec = do +reachSpec :: Spec +reachSpec = do let row cells = mkArray (fromList cells) -- The first column has to vary in width for AutoPad to show, since -- trailing spaces on the last one are trimmed either way. @@ -124,21 +124,21 @@ matchModeSpec = do baseline = wrap " [\"a_long_name\", 1],\n [\"n1\", 2]" padded = wrap " [\"a_long_name\", 1],\n [\"n1\", 2]" - describe "which match mode a property is read in" $ do - it "reads AutoPad from an exact match only" $ do + describe "how far down a property reaches" $ do + it "applies AutoPad to the matched value only" $ do formatWith (exactPattern "AutoPad : true;") `shouldBe` padded -- Without this line the assertion below also passes for a shortPattern -- that matches nothing at all, which is not what is being claimed. formatWith (shortPattern "ComplexNewLine : Force;") `shouldNotBe` baseline formatWith (shortPattern "AutoPad : true;") `shouldBe` baseline - it "reads ComplexNewLine from a prefix match" $ + it "applies ComplexNewLine below the matched value too" $ formatWith (shortPattern "ComplexNewLine : Force;") `shouldNotBe` baseline spec :: Spec spec = do mapM_ formatNodeSpec specs - matchModeSpec + reachSpec dynamicTests <- runIO dynamicJbflTests forM_ dynamicTests $ \(outFile, formatted, expected) -> From 0f0c2a1a2adaa2c5c7357d5cdb712d862da7c54e Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:47:49 +0200 Subject: [PATCH 25/35] Assert prefix precedence in both source orders --- test/Formatting/RulesSpec.hs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index d20e1488..1e164a91 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -40,10 +40,8 @@ spec = do applyPadLogic (formatScalarNode False) ruleSet fakeNode `shouldBe` "123.50 " -- Whether a property reaches below the node its rule names is decided by the - -- property, not by the caller: the parser puts the keys in `prefixProperties` - -- into rsBelow and the rest into rsHere. Every property the formatter reads - -- comes through this one lookup, so a split that answers at the wrong depth - -- changes formatting everywhere. + -- property, not by the caller: `prefixProperties` goes to rsBelow, the rest + -- to rsHere. describe "matching a pattern against a cursor" $ do let cursorAt crumbs = NodeCursor (fromList crumbs) nodesCursor = @@ -64,10 +62,8 @@ spec = do cascading ".*.nodes[*]" nodesCursor `shouldBe` Nothing hereOnly ".*.nodes[*]" nodesCursor `shouldBe` Nothing - -- `.test*` is documented JBFL (JBFL_DOCS.md) and cannot be looked up by - -- equality, since the stored key is a prefix of the breadcrumb rather than - -- the same text. It is the one selector a trie has to solve rather than - -- key on directly. + -- The one selector a trie cannot key on directly: the stored text is a + -- prefix of the breadcrumb, not equal to it. it "matches a prefix key against the rest of the breadcrumb" $ do let p k = ".*." ++ k ++ "*" atDeformGroups = @@ -87,12 +83,8 @@ spec = do hereOnly ".*[*]" atKey `shouldBe` Nothing {- | When several patterns match the same node, the more specific one supplies -the property. Specificity is how many nodes a selector can match at that level: -a named key first, then a positional index, then a prefix key with the longer -prefix winning, then the wildcards. - -Written as JBFL source and formatted output on purpose. Both ends survive the -rule lookup becoming a trie, while `NodePattern` and `MatchMode` do not. +the property: a named key, then a positional index, then a prefix key with the +longer prefix, then the wildcards. -} precedenceSpec :: Spec precedenceSpec = do @@ -117,10 +109,12 @@ precedenceSpec = do ) rulesFrom = rulesFromSource formatWith = flip formatNode topNode . rulesFrom - -- The second assertion is what stops the first passing for two rules that - -- happen to format the same way. + -- Both orders, because writing the winner first would otherwise let a + -- lookup that just takes the first parsed rule pass. The last assertion + -- stops the others passing for two rules that format the same way. beats winner loser = do formatWith (winner <> "\n" <> loser) `shouldBe` formatWith winner + formatWith (loser <> "\n" <> winner) `shouldBe` formatWith winner formatWith winner `shouldNotBe` formatWith loser named = ".deformGroups { Indent : 1; }" positional = ".0 { Indent : 2; }" From a21cfaf64a19e309c6c7da5178ae386126afdd25 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 14:21:01 +0200 Subject: [PATCH 26/35] Assert per-property merging across matching prefix rules --- test/Formatting/RulesSpec.hs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index 1e164a91..52a1c44c 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -127,6 +127,20 @@ precedenceSpec = do it "prefers a positional index over a prefix key" $ positional `beats` longPrefix it "prefers the longer of two prefix keys" $ longPrefix `beats` shortPrefix + + -- Resolution is per property, as in CSS: two matching rules that set + -- different properties both apply, and only a property they both set is + -- decided by specificity. Read through the lookup rather than the output, + -- since one formatted file cannot show which rule each property came from. + it "takes each property from its own most specific match" $ do + let cur = NodeCursor (fromList [ObjectIndexAndKey 0 "deformGroups"]) + both a b = rulesFromSource (a <> "\n" <> b) + short = ".de* { Indent: 2; PadAmount: 4; }" + long = ".deform* { PadAmount: 8; }" + lookupPropertyForCursor Indent (both short long) cur `shouldBe` Just 2 + lookupPropertyForCursor Indent (both long short) cur `shouldBe` Just 2 + lookupPropertyForCursor PadAmount (both short long) cur `shouldBe` Just 8 + lookupPropertyForCursor PadAmount (both long short) cur `shouldBe` Just 8 it "prefers a prefix key over a wildcard" $ shortPrefix `beats` wildcard -- Precedence settles one property at a time. Every shipped ruleset is From 80de6eb195364358fa90d698cc7ff3b9c18115af Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 14:25:47 +0200 Subject: [PATCH 27/35] Assert the later of two rules with one pattern wins --- test/Formatting/RulesSpec.hs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index 52a1c44c..32ca6b8e 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -185,6 +185,14 @@ precedenceSpec = do -- (`Formatting/Config.hs`), so this is how every configured install resolves -- its rules. The union is left-biased twice over, per pattern and per -- property, and a trie has to reproduce both. + -- The other direction from the merge below: within one file the later rule + -- wins, while a user ruleset beats the shipped one it is merged with. + describe "two rules with the same pattern" + . it "takes the value from the later one" $ do + let twice = rulesFrom ".deformGroups { Indent : 1; }\n.deformGroups { Indent : 2; }" + cur = NodeCursor (fromList [ObjectIndexAndKey 0 "deformGroups"]) + lookupPropertyForCursor Indent twice cur `shouldBe` Just 2 + describe "combining a user ruleset with the shipped one" $ do let user = rulesFrom ".deformGroups { Indent : 1; }" shipped = rulesFrom ".deformGroups { Indent : 7; TrailingComma : Force; }" From 42fb9a10a474b674d534b9b665222244c57a772e Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 14:50:32 +0200 Subject: [PATCH 28/35] Fixed regressions --- src/JbeamEdit/Formatting/Rules.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index baa574d5..84572162 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -31,7 +31,7 @@ module JbeamEdit.Formatting.Rules ( import Data.Bool (bool) import Data.Foldable (fold) import Data.Function (on) -import Data.List (find) +import Data.List (find, sortOn) import Data.Map (Map) import Data.Map qualified as M import Data.Ord (Down (..)) @@ -291,7 +291,7 @@ findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor ( addBelowProps rs $ fold (M.lookup (NP.ObjectKey k) rs.rsBySelectors) <> fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) - <> foldMap snd (find (\(prefix, _) -> T.isPrefixOf prefix k) rs.rsPrefixes) + <> sortAndMergePrefixes k rs.rsPrefixes <> fold rs.rsAnyObjectKey ) go (NC.ArrayIndex i :<| bs) rs = @@ -306,3 +306,7 @@ findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor { rsBelow = bool rs.rsBelow (rs.rsBelow <> rsAbove.rsBelow) (matchMode == PrefixMatch) } + sortAndMergePrefixes k = + foldMap snd + . sortOn (Down . T.length . fst) + . filter ((`T.isPrefixOf` k) . fst) From 8b72d2ef67c3eaccb38f388bf8d51c9f34ff77a7 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 14:56:40 +0200 Subject: [PATCH 29/35] Bugfix --- src/JbeamEdit/Parsing/DSL.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/JbeamEdit/Parsing/DSL.hs b/src/JbeamEdit/Parsing/DSL.hs index 4a755d36..5180e228 100644 --- a/src/JbeamEdit/Parsing/DSL.hs +++ b/src/JbeamEdit/Parsing/DSL.hs @@ -19,6 +19,7 @@ import Data.Functor.Identity (Identity (..)) import Data.List.NonEmpty qualified as NE (fromList) import Data.Map (Map) import Data.Map qualified as M (empty, fromList, partitionWithKey, singleton) +import Data.Monoid (Dual (..)) import Data.Set qualified as S (fromList) import Data.Text (Text) import Data.Text qualified as T (init, isSuffixOf, unpack) @@ -187,7 +188,7 @@ combineRuleSets (pats, props) = fold [fold (go pat) | pat <- pats] go (Selector s : pats') = Just (mempty {rsBySelectors = maybe M.empty (M.singleton s) (go pats')}) ruleSetParser :: JbflParser RuleSet -ruleSetParser = foldMap combineRuleSets <$> MP.some singleRuleSet +ruleSetParser = getDual . foldMap (Dual . combineRuleSets) <$> MP.some singleRuleSet where singleRuleSet = skipComment *> ruleParser <* skipComment From 52e9161754165902689854ecaa3c4dfc858959fc Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:01:02 +0200 Subject: [PATCH 30/35] Drop NodePattern, unused since patterns stopped being keys --- src/JbeamEdit/Formatting/Rules.hs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 84572162..b1e6a023 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -8,7 +8,6 @@ module JbeamEdit.Formatting.Rules ( MatchMode (..), NodePatternSelector (..), - NodePattern (..), SomeKey (..), SomeProperty (..), PropertyKey (..), @@ -36,7 +35,6 @@ import Data.Map (Map) import Data.Map qualified as M import Data.Ord (Down (..)) import Data.Sequence (Seq (..)) -import Data.Sequence qualified as Seq (length) import Data.Text (Text) import Data.Text qualified as T import Data.Type.Equality ((:~:) (Refl)) @@ -54,18 +52,6 @@ data NodePatternSelector | Selector NP.NodeSelector deriving stock (Eq, Read, Show) -newtype NodePattern - = NodePattern (Seq NodePatternSelector) - deriving stock (Eq, Read, Show) - -instance Ord NodePatternSelector where - compare = on compare rank - where - rank :: NodePatternSelector -> (Int, Maybe NP.NodeSelector) - rank AnyArrayIndex = (2, Nothing) - rank AnyObjectKey = (1, Nothing) - rank (Selector s) = (0, Just s) - instance Monoid RuleSet where mempty = RuleSet M.empty [] mempty mempty M.empty M.empty @@ -79,12 +65,6 @@ instance Semigroup RuleSet where (h1 <> h2) (b1 <> b2) -instance Ord NodePattern where - compare (NodePattern a) (NodePattern b) = - case on compare (Down . Seq.length) a b of - EQ -> compare a b - c -> c - data PropertyKey a where AutoPad :: PropertyKey Bool ComplexNewLine :: PropertyKey ComplexNewLine From 921b6bf57d3cc717400963d83e49dd2784dc0838 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:01:02 +0200 Subject: [PATCH 31/35] Use M.null and drop the duplicate NodePath import --- src/JbeamEdit/Parsing/DSL.hs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/JbeamEdit/Parsing/DSL.hs b/src/JbeamEdit/Parsing/DSL.hs index 5180e228..ff23d204 100644 --- a/src/JbeamEdit/Parsing/DSL.hs +++ b/src/JbeamEdit/Parsing/DSL.hs @@ -18,7 +18,13 @@ import Data.Functor (void, ($>)) import Data.Functor.Identity (Identity (..)) import Data.List.NonEmpty qualified as NE (fromList) import Data.Map (Map) -import Data.Map qualified as M (empty, fromList, partitionWithKey, singleton) +import Data.Map qualified as M ( + empty, + fromList, + null, + partitionWithKey, + singleton, + ) import Data.Monoid (Dual (..)) import Data.Set qualified as S (fromList) import Data.Text (Text) @@ -26,7 +32,6 @@ import Data.Text qualified as T (init, isSuffixOf, unpack) import Data.Text.Encoding (decodeUtf8') import Data.Word (Word8) import JbeamEdit.Core.NodePath -import JbeamEdit.Core.NodePath qualified as NP (NodeSelector (..)) import JbeamEdit.Formatting.Rules import JbeamEdit.Formatting.Rules.ComplexNewLine qualified as CNL import JbeamEdit.Formatting.Rules.TrailingComma qualified as TC @@ -175,7 +180,7 @@ ruleParser = do combineRuleSets :: ([[NodePatternSelector]], Map SomeKey SomeProperty) -> RuleSet combineRuleSets (_, props) - | props == M.empty = mempty + | M.null props = mempty combineRuleSets (pats, props) = fold [fold (go pat) | pat <- pats] where go :: [NodePatternSelector] -> Maybe RuleSet @@ -184,7 +189,7 @@ combineRuleSets (pats, props) = fold [fold (go pat) | pat <- pats] (belowProps, hereProps) = M.partitionWithKey (\k _ -> k `elem` prefixProperties) props go (AnyObjectKey : pats') = Just (mempty {rsAnyObjectKey = go pats'}) go (AnyArrayIndex : pats') = Just (mempty {rsAnyArrayIndex = go pats'}) - go (Selector (NP.ObjectPrefixKey p) : pats') = Just (mempty {rsPrefixes = maybe [] (\x -> [(p, x)]) (go pats')}) + go (Selector (ObjectPrefixKey p) : pats') = Just (mempty {rsPrefixes = maybe [] (\x -> [(p, x)]) (go pats')}) go (Selector s : pats') = Just (mempty {rsBySelectors = maybe M.empty (M.singleton s) (go pats')}) ruleSetParser :: JbflParser RuleSet From f2446cbc989e2fda4eba489d8af0eb3831594c5d Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:09:00 +0200 Subject: [PATCH 32/35] Give the same-pattern spec a stable formatting --- test/Formatting/RulesSpec.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index 32ca6b8e..8cfc871c 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -187,11 +187,12 @@ precedenceSpec = do -- property, and a trie has to reproduce both. -- The other direction from the merge below: within one file the later rule -- wins, while a user ruleset beats the shipped one it is merged with. - describe "two rules with the same pattern" - . it "takes the value from the later one" $ do + describe "two rules with the same pattern" $ do let twice = rulesFrom ".deformGroups { Indent : 1; }\n.deformGroups { Indent : 2; }" cur = NodeCursor (fromList [ObjectIndexAndKey 0 "deformGroups"]) - lookupPropertyForCursor Indent twice cur `shouldBe` Just 2 + + it "takes the value from the later one" $ + lookupPropertyForCursor Indent twice cur `shouldBe` Just 2 describe "combining a user ruleset with the shipped one" $ do let user = rulesFrom ".deformGroups { Indent : 1; }" From ec337923be91b0f36f2381f1282e5c24bd6539d9 Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:17:03 +0200 Subject: [PATCH 33/35] Drop MatchMode, now decided by the property key --- src/JbeamEdit/Formatting.hs | 18 ++++++------- src/JbeamEdit/Formatting/Rules.hs | 45 ++++++++++++++++--------------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/JbeamEdit/Formatting.hs b/src/JbeamEdit/Formatting.hs index 0e46a55b..99c6207e 100644 --- a/src/JbeamEdit/Formatting.hs +++ b/src/JbeamEdit/Formatting.hs @@ -41,7 +41,6 @@ import JbeamEdit.Core.Node ( import JbeamEdit.Core.NodeCursor (newCursor) import JbeamEdit.Core.NodeCursor qualified as NC import JbeamEdit.Formatting.Rules ( - MatchMode (..), PropertyKey (..), RuleSet (..), applyPadLogic, @@ -320,17 +319,16 @@ doFormatNode -> Text doFormatNode rs cursor state elems = let nodes = V.map fst elems - prefixProps = findPropertiesForCursor PrefixMatch cursor rs - exactProps = findPropertiesForCursor ExactMatch cursor rs + props = findPropertiesForCursor cursor rs - autoPadEnabled = lookupProperty AutoPad exactProps == Just True - alignObjectKeysEnabled = lookupProperty AlignObjectKeys exactProps == Just True - autopadSubObjectsEnabled = lookupProperty AutoPadSubObjects exactProps == Just True + autoPadEnabled = lookupProperty AutoPad props == Just True + alignObjectKeysEnabled = lookupProperty AlignObjectKeys props == Just True + autopadSubObjectsEnabled = lookupProperty AutoPadSubObjects props == Just True complexChildren = - lookupProperty ComplexNewLine prefixProps == Just CNL.Force + lookupProperty ComplexNewLine props == Just CNL.Force || any (liftA2 (||) isSinglelineComment isComplexNode) nodes - && lookupProperty ComplexNewLine prefixProps /= Just CNL.None + && lookupProperty ComplexNewLine props /= Just CNL.None (colWidths, formattedCache, headerWasExtracted) = maxColumnLengthsWithCache rs cursor nodes @@ -397,7 +395,7 @@ doFormatNode rs cursor state elems = . V.toList $ elems - indentationAmount = fromMaybe 4 (lookupProperty Indent prefixProps) + indentationAmount = fromMaybe 4 (lookupProperty Indent props) in if complexChildren then T.unlines @@ -453,7 +451,7 @@ formatWithCursor rs state cursor (ObjectKey (k, v)) = in paddedKey <> " : " <> valueText formatWithCursor _ _ _ (Comment comment) = formatComment comment formatWithCursor rs _ cursor n = - let ps = findPropertiesForCursor PrefixMatch cursor rs + let ps = findPropertiesForCursor cursor rs preserve = (Just True == lookupProperty PreserveNumberFormat ps) in applyPadLogic (formatScalarNode preserve) ps n diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index b1e6a023..98cbd938 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -6,7 +6,6 @@ {-# LANGUAGE TypeOperators #-} module JbeamEdit.Formatting.Rules ( - MatchMode (..), NodePatternSelector (..), SomeKey (..), SomeProperty (..), @@ -59,7 +58,7 @@ instance Semigroup RuleSet where (RuleSet rs1 ps1 aok1 aai1 h1 b1) <> (RuleSet rs2 ps2 aok2 aai2 h2 b2) = RuleSet (M.unionWith (<>) rs1 rs2) - (ps1 <> ps2) + (mergePrefixes ps1 ps2) (aok1 <> aok2) (aai1 <> aai2) (h1 <> h2) @@ -179,6 +178,16 @@ intProperties = map SomeKey [PadAmount, PadDecimals, Indent] allProperties :: [SomeKey] allProperties = boolProperties ++ enumProperties ++ intProperties +{- | Longest prefix first, one entry per prefix, so a lookup only has to keep +the matches in the order it finds them. Kept here rather than at the lookup +because it also makes two rulesets that say the same thing compare equal, which +`examples/ast/jbfl/` relies on. +-} +mergePrefixes :: [(Text, RuleSet)] -> [(Text, RuleSet)] -> [(Text, RuleSet)] +mergePrefixes ps1 ps2 = + sortOn (Down . T.length . fst) . M.toList . M.fromListWith (flip (<>)) $ + ps1 <> ps2 + prefixProperties :: [SomeKey] prefixProperties = SomeKey ComplexNewLine @@ -249,20 +258,21 @@ applyPadLogic f rs n = complexNewLine :: RuleSet -> NC.NodeCursor -> Maybe ComplexNewLine complexNewLine rs cursor = - let ps = findPropertiesForCursor PrefixMatch cursor rs + let ps = findPropertiesForCursor cursor rs in lookupProperty ComplexNewLine ps -data MatchMode = PrefixMatch | ExactMatch deriving (Eq, Show) - lookupPropertyForCursor :: (Eq a, Read a, Show a) => PropertyKey a -> RuleSet -> NC.NodeCursor -> Maybe a -lookupPropertyForCursor key rs cursor = lookupProperty key (findPropertiesForCursor matchMode cursor rs) - where - matchMode = bool ExactMatch PrefixMatch (SomeKey key `elem` prefixProperties) - -findPropertiesForCursor :: MatchMode -> NC.NodeCursor -> RuleSet -> Rule -findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor +lookupPropertyForCursor key rs cursor = + lookupProperty key (findPropertiesForCursor cursor rs) + +{- | Every property that applies at the cursor. What reaches below the node a +rule names is decided when the rule is parsed, by whether its key is in +'prefixProperties', so the walk always inherits rsBelow and never rsHere. +-} +findPropertiesForCursor :: NC.NodeCursor -> RuleSet -> Rule +findPropertiesForCursor (NC.NodeCursor cursor) = go cursor where go Empty rs = rs.rsHere <> rs.rsBelow go (NC.ObjectIndexAndKey i k :<| bs) rs = @@ -271,7 +281,7 @@ findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor ( addBelowProps rs $ fold (M.lookup (NP.ObjectKey k) rs.rsBySelectors) <> fold (M.lookup (NP.ObjectIndex i) rs.rsBySelectors) - <> sortAndMergePrefixes k rs.rsPrefixes + <> matchingPrefixes k rs.rsPrefixes <> fold rs.rsAnyObjectKey ) go (NC.ArrayIndex i :<| bs) rs = @@ -281,12 +291,5 @@ findPropertiesForCursor matchMode (NC.NodeCursor cursor) = go cursor fold (M.lookup (NP.ArrayIndex i) rs.rsBySelectors) <> fold rs.rsAnyArrayIndex ) - addBelowProps rsAbove rs = - rs - { rsBelow = - bool rs.rsBelow (rs.rsBelow <> rsAbove.rsBelow) (matchMode == PrefixMatch) - } - sortAndMergePrefixes k = - foldMap snd - . sortOn (Down . T.length . fst) - . filter ((`T.isPrefixOf` k) . fst) + addBelowProps rsAbove rs = rs {rsBelow = rs.rsBelow <> rsAbove.rsBelow} + matchingPrefixes k = foldMap snd . filter ((`T.isPrefixOf` k) . fst) From 004dd8b7a0296ed637eeed73541cb0956f1ccfab Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:19:51 +0200 Subject: [PATCH 34/35] Regenerate the JBFL ASTs after the cascade change --- examples/ast/jbfl/complex.hs | 230 +++++++++++++++-------------------- examples/ast/jbfl/minimal.hs | 218 +++++++++++++++------------------ 2 files changed, 196 insertions(+), 252 deletions(-) diff --git a/examples/ast/jbfl/complex.hs b/examples/ast/jbfl/complex.hs index c03fe1fa..459b9b9a 100644 --- a/examples/ast/jbfl/complex.hs +++ b/examples/ast/jbfl/complex.hs @@ -8,23 +8,20 @@ RuleSet ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), ( ObjectKey "components", RuleSet @@ -36,41 +33,36 @@ RuleSet ( ObjectKey "smoothers", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "controller", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "flexbodies", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "glowMap", RuleSet { rsBySelectors = fromList [ @@ -83,20 +75,20 @@ RuleSet ( ObjectKey "chassis_gaugelight_warning", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "checkengine", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), ( ObjectKey "dumptruck_gaugelight_warning", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "hazard", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ ( SomeKey PadAmount, SomeProperty PadAmount 20 ) ] } ), @@ -129,81 +121,74 @@ RuleSet ( ObjectKey "on", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PadAmount, SomeProperty PadAmount 10 ) ] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey PadAmount, SomeProperty PadAmount 10 ) ] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [ ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), ( SomeKey AutoPadSubObjects, SomeProperty AutoPadSubObjects True ) ], rsBelow = fromList [] } ), ( ObjectKey "information", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "mainEngine", RuleSet { rsBySelectors = fromList [ ( ObjectKey "burnEfficiency", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "torque", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "torqueModIntake", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "torqueModMult", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "nodes", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList + ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ] } ), rsHere = fromList [], rsBelow = fromList [ ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [ @@ -212,124 +197,111 @@ RuleSet ( ObjectKey "powertrain", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "props", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "rails", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "slots", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "slots2", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "soundConfig", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "soundConfigExhaust", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "sounds", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "triangles", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), ( ObjectKey "variables", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ ( SomeKey Indent, SomeProperty Indent 2 ), ( SomeKey TrailingComma, SomeProperty TrailingComma None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } diff --git a/examples/ast/jbfl/minimal.hs b/examples/ast/jbfl/minimal.hs index a95efa55..735cc739 100644 --- a/examples/ast/jbfl/minimal.hs +++ b/examples/ast/jbfl/minimal.hs @@ -8,23 +8,20 @@ RuleSet ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), ( ObjectKey "components", RuleSet @@ -36,119 +33,107 @@ RuleSet ( ObjectKey "smoothers", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "controller", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "flexbodies", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "glowMap", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [ ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), ( SomeKey AutoPadSubObjects, SomeProperty AutoPadSubObjects True ) ], rsBelow = fromList [] } ), ( ObjectKey "information", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "mainEngine", RuleSet { rsBySelectors = fromList [ ( ObjectKey "burnEfficiency", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "torque", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "torqueModIntake", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "torqueModMult", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "nodes", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList + ( SomeKey PadDecimals, SomeProperty PadDecimals 3 ) ] } ), rsHere = fromList [], rsBelow = fromList [ ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [ @@ -157,121 +142,108 @@ RuleSet ( ObjectKey "powertrain", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "props", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "rails", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "slots", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "slots2", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Just + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Just ( RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList - [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ), ( ObjectKey "soundConfig", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "soundConfigExhaust", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "sounds", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [ - ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ), - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + ( SomeKey AlignObjectKeys, SomeProperty AlignObjectKeys True ) ], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ) ] } ), + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine Force ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), ( ObjectKey "triangles", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [ ( SomeKey AutoPad, SomeProperty AutoPad True ) ], rsBelow = fromList [] } ), ( ObjectKey "variables", RuleSet { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Just ( RuleSet - { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList - [ - ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ], rsBelow = fromList + { rsBySelectors = fromList [], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [ - ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } + ( SomeKey ComplexNewLine, SomeProperty ComplexNewLine None ), + ( SomeKey PreserveNumberFormat, SomeProperty PreserveNumberFormat True ) ] } ), rsHere = fromList [], rsBelow = fromList [] } ) ], rsPrefixes = [], rsAnyObjectKey = Nothing, rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } ), rsAnyArrayIndex = Nothing, rsHere = fromList [], rsBelow = fromList [] } From 048ff8f9147b17d880a7c059acb3eccbf60a7ded Mon Sep 17 00:00:00 2001 From: webdevred <148627186+webdevred@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:27:55 +0200 Subject: [PATCH 35/35] Cut the comments back to the three that carry something --- src/JbeamEdit/Formatting/Rules.hs | 9 ------- test/Formatting/RulesSpec.hs | 41 ++----------------------------- test/FormattingSpec.hs | 19 +------------- 3 files changed, 3 insertions(+), 66 deletions(-) diff --git a/src/JbeamEdit/Formatting/Rules.hs b/src/JbeamEdit/Formatting/Rules.hs index 98cbd938..68127bce 100644 --- a/src/JbeamEdit/Formatting/Rules.hs +++ b/src/JbeamEdit/Formatting/Rules.hs @@ -178,11 +178,6 @@ intProperties = map SomeKey [PadAmount, PadDecimals, Indent] allProperties :: [SomeKey] allProperties = boolProperties ++ enumProperties ++ intProperties -{- | Longest prefix first, one entry per prefix, so a lookup only has to keep -the matches in the order it finds them. Kept here rather than at the lookup -because it also makes two rulesets that say the same thing compare equal, which -`examples/ast/jbfl/` relies on. --} mergePrefixes :: [(Text, RuleSet)] -> [(Text, RuleSet)] -> [(Text, RuleSet)] mergePrefixes ps1 ps2 = sortOn (Down . T.length . fst) . M.toList . M.fromListWith (flip (<>)) $ @@ -267,10 +262,6 @@ lookupPropertyForCursor lookupPropertyForCursor key rs cursor = lookupProperty key (findPropertiesForCursor cursor rs) -{- | Every property that applies at the cursor. What reaches below the node a -rule names is decided when the rule is parsed, by whether its key is in -'prefixProperties', so the walk always inherits rsBelow and never rsHere. --} findPropertiesForCursor :: NC.NodeCursor -> RuleSet -> Rule findPropertiesForCursor (NC.NodeCursor cursor) = go cursor where diff --git a/test/Formatting/RulesSpec.hs b/test/Formatting/RulesSpec.hs index 8cfc871c..27e50c1d 100644 --- a/test/Formatting/RulesSpec.hs +++ b/test/Formatting/RulesSpec.hs @@ -39,9 +39,6 @@ spec = do it "applies PadAmount and PadDecimals" $ applyPadLogic (formatScalarNode False) ruleSet fakeNode `shouldBe` "123.50 " - -- Whether a property reaches below the node its rule names is decided by the - -- property, not by the caller: `prefixProperties` goes to rsBelow, the rest - -- to rsHere. describe "matching a pattern against a cursor" $ do let cursorAt crumbs = NodeCursor (fromList crumbs) nodesCursor = @@ -62,8 +59,6 @@ spec = do cascading ".*.nodes[*]" nodesCursor `shouldBe` Nothing hereOnly ".*.nodes[*]" nodesCursor `shouldBe` Nothing - -- The one selector a trie cannot key on directly: the stored text is a - -- prefix of the breadcrumb, not equal to it. it "matches a prefix key against the rest of the breadcrumb" $ do let p k = ".*." ++ k ++ "*" atDeformGroups = @@ -82,17 +77,11 @@ spec = do hereOnly ".*.*" atKey `shouldBe` Just True hereOnly ".*[*]" atKey `shouldBe` Nothing -{- | When several patterns match the same node, the more specific one supplies -the property: a named key, then a positional index, then a prefix key with the -longer prefix, then the wildcards. --} precedenceSpec :: Spec precedenceSpec = do let cell :: Int -> Node cell n = Number (mkNumberValue (T.pack (show n)) (fromIntegral n)) - -- Three levels deep, so Indent set two breadcrumbs down still shows. pair a b = mkArray (fromList [mkArray (fromList [a, b]), mkArray (fromList [b, a])]) - -- Complex enough to be broken across lines, so Indent shows in the output. topNode = mkObject ( fromList @@ -109,9 +98,7 @@ precedenceSpec = do ) rulesFrom = rulesFromSource formatWith = flip formatNode topNode . rulesFrom - -- Both orders, because writing the winner first would otherwise let a - -- lookup that just takes the first parsed rule pass. The last assertion - -- stops the others passing for two rules that format the same way. + -- Both orders: the first alone passes for a first-parsed-rule lookup. beats winner loser = do formatWith (winner <> "\n" <> loser) `shouldBe` formatWith winner formatWith (loser <> "\n" <> winner) `shouldBe` formatWith winner @@ -128,10 +115,6 @@ precedenceSpec = do positional `beats` longPrefix it "prefers the longer of two prefix keys" $ longPrefix `beats` shortPrefix - -- Resolution is per property, as in CSS: two matching rules that set - -- different properties both apply, and only a property they both set is - -- decided by specificity. Read through the lookup rather than the output, - -- since one formatted file cannot show which rule each property came from. it "takes each property from its own most specific match" $ do let cur = NodeCursor (fromList [ObjectIndexAndKey 0 "deformGroups"]) both a b = rulesFromSource (a <> "\n" <> b) @@ -143,24 +126,11 @@ precedenceSpec = do lookupPropertyForCursor PadAmount (both long short) cur `shouldBe` Just 8 it "prefers a prefix key over a wildcard" $ shortPrefix `beats` wildcard - -- Precedence settles one property at a time. Every shipped ruleset is - -- written this way: `.*` carries Indent and TrailingComma for the whole - -- file and narrower patterns add to it, so a winner that supplied its - -- properties wholesale would strip the broad ones off every node it matched. - -- `[4]` is the last row of the selector table in JBFL_DOCS.md, and the only - -- one no shipped ruleset uses, so nothing else would notice it going away. - -- A prefix key has to reach below the node it names, like any other - -- selector under a prefix match. It is also the one a trie cannot key on - -- directly, so it is the likeliest of them to lose that reach. it "cascades from a prefix key the same way a named key does" $ do let byPrefix = formatWith ".deform* { Indent : 1; }" byPrefix `shouldBe` formatWith ".deformGroups { Indent : 1; }" byPrefix `shouldNotBe` formatWith ".deformGroups { Indent : 6; }" - -- Length is settled before specificity, and it is the one rung with no - -- shorthand: the two patterns reach different sets of nodes, so the winner - -- alone cannot be the expected value. The outer array is indented by the - -- shorter rule, the inner ones by the longer. it "settles length before specificity" $ do let shorter = ".deformGroups { Indent : 7; }" longer = ".deformGroups[*] { Indent : 1; }" @@ -181,12 +151,6 @@ precedenceSpec = do formatWith (winnerOnly <> "\n" <> loserOnly) `shouldNotBe` formatWith loserOnly - -- A user's rules.jbfl is laid over the shipped one with `rs <> defaultRs` - -- (`Formatting/Config.hs`), so this is how every configured install resolves - -- its rules. The union is left-biased twice over, per pattern and per - -- property, and a trie has to reproduce both. - -- The other direction from the merge below: within one file the later rule - -- wins, while a user ruleset beats the shipped one it is merged with. describe "two rules with the same pattern" $ do let twice = rulesFrom ".deformGroups { Indent : 1; }\n.deformGroups { Indent : 2; }" cur = NodeCursor (fromList [ObjectIndexAndKey 0 "deformGroups"]) @@ -202,7 +166,6 @@ precedenceSpec = do it "takes the user's value and keeps the rest of the shipped one" $ do let merged = rulesFrom ".deformGroups { Indent : 1; TrailingComma : Force; }" format (user <> shipped) `shouldBe` format merged - -- Guards the line above: without these the two rulesets could be - -- indistinguishable and the merge would prove nothing. + -- Guards the line above: without these the two could be indistinguishable. format user `shouldNotBe` format shipped format merged `shouldNotBe` format user diff --git a/test/FormattingSpec.hs b/test/FormattingSpec.hs index 9098999a..51be4372 100644 --- a/test/FormattingSpec.hs +++ b/test/FormattingSpec.hs @@ -83,21 +83,9 @@ dynamicJbflTests = do expected <- T.pack <$> readFile outFile pure (outFile, formatted, expected) -{- | Which mode a property is read in is hardcoded in the formatter. Three come -from an exact match, AutoPad, AlignObjectKeys and AutoPadSubObjects, and they -are the ones about how a container lays out its own children. The other six -cascade and come from a prefix match: ComplexNewLine, TrailingComma, Indent, -PreserveNumberFormat, PadAmount and PadDecimals. - -Moving one across changes formatting and no fixture notices. This pins the split -as it stands before `>` (see #187), which is meant to replace it, so expect to -rewrite this when that lands. --} reachSpec :: Spec reachSpec = do let row cells = mkArray (fromList cells) - -- The first column has to vary in width for AutoPad to show, since - -- trailing spaces on the last one are trimmed either way. rows = row [ row [String "a_long_name", Number (mkNumberValue "1" 1)] @@ -112,14 +100,10 @@ reachSpec = do ) ] ) - -- The rows array sits two breadcrumbs deep, so `.*` is a prefix of its - -- cursor and `.*.rows` matches it exactly. formatWith src = formatNode (rulesFromSource src) topNode shortPattern prop = ".* { " <> prop <> " }" exactPattern prop = ".*.rows { " <> prop <> " }" - -- The only difference is the run of spaces before the 2, which is the - -- second column padded out to the width of the first row. wrap body = "{\"part\" : {\n \"rows\" : [\n" <> body <> "\n ]\n}}\n" baseline = wrap " [\"a_long_name\", 1],\n [\"n1\", 2]" padded = wrap " [\"a_long_name\", 1],\n [\"n1\", 2]" @@ -127,8 +111,7 @@ reachSpec = do describe "how far down a property reaches" $ do it "applies AutoPad to the matched value only" $ do formatWith (exactPattern "AutoPad : true;") `shouldBe` padded - -- Without this line the assertion below also passes for a shortPattern - -- that matches nothing at all, which is not what is being claimed. + -- Guards the line below: a shortPattern matching nothing passes it too. formatWith (shortPattern "ComplexNewLine : Force;") `shouldNotBe` baseline formatWith (shortPattern "AutoPad : true;") `shouldBe` baseline