├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── swift.yml ├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── .swiftpm └── xcode │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDETemplateMacros.plist │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ └── xcschemes │ ├── Scout-Package.xcscheme │ ├── Scout.xcscheme │ ├── ScoutCLT.xcscheme │ └── ScoutCLTCore.xcscheme ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Highlight-presets ├── Colors-Homebrew.plist ├── Colors-Novel.plist ├── Colors-Ocean.plist └── README.md ├── LICENSE ├── Package.resolved ├── Package.swift ├── Playground ├── Commands.md ├── People.json ├── People.plist ├── People.xml └── People.yml ├── README.md ├── Resources ├── scout-logo.png ├── syntax-highlight.png └── syntax-highlighting-2.png ├── Sources ├── Parsing │ ├── Character+Extensions.swift │ ├── Parser+Operators.swift │ ├── Parser+Types.swift │ └── Parser.swift ├── Scout │ ├── Constants │ │ ├── DataFormat.swift │ │ ├── Folding.swift │ │ └── ScoutVersion.swift │ ├── ExplorerValue │ │ ├── CRUD │ │ │ ├── ExplorerValue+Add.swift │ │ │ ├── ExplorerValue+Delete.swift │ │ │ ├── ExplorerValue+Get.swift │ │ │ └── ExplorerValue+Set.swift │ │ ├── CSV │ │ │ ├── ExplorerValue+CSVExport.swift │ │ │ └── ExplorerValue+CSVImport.swift │ │ ├── ExplorerValue.swift │ │ └── Other │ │ │ ├── ExplorerValue+Codable.swift │ │ │ ├── ExplorerValue+Convenience.swift │ │ │ ├── ExplorerValue+CustomStringConvertible.swift │ │ │ ├── ExplorerValue+ExpressibleBy.swift │ │ │ ├── ExplorerValue+Folded.swift │ │ │ ├── ExplorerValue+Helpers.swift │ │ │ └── ExplorerValue+PathsListing.swift │ ├── ExplorerValueSerialization │ │ ├── ExplorerValueConvertible+Codable │ │ │ ├── CodableFormat │ │ │ │ ├── CodableFormat.swift │ │ │ │ ├── CodableFormats+JsonDateIso8601.swift │ │ │ │ ├── CodableFormats+JsonDefault.swift │ │ │ │ ├── CodableFormats+Namespace.swift │ │ │ │ ├── CodableFormats+PlistDefault.swift │ │ │ │ └── CodableFormats+YamlDefault.swift │ │ │ ├── Decoding │ │ │ │ ├── ExplorerValueDecoder.swift │ │ │ │ ├── ExplorerValueDecodingContainer.swift │ │ │ │ ├── ExplorerValueSingleDecodingContainer.swift │ │ │ │ └── ExplorerValueUnkeyedDecodingContainer.swift │ │ │ ├── DecodingError+Extensions.swift │ │ │ └── Encoding │ │ │ │ ├── ExplorerValueEncoder.swift │ │ │ │ ├── ExplorerValueEncodingContainer.swift │ │ │ │ ├── ExplorerValueSingleEncodingContainer.swift │ │ │ │ └── ExplorerValueUnkeyedEncodingContainer.swift │ │ ├── ExplorerValueConvertible+Primitive.swift │ │ ├── ExplorerValueConvertible.swift │ │ └── SerializationError.swift │ ├── ExplorerXML │ │ ├── ExplorerXML+Add.swift │ │ ├── ExplorerXML+CSVExport.swift │ │ ├── ExplorerXML+CSVImport.swift │ │ ├── ExplorerXML+Delete.swift │ │ ├── ExplorerXML+ExplorerValue.swift │ │ ├── ExplorerXML+Fold.swift │ │ ├── ExplorerXML+Get.swift │ │ ├── ExplorerXML+PathsListing.swift │ │ ├── ExplorerXML+Serialization.swift │ │ ├── ExplorerXML+Set.swift │ │ ├── ExplorerXML+SingleChildStrategy.swift │ │ ├── ExplorerXML+ValueSetter.swift │ │ └── ExplorerXML.swift │ ├── Extensions │ │ ├── AEXML │ │ │ ├── AEXMLElement+Children.swift │ │ │ ├── AEXMLElement+Equal.swift │ │ │ └── AEXMLElement+Group.swift │ │ ├── Array+Extensions.swift │ │ ├── CodingKey+Extensions.swift │ │ ├── Collection+Extensions.swift │ │ ├── Collection+Path.swift │ │ ├── Dictionary+Extensions.swift │ │ ├── Int+LastIndex.swift │ │ ├── NSRegularExpression+Extensions.swift │ │ ├── Optional+Extensions.swift │ │ ├── Slice+Etensions.swift │ │ ├── String+Extension.swift │ │ └── String+Jaro-Winkler.swift │ ├── Models │ │ ├── Error │ │ │ ├── ExplorerError.swift │ │ │ └── PathError.swift │ │ ├── Path │ │ │ ├── Bounds+Bound.swift │ │ │ ├── Bounds+IntWrapper.swift │ │ │ ├── Bounds.swift │ │ │ ├── Path+Flattening.swift │ │ │ ├── Path+Miscellaneous.swift │ │ │ ├── Path+StringConvertible.swift │ │ │ ├── Path.swift │ │ │ ├── PathElement+Convenience.swift │ │ │ ├── PathElement.swift │ │ │ ├── PathElementRepresentable.swift │ │ │ ├── PathTree+ValueType.swift │ │ │ └── PathTree.swift │ │ ├── PathExplorer │ │ │ ├── CodablePathExplorer+Serialization.swift │ │ │ ├── CodablePathExplorer.swift │ │ │ ├── EquatablePathExplorer.swift │ │ │ ├── PathExplorer+Convenience.swift │ │ │ ├── PathExplorer+ExploreWithMemory.swift │ │ │ ├── PathExplorer+Helpers.swift │ │ │ ├── PathExplorer.swift │ │ │ ├── PathExplorers.swift │ │ │ └── SerializablePathExplorer.swift │ │ ├── PathParser │ │ │ └── Path+Parsing.swift │ │ └── PathsFilter │ │ │ ├── PathsFilter+ExpressionPredicate.swift │ │ │ ├── PathsFilter+FunctionPredicate.swift │ │ │ ├── PathsFilter.swift │ │ │ ├── ValuePredicate.swift │ │ │ └── ValueTarget.swift │ └── Scout.docc │ │ ├── Articles │ │ ├── custom-types-explorerValue.md │ │ ├── getting-started.md │ │ ├── mastering-paths.md │ │ ├── new-4.0.0.md │ │ └── paths-listing.md │ │ ├── Extensions │ │ ├── explorer-value.md │ │ ├── path-element.md │ │ ├── path-explorer.md │ │ ├── path.md │ │ ├── paths-filter.md │ │ ├── serializable-path-explorer-export-folder.md │ │ └── serializable-path-explorer.md │ │ └── Scout.md ├── ScoutCLT │ ├── AdvancedTopicsDoc │ │ ├── AdvancedTopic.swift │ │ └── AdvandedPredicates.swift │ ├── CRUD │ │ ├── Add │ │ │ ├── AddCommand.swift │ │ │ └── AddDocumentation.swift │ │ ├── Delete │ │ │ ├── DeleteCommand.swift │ │ │ ├── DeleteDocumentation.swift │ │ │ └── DeleteKeyCommand.swift │ │ ├── Read │ │ │ ├── ReadCommand.swift │ │ │ └── ReadDocumentation.swift │ │ └── Set │ │ │ ├── SetCommand.swift │ │ │ └── SetDocumentation.swift │ ├── CSVCommand.swift │ ├── ColorDelegates │ │ ├── ColorFile.swift │ │ ├── JSONInjectorDelegate.swift │ │ ├── PlistInjectorColorDelegate.swift │ │ ├── XMLInjectorColorDelegate.swift │ │ └── YAMLInjectorColorDelegate.swift │ ├── Extensions │ │ ├── ArgumentHelp+Extensions.swift │ │ ├── ArgumentParserConformance │ │ │ ├── DataFormat+ArgumentParser.swift │ │ │ ├── ExportFormat+ArgumentParser.swift │ │ │ ├── ParsableCommand+Extensions.swift │ │ │ ├── ParsableCommand+PathCompletion.swift │ │ │ └── PathAndValue+ArgumentParser.swift │ │ ├── FileHandle+Extensions.swift │ │ ├── Optional+Extensions.swift │ │ ├── Path+Extensions.swift │ │ └── String+Extensions.swift │ ├── Main │ │ ├── CommandsRecords.swift │ │ ├── DocCommand.swift │ │ ├── InstallCompletionScriptCommand.swift │ │ ├── PathExplorerInputCommand.swift │ │ └── ScoutMainCommand.swift │ ├── Models │ │ ├── ColorFlag.swift │ │ ├── Command.swift │ │ ├── Documentation.swift │ │ ├── PathExplorer+Alias.swift │ │ ├── RuntimeError.swift │ │ ├── SADCommand.swift │ │ └── ValidationError.swift │ └── Paths │ │ ├── PathsCommand.swift │ │ └── PathsDocumentation.swift └── ScoutCLTCore │ ├── Extensions │ ├── Collection+Extensions.swift │ ├── ExplorerValue+Extensions.swift │ └── URL+Extensions.swift │ └── Models │ ├── CLTCoreError.swift │ ├── ExportCommand.swift │ ├── ExportFormat.swift │ ├── GroupExportValue.swift │ ├── PathAndValue+Parser.swift │ ├── PathAndValue.swift │ └── ValueType.swift ├── Tests ├── ScoutCLTCoreTests │ ├── ExportCommandTests.swift │ └── ValueParserTests.swift └── ScoutTests │ ├── Definitions │ ├── ParserTests.swift │ ├── Path │ │ ├── PathTests+Flattening.swift │ │ ├── PathTests+Miscellaneous.swift │ │ └── PathTests.swift │ └── ValueTypeTests+Codable.swift │ ├── ExplorerValueCoder │ ├── ExplorerValueDecoderTests.swift │ └── ExplorerValueEncoderTests.swift │ ├── ExplorerXML │ ├── PathExplorerXMLTests+COW.swift │ └── PathExplorerXMLTests+ExplorerValue.swift │ ├── Extensions │ ├── PathExplorers+Alias.swift │ ├── URL+Extensions.swift │ └── XCTestCase+Extensions.swift │ ├── ExtensionsTests │ ├── AEXMLExtensionsTests.swift │ ├── ArrayTests.swift │ ├── NSRegularExpressionExtensionsTests.swift │ ├── PathExplorerHelperTests.swift │ ├── String+Jaro-WinklerTests.swift │ └── StringExtensionsTests.swift │ ├── Models │ ├── BoundsTests.swift │ └── PathsFilterTests.swift │ ├── PathExplorerTestsSuite │ ├── PathExplorer+CSVImport.swift │ ├── PathExplorerTests+Add.swift │ ├── PathExplorerTests+CSVExport.swift │ ├── PathExplorerTests+Delete.swift │ ├── PathExplorerTests+Fold.swift │ ├── PathExplorerTests+Get.swift │ ├── PathExplorerTests+PathsListing.swift │ └── PathExplorerTests+Set.swift │ └── PathTree │ └── PathTreeTests.swift ├── clt-test.sh ├── codecov.yml └── docs ├── css ├── chunk-c0335d80.10a2f091.css ├── documentation-topic.1d1eec04.css ├── documentation-topic~topic.b6287bcf.css ├── documentation-topic~topic~tutorials-overview.d6f5411c.css ├── index.038e887c.css ├── topic.d8c126f3.css └── tutorials-overview.c249c765.css ├── data └── documentation │ ├── scout.json │ └── scout │ ├── bounds.json │ ├── bounds │ ├── !=(_:_:).json │ ├── bound.json │ ├── bound │ │ ├── !=(_:_:).json │ │ ├── equatable-implementations.json │ │ ├── first.json │ │ ├── init(_:).json │ │ ├── init(integerliteral:).json │ │ ├── integerliteraltype.json │ │ └── last.json │ ├── equatable-implementations.json │ ├── init(lower:upper:).json │ └── range(arraycount:).json │ ├── codableformat.json │ ├── codableformat │ ├── dataformat.json │ ├── decode(_:from:).json │ ├── encode(_:).json │ ├── encode(_:rootname:).json │ └── foldedregexpattern.json │ ├── codableformats.json │ ├── codableformats │ ├── jsondateiso8601.json │ ├── jsondateiso8601 │ │ ├── codableformat-implementations.json │ │ ├── dataformat.json │ │ ├── decode(_:from:).json │ │ ├── encode(_:).json │ │ ├── encode(_:rootname:).json │ │ └── foldedregexpattern.json │ ├── jsondefault.json │ ├── jsondefault │ │ ├── codableformat-implementations.json │ │ ├── dataformat.json │ │ ├── decode(_:from:).json │ │ ├── encode(_:).json │ │ ├── encode(_:rootname:).json │ │ └── foldedregexpattern.json │ ├── plistdefault.json │ ├── plistdefault │ │ ├── codableformat-implementations.json │ │ ├── dataformat.json │ │ ├── decode(_:from:).json │ │ ├── encode(_:).json │ │ ├── encode(_:rootname:).json │ │ └── foldedregexpattern.json │ ├── yamldefault.json │ └── yamldefault │ │ ├── codableformat-implementations.json │ │ ├── dataformat.json │ │ ├── decode(_:from:).json │ │ ├── encode(_:).json │ │ ├── encode(_:rootname:).json │ │ └── foldedregexpattern.json │ ├── codablepathexplorer.json │ ├── codablepathexplorer │ ├── add(_:at:)-13yei.json │ ├── add(_:at:)-1mpqn.json │ ├── add(_:at:)-9ka70.json │ ├── add(_:at:)-w76g.json │ ├── adding(_:at:).json │ ├── array(of:).json │ ├── bool.json │ ├── data.json │ ├── date.json │ ├── debugdescription.json │ ├── delete(_:).json │ ├── delete(_:deleteifempty:)-1iwci.json │ ├── delete(_:deleteifempty:)-3e7af.json │ ├── delete(_:deleteifempty:)-8sq6g.json │ ├── deleting(_:deleteifempty:).json │ ├── description.json │ ├── dictionary(of:).json │ ├── double.json │ ├── exportcsv().json │ ├── exportcsv(separator:).json │ ├── exportdata().json │ ├── exportdata(to:).json │ ├── exportdata(to:rootname:).json │ ├── exportfoldedstring(upto:).json │ ├── exportstring().json │ ├── exportstring(to:).json │ ├── exportstring(to:rootname:).json │ ├── expressiblebyextendedgraphemeclusterliteral-implementations.json │ ├── expressiblebyunicodescalarliteral-implementations.json │ ├── folded(upto:).json │ ├── format.json │ ├── fromcsv(string:separator:hasheaders:).json │ ├── get(_:).json │ ├── init(booleanliteral:).json │ ├── init(data:).json │ ├── init(extendedgraphemeclusterliteral:).json │ ├── init(floatliteral:).json │ ├── init(integerliteral:).json │ ├── init(stringliteral:).json │ ├── init(unicodescalarliteral:).json │ ├── init(value:).json │ ├── init(value:name:).json │ ├── int.json │ ├── isgroup.json │ ├── issingle.json │ ├── listpaths(startingat:).json │ ├── listpaths(startingat:filter:).json │ ├── pathexplorer-implementations.json │ ├── real.json │ ├── serializablepathexplorer-implementations.json │ ├── set(_:keynameto:)-1z5hp.json │ ├── set(_:keynameto:)-40f4n.json │ ├── set(_:keynameto:)-6dvwq.json │ ├── set(_:to:)-15dj0.json │ ├── set(_:to:)-40ro5.json │ ├── set(_:to:)-61aqz.json │ ├── set(_:to:)-7lp6u.json │ ├── setting(_:keynameto:).json │ ├── setting(_:to:).json │ └── string.json │ ├── custom-types-explorervalue.json │ ├── dataformat.json │ ├── dataformat │ ├── !=(_:_:).json │ ├── equatable-implementations.json │ ├── hash(into:).json │ ├── hashvalue.json │ ├── init(rawvalue:).json │ ├── json.json │ ├── plist.json │ ├── rawrepresentable-implementations.json │ ├── xml.json │ └── yaml.json │ ├── explorererror.json │ ├── explorererror │ ├── !=(_:_:).json │ ├── equatable-implementations.json │ ├── error-implementations.json │ ├── errordescription.json │ ├── failurereason.json │ ├── helpanchor.json │ ├── invalid(value:).json │ ├── localizeddescription.json │ ├── localizederror-implementations.json │ ├── mismatchingtype(_:value:).json │ ├── missing(key:bestmatch:).json │ ├── path.json │ ├── predicatenotevaluatable(_:description:).json │ ├── recoverysuggestion.json │ ├── subscriptindexnoarray.json │ ├── subscriptkeynodict.json │ ├── wrong(bounds:arraycount:).json │ ├── wrong(index:arraycount:).json │ ├── wrong(regexpattern:).json │ └── wrongusage(of:).json │ ├── explorervalue.json │ ├── explorervalue │ ├── !=(_:_:).json │ ├── add(_:at:)-4gmuo.json │ ├── add(_:at:)-5gilx.json │ ├── add(_:at:)-8223h.json │ ├── add(_:at:)-8r71p.json │ ├── adding(_:at:).json │ ├── array(_:).json │ ├── array(of:).json │ ├── array.json │ ├── arrayvalue.json │ ├── bool(_:).json │ ├── bool.json │ ├── customdebugstringconvertible-implementations.json │ ├── customstringconvertible-implementations.json │ ├── data(_:).json │ ├── data.json │ ├── date(_:).json │ ├── date.json │ ├── debugdescription.json │ ├── decodable-implementations.json │ ├── delete(_:).json │ ├── delete(_:deleteifempty:)-215jh.json │ ├── delete(_:deleteifempty:)-55slk.json │ ├── delete(_:deleteifempty:)-5j8qh.json │ ├── deleting(_:deleteifempty:).json │ ├── description.json │ ├── dictionary(_:).json │ ├── dictionary(of:).json │ ├── dictionary.json │ ├── dictionaryvalue.json │ ├── double(_:).json │ ├── double.json │ ├── encodable-implementations.json │ ├── encode(to:).json │ ├── equatable-implementations.json │ ├── expressiblebyarrayliteral-implementations.json │ ├── expressiblebybooleanliteral-implementations.json │ ├── expressiblebydictionaryliteral-implementations.json │ ├── expressiblebyextendedgraphemeclusterliteral-implementations.json │ ├── expressiblebyfloatliteral-implementations.json │ ├── expressiblebyintegerliteral-implementations.json │ ├── expressiblebystringliteral-implementations.json │ ├── expressiblebyunicodescalarliteral-implementations.json │ ├── get(_:).json │ ├── init(arrayliteral:).json │ ├── init(booleanliteral:).json │ ├── init(dictionaryliteral:).json │ ├── init(extendedgraphemeclusterliteral:).json │ ├── init(floatliteral:).json │ ├── init(from:).json │ ├── init(integerliteral:).json │ ├── init(stringliteral:).json │ ├── init(unicodescalarliteral:).json │ ├── init(value:).json │ ├── init(value:name:).json │ ├── int(_:).json │ ├── int.json │ ├── isgroup.json │ ├── issingle.json │ ├── listpaths(startingat:).json │ ├── listpaths(startingat:filter:).json │ ├── pathexplorer-implementations.json │ ├── real.json │ ├── set(_:keynameto:)-71khn.json │ ├── set(_:keynameto:)-7cmde.json │ ├── set(_:keynameto:)-9elrr.json │ ├── set(_:to:)-1osuj.json │ ├── set(_:to:)-1p08w.json │ ├── set(_:to:)-85z1n.json │ ├── set(_:to:)-neu9.json │ ├── setting(_:keynameto:).json │ ├── setting(_:to:).json │ ├── string(_:).json │ └── string.json │ ├── explorervalueconvertible.json │ ├── explorervaluecreatable.json │ ├── explorervaluecreatable │ ├── init(from:)-2m6tw.json │ └── init(from:)-7khyl.json │ ├── explorervaluerepresentable.json │ ├── explorervaluerepresentable │ ├── explorervalue()-1gz0u.json │ └── explorervalue()-9wvc3.json │ ├── explorerxml.json │ ├── explorerxml │ ├── add(_:at:)-1bcbx.json │ ├── add(_:at:)-1pzz6.json │ ├── add(_:at:)-1vd0k.json │ ├── add(_:at:)-4t6ia.json │ ├── add(_:at:)-4y7o0.json │ ├── add(_:at:)-5c99x.json │ ├── adding(_:at:)-1pus.json │ ├── adding(_:at:)-3bl3a.json │ ├── adding(_:at:)-4y55p.json │ ├── adding(_:at:)-5hn92.json │ ├── adding(_:at:)-9e3bi.json │ ├── adding(_:at:)-cwm8.json │ ├── array(of:).json │ ├── array(of:keepingattributes:singlechildstrategy:).json │ ├── bool.json │ ├── data.json │ ├── date.json │ ├── debugdescription.json │ ├── delete(_:).json │ ├── delete(_:deleteifempty:)-3fqmj.json │ ├── delete(_:deleteifempty:)-9oiah.json │ ├── delete(_:deleteifempty:)-9pz8.json │ ├── deleting(_:deleteifempty:).json │ ├── description.json │ ├── dictionary(of:).json │ ├── dictionary(of:keepingattributes:singlechildstrategy:).json │ ├── double.json │ ├── element.json │ ├── explorervalue(keepingattributes:singlechildstrategy:).json │ ├── exportcsv().json │ ├── exportcsv(separator:).json │ ├── exportdata().json │ ├── exportdata(to:).json │ ├── exportdata(to:rootname:).json │ ├── exportfoldedstring(upto:).json │ ├── exportstring().json │ ├── exportstring(to:).json │ ├── exportstring(to:rootname:).json │ ├── expressiblebyextendedgraphemeclusterliteral-implementations.json │ ├── expressiblebyunicodescalarliteral-implementations.json │ ├── folded(upto:).json │ ├── format.json │ ├── fromcsv(string:separator:hasheaders:).json │ ├── get(_:).json │ ├── init(booleanliteral:).json │ ├── init(data:).json │ ├── init(extendedgraphemeclusterliteral:).json │ ├── init(floatliteral:).json │ ├── init(integerliteral:).json │ ├── init(stringliteral:).json │ ├── init(unicodescalarliteral:).json │ ├── init(value:).json │ ├── init(value:name:).json │ ├── int.json │ ├── isgroup.json │ ├── issingle.json │ ├── listpaths(startingat:).json │ ├── listpaths(startingat:filter:).json │ ├── pathexplorer-implementations.json │ ├── real.json │ ├── serializablepathexplorer-implementations.json │ ├── set(_:keynameto:)-1bi3d.json │ ├── set(_:keynameto:)-3whe6.json │ ├── set(_:keynameto:)-8bycm.json │ ├── set(_:to:)-2wq5w.json │ ├── set(_:to:)-3d1tv.json │ ├── set(_:to:)-45huy.json │ ├── set(_:to:)-54j6g.json │ ├── set(_:to:)-8wtzf.json │ ├── set(_:to:)-ofo9.json │ ├── setting(_:keynameto:).json │ ├── setting(_:to:)-1eczh.json │ ├── setting(_:to:)-2pw3q.json │ ├── setting(_:to:)-4m6ll.json │ ├── setting(_:to:)-4xlv9.json │ ├── setting(_:to:)-5h22p.json │ ├── setting(_:to:)-7elcu.json │ ├── singlechildstrategy.json │ ├── singlechildstrategy │ │ ├── array.json │ │ ├── custom(_:).json │ │ ├── default.json │ │ ├── dictionary.json │ │ └── transform.json │ └── string.json │ ├── getting-started.json │ ├── mastering-paths.json │ ├── new-4.0.0.json │ ├── path.json │ ├── path │ ├── !=(_:_:).json │ ├── +(_:_:)-1mpyt.json │ ├── +(_:_:)-4knou.json │ ├── +(_:_:)-wurs.json │ ├── +=(_:_:).json │ ├── allsatisfy(_:).json │ ├── append(_:)-6mddf.json │ ├── append(_:)-9l194.json │ ├── append(contentsof:).json │ ├── appending(_:)-2ptn6.json │ ├── appending(_:)-3mvwq.json │ ├── applying(_:).json │ ├── arrayliteralelement.json │ ├── bidirectionalcollection-implementations.json │ ├── collection-implementations.json │ ├── commonprefix(with:).json │ ├── compactmap(_:).json │ ├── compactmapfilter.json │ ├── compactmapindexes.json │ ├── compactmapkeys.json │ ├── compactmapslices.json │ ├── compare(_:_:).json │ ├── comparedbykeyandindexes(with:).json │ ├── contains(_:).json │ ├── contains(where:).json │ ├── count.json │ ├── debugdescription.json │ ├── defaultseparator.json │ ├── description.json │ ├── difference(from:).json │ ├── difference(from:by:).json │ ├── drop(while:).json │ ├── dropfirst(_:).json │ ├── droplast(_:).json │ ├── elementsequal(_:).json │ ├── elementsequal(_:by:).json │ ├── empty.json │ ├── endindex.json │ ├── enumerated().json │ ├── equatable-implementations.json │ ├── expressiblebyarrayliteral-implementations.json │ ├── filter(_:).json │ ├── first(where:).json │ ├── first.json │ ├── firstindex(of:).json │ ├── firstindex(where:).json │ ├── firstrange(of:).json │ ├── flatmap(_:)-4dfav.json │ ├── flatmap(_:)-658d.json │ ├── flattened().json │ ├── foreach(_:).json │ ├── formatted(_:).json │ ├── formindex(_:offsetby:).json │ ├── formindex(_:offsetby:limitedby:).json │ ├── formindex(after:).json │ ├── formindex(before:).json │ ├── index(_:offsetby:limitedby:).json │ ├── index(after:).json │ ├── index(of:).json │ ├── init().json │ ├── init(_:)-1b2iy.json │ ├── init(_:)-3ayg2.json │ ├── init(_:)-cgb7.json │ ├── init(arrayliteral:).json │ ├── init(elements:)-8dch4.json │ ├── init(elements:)-9i64v.json │ ├── init(repeating:count:).json │ ├── init(string:separator:).json │ ├── insert(_:at:).json │ ├── insert(contentsof:at:).json │ ├── isempty.json │ ├── last(where:).json │ ├── last.json │ ├── lastindex(of:).json │ ├── lastindex(where:).json │ ├── lazy.json │ ├── lexicographicallyprecedes(_:by:).json │ ├── makeiterator().json │ ├── map(_:)-1pyvn.json │ ├── map(_:)-3bvvx.json │ ├── max(by:).json │ ├── min(by:).json │ ├── mutablecollection-implementations.json │ ├── parser(separator:keyforbiddencharacters:).json │ ├── partition(by:)-5mp72.json │ ├── partition(by:)-70krf.json │ ├── poplast().json │ ├── prefix(_:).json │ ├── prefix(through:).json │ ├── prefix(upto:).json │ ├── prefix(while:).json │ ├── publisher.json │ ├── randomaccesscollection-implementations.json │ ├── randomelement().json │ ├── randomelement(using:).json │ ├── rangereplaceablecollection-implementations.json │ ├── ranges(of:).json │ ├── reduce(_:_:).json │ ├── reduce(into:_:).json │ ├── remove(at:).json │ ├── removeall(keepingcapacity:).json │ ├── removeall(where:)-13bwz.json │ ├── removeall(where:)-6oyg2.json │ ├── removefirst().json │ ├── removefirst(_:).json │ ├── removelast().json │ ├── removelast(_:).json │ ├── removesubrange(_:)-28mkd.json │ ├── removesubrange(_:)-3w6oh.json │ ├── replace(_:with:maxreplacements:).json │ ├── replacesubrange(_:with:)-69vd1.json │ ├── replacesubrange(_:with:)-8jwu3.json │ ├── replacesubrange(_:with:)-8v4n8.json │ ├── replacing(_:with:maxreplacements:).json │ ├── replacing(_:with:subrange:maxreplacements:).json │ ├── reservecapacity(_:).json │ ├── reverse().json │ ├── reversed().json │ ├── sequence-implementations.json │ ├── shuffle().json │ ├── shuffle(using:).json │ ├── shuffled().json │ ├── shuffled(using:).json │ ├── sort(by:).json │ ├── sort(using:)-20eip.json │ ├── sort(using:)-7hq1j.json │ ├── sorted(by:).json │ ├── sorted(using:)-1q9xt.json │ ├── sorted(using:)-2epe7.json │ ├── split(maxsplits:omittingemptysubsequences:whereseparator:).json │ ├── split(separator:maxsplits:omittingemptysubsequences:).json │ ├── startindex.json │ ├── starts(with:).json │ ├── starts(with:by:).json │ ├── subscript(_:).json │ ├── suffix(_:).json │ ├── suffix(from:).json │ ├── swapat(_:_:).json │ ├── trimmingprefix(_:).json │ ├── trimmingprefix(while:).json │ ├── trimprefix(_:).json │ ├── trimprefix(while:).json │ ├── underestimatedcount.json │ ├── withcontiguousmutablestorageifavailable(_:).json │ └── withcontiguousstorageifavailable(_:).json │ ├── pathelement.json │ ├── pathelement │ ├── !=(_:_:).json │ ├── count.json │ ├── customstringconvertible-implementations.json │ ├── description.json │ ├── equatable-implementations.json │ ├── expressiblebyextendedgraphemeclusterliteral-implementations.json │ ├── expressiblebyintegerliteral-implementations.json │ ├── expressiblebystringliteral-implementations.json │ ├── expressiblebyunicodescalarliteral-implementations.json │ ├── filter(_:).json │ ├── index(_:).json │ ├── init(extendedgraphemeclusterliteral:).json │ ├── init(integerliteral:).json │ ├── init(stringliteral:).json │ ├── init(unicodescalarliteral:).json │ ├── integerliteraltype.json │ ├── key(_:).json │ ├── keyslist.json │ ├── pathelementrepresentable-implementations.json │ ├── pathvalue.json │ ├── slice(_:).json │ ├── slice(_:_:).json │ └── stringliteraltype.json │ ├── pathelementrepresentable.json │ ├── pathelementrepresentable │ └── pathvalue.json │ ├── pathexplorer.json │ ├── pathexplorer │ ├── add(_:at:)-2kii6.json │ ├── add(_:at:)-2zxor.json │ ├── add(_:at:)-6wo3i.json │ ├── add(_:at:)-861h4.json │ ├── adding(_:at:)-4ju9b.json │ ├── adding(_:at:)-5uv86.json │ ├── adding(_:at:)-68mxp.json │ ├── adding(_:at:)-7fd9c.json │ ├── array(of:).json │ ├── bool.json │ ├── data.json │ ├── date.json │ ├── delete(_:).json │ ├── delete(_:deleteifempty:)-2uxwq.json │ ├── delete(_:deleteifempty:)-40w9g.json │ ├── delete(_:deleteifempty:)-g45f.json │ ├── deleting(_:deleteifempty:)-1byw9.json │ ├── deleting(_:deleteifempty:)-2u4ud.json │ ├── deleting(_:deleteifempty:)-32ufs.json │ ├── dictionary(of:).json │ ├── double.json │ ├── get(_:)-2ghf1.json │ ├── get(_:)-6pa9h.json │ ├── get(_:)-8vyte.json │ ├── init(value:).json │ ├── init(value:name:).json │ ├── int.json │ ├── isgroup.json │ ├── issingle.json │ ├── listpaths(startingat:).json │ ├── listpaths(startingat:filter:)-4tkeq.json │ ├── listpaths(startingat:filter:)-8y0x2.json │ ├── real.json │ ├── set(_:keynameto:)-1zwfv.json │ ├── set(_:keynameto:)-5j60r.json │ ├── set(_:keynameto:)-9i6hd.json │ ├── set(_:to:)-376n0.json │ ├── set(_:to:)-5fgny.json │ ├── set(_:to:)-6yk0i.json │ ├── set(_:to:)-9d877.json │ ├── setting(_:keynameto:)-1fmyp.json │ ├── setting(_:keynameto:)-1vrh.json │ ├── setting(_:keynameto:)-7ar89.json │ ├── setting(_:to:)-5tdzy.json │ ├── setting(_:to:)-7q3g.json │ ├── setting(_:to:)-9vtr8.json │ ├── setting(_:to:)-n2ij.json │ └── string.json │ ├── pathexplorers.json │ ├── pathexplorers │ ├── json.json │ ├── plist.json │ ├── xml.json │ └── yaml.json │ ├── paths-listing.json │ ├── pathsfilter.json │ ├── pathsfilter │ ├── expressionpredicate.json │ ├── expressionpredicate │ │ ├── evaluate(with:).json │ │ └── init(format:).json │ ├── functionpredicate.json │ ├── functionpredicate │ │ ├── evaluate(with:).json │ │ ├── evaluation-swift.property.json │ │ ├── evaluation-swift.typealias.json │ │ └── init(evaluation:).json │ ├── key(pattern:target:).json │ ├── key(regex:).json │ ├── key(regex:target:).json │ ├── keyandvalue(keyregex:valuepredicate:).json │ ├── keyandvalue(keyregex:valuepredicates:).json │ ├── keyandvalue(keyregex:valuepredicates:_:).json │ ├── keyandvalue(pattern:valuepredicate:).json │ ├── keyandvalue(pattern:valuepredicatesformat:_:).json │ ├── nofilter.json │ ├── targetonly(_:).json │ ├── value(_:).json │ ├── value(_:_:)-2wxh0.json │ ├── value(_:_:)-8tfx1.json │ ├── valuetarget.json │ └── valuetarget │ │ ├── !=(_:_:).json │ │ ├── equatable-implementations.json │ │ ├── group.json │ │ ├── hash(into:).json │ │ ├── hashvalue.json │ │ ├── init(rawvalue:).json │ │ ├── rawrepresentable-implementations.json │ │ ├── single.json │ │ └── singleandgroup.json │ ├── serializablepathexplorer.json │ ├── serializablepathexplorer │ ├── exportcsv().json │ ├── exportcsv(separator:).json │ ├── exportdata().json │ ├── exportdata(to:).json │ ├── exportdata(to:rootname:).json │ ├── exportfoldedstring(upto:).json │ ├── exportstring().json │ ├── exportstring(to:).json │ ├── exportstring(to:rootname:).json │ ├── folded(upto:).json │ ├── format.json │ ├── fromcsv(string:separator:hasheaders:).json │ └── init(data:).json │ ├── serializationerror.json │ ├── serializationerror │ ├── datatostring.json │ ├── error-implementations.json │ ├── errordescription.json │ ├── failurereason.json │ ├── helpanchor.json │ ├── localizeddescription.json │ ├── localizederror-implementations.json │ ├── notcsvexportable(description:).json │ ├── recoverysuggestion.json │ └── stringtodata.json │ ├── valuepredicate.json │ └── valuepredicate │ └── evaluate(with:).json ├── developer-og-twitter.jpg ├── developer-og.jpg ├── documentation └── scout │ ├── bounds │ ├── !=(_:_:) │ │ └── index.html │ ├── bound │ │ ├── !=(_:_:) │ │ │ └── index.html │ │ ├── equatable-implementations │ │ │ └── index.html │ │ ├── first │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(_:) │ │ │ └── index.html │ │ ├── init(integerliteral:) │ │ │ └── index.html │ │ ├── integerliteraltype │ │ │ └── index.html │ │ └── last │ │ │ └── index.html │ ├── equatable-implementations │ │ └── index.html │ ├── index.html │ ├── init(lower:upper:) │ │ └── index.html │ └── range(arraycount:) │ │ └── index.html │ ├── codableformat │ ├── dataformat │ │ └── index.html │ ├── decode(_:from:) │ │ └── index.html │ ├── encode(_:) │ │ └── index.html │ ├── encode(_:rootname:) │ │ └── index.html │ ├── foldedregexpattern │ │ └── index.html │ └── index.html │ ├── codableformats │ ├── index.html │ ├── jsondateiso8601 │ │ ├── codableformat-implementations │ │ │ └── index.html │ │ ├── dataformat │ │ │ └── index.html │ │ ├── decode(_:from:) │ │ │ └── index.html │ │ ├── encode(_:) │ │ │ └── index.html │ │ ├── encode(_:rootname:) │ │ │ └── index.html │ │ ├── foldedregexpattern │ │ │ └── index.html │ │ └── index.html │ ├── jsondefault │ │ ├── codableformat-implementations │ │ │ └── index.html │ │ ├── dataformat │ │ │ └── index.html │ │ ├── decode(_:from:) │ │ │ └── index.html │ │ ├── encode(_:) │ │ │ └── index.html │ │ ├── encode(_:rootname:) │ │ │ └── index.html │ │ ├── foldedregexpattern │ │ │ └── index.html │ │ └── index.html │ ├── plistdefault │ │ ├── codableformat-implementations │ │ │ └── index.html │ │ ├── dataformat │ │ │ └── index.html │ │ ├── decode(_:from:) │ │ │ └── index.html │ │ ├── encode(_:) │ │ │ └── index.html │ │ ├── encode(_:rootname:) │ │ │ └── index.html │ │ ├── foldedregexpattern │ │ │ └── index.html │ │ └── index.html │ └── yamldefault │ │ ├── codableformat-implementations │ │ └── index.html │ │ ├── dataformat │ │ └── index.html │ │ ├── decode(_:from:) │ │ └── index.html │ │ ├── encode(_:) │ │ └── index.html │ │ ├── encode(_:rootname:) │ │ └── index.html │ │ ├── foldedregexpattern │ │ └── index.html │ │ └── index.html │ ├── codablepathexplorer │ ├── add(_:at:)-13yei │ │ └── index.html │ ├── add(_:at:)-1mpqn │ │ └── index.html │ ├── add(_:at:)-9ka70 │ │ └── index.html │ ├── add(_:at:)-w76g │ │ └── index.html │ ├── adding(_:at:) │ │ └── index.html │ ├── array(of:) │ │ └── index.html │ ├── bool │ │ └── index.html │ ├── data │ │ └── index.html │ ├── date │ │ └── index.html │ ├── debugdescription │ │ └── index.html │ ├── delete(_:) │ │ └── index.html │ ├── delete(_:deleteifempty:)-1iwci │ │ └── index.html │ ├── delete(_:deleteifempty:)-3e7af │ │ └── index.html │ ├── delete(_:deleteifempty:)-8sq6g │ │ └── index.html │ ├── deleting(_:deleteifempty:) │ │ └── index.html │ ├── description │ │ └── index.html │ ├── dictionary(of:) │ │ └── index.html │ ├── double │ │ └── index.html │ ├── exportcsv() │ │ └── index.html │ ├── exportcsv(separator:) │ │ └── index.html │ ├── exportdata() │ │ └── index.html │ ├── exportdata(to:) │ │ └── index.html │ ├── exportdata(to:rootname:) │ │ └── index.html │ ├── exportfoldedstring(upto:) │ │ └── index.html │ ├── exportstring() │ │ └── index.html │ ├── exportstring(to:) │ │ └── index.html │ ├── exportstring(to:rootname:) │ │ └── index.html │ ├── expressiblebyextendedgraphemeclusterliteral-implementations │ │ └── index.html │ ├── expressiblebyunicodescalarliteral-implementations │ │ └── index.html │ ├── folded(upto:) │ │ └── index.html │ ├── format │ │ └── index.html │ ├── fromcsv(string:separator:hasheaders:) │ │ └── index.html │ ├── get(_:) │ │ └── index.html │ ├── index.html │ ├── init(booleanliteral:) │ │ └── index.html │ ├── init(data:) │ │ └── index.html │ ├── init(extendedgraphemeclusterliteral:) │ │ └── index.html │ ├── init(floatliteral:) │ │ └── index.html │ ├── init(integerliteral:) │ │ └── index.html │ ├── init(stringliteral:) │ │ └── index.html │ ├── init(unicodescalarliteral:) │ │ └── index.html │ ├── init(value:) │ │ └── index.html │ ├── init(value:name:) │ │ └── index.html │ ├── int │ │ └── index.html │ ├── isgroup │ │ └── index.html │ ├── issingle │ │ └── index.html │ ├── listpaths(startingat:) │ │ └── index.html │ ├── listpaths(startingat:filter:) │ │ └── index.html │ ├── pathexplorer-implementations │ │ └── index.html │ ├── real │ │ └── index.html │ ├── serializablepathexplorer-implementations │ │ └── index.html │ ├── set(_:keynameto:)-1z5hp │ │ └── index.html │ ├── set(_:keynameto:)-40f4n │ │ └── index.html │ ├── set(_:keynameto:)-6dvwq │ │ └── index.html │ ├── set(_:to:)-15dj0 │ │ └── index.html │ ├── set(_:to:)-40ro5 │ │ └── index.html │ ├── set(_:to:)-61aqz │ │ └── index.html │ ├── set(_:to:)-7lp6u │ │ └── index.html │ ├── setting(_:keynameto:) │ │ └── index.html │ ├── setting(_:to:) │ │ └── index.html │ └── string │ │ └── index.html │ ├── custom-types-explorervalue │ └── index.html │ ├── dataformat │ ├── !=(_:_:) │ │ └── index.html │ ├── equatable-implementations │ │ └── index.html │ ├── hash(into:) │ │ └── index.html │ ├── hashvalue │ │ └── index.html │ ├── index.html │ ├── init(rawvalue:) │ │ └── index.html │ ├── json │ │ └── index.html │ ├── plist │ │ └── index.html │ ├── rawrepresentable-implementations │ │ └── index.html │ ├── xml │ │ └── index.html │ └── yaml │ │ └── index.html │ ├── explorererror │ ├── !=(_:_:) │ │ └── index.html │ ├── equatable-implementations │ │ └── index.html │ ├── error-implementations │ │ └── index.html │ ├── errordescription │ │ └── index.html │ ├── failurereason │ │ └── index.html │ ├── helpanchor │ │ └── index.html │ ├── index.html │ ├── invalid(value:) │ │ └── index.html │ ├── localizeddescription │ │ └── index.html │ ├── localizederror-implementations │ │ └── index.html │ ├── mismatchingtype(_:value:) │ │ └── index.html │ ├── missing(key:bestmatch:) │ │ └── index.html │ ├── path │ │ └── index.html │ ├── predicatenotevaluatable(_:description:) │ │ └── index.html │ ├── recoverysuggestion │ │ └── index.html │ ├── subscriptindexnoarray │ │ └── index.html │ ├── subscriptkeynodict │ │ └── index.html │ ├── wrong(bounds:arraycount:) │ │ └── index.html │ ├── wrong(index:arraycount:) │ │ └── index.html │ ├── wrong(regexpattern:) │ │ └── index.html │ └── wrongusage(of:) │ │ └── index.html │ ├── explorervalue │ ├── !=(_:_:) │ │ └── index.html │ ├── add(_:at:)-4gmuo │ │ └── index.html │ ├── add(_:at:)-5gilx │ │ └── index.html │ ├── add(_:at:)-8223h │ │ └── index.html │ ├── add(_:at:)-8r71p │ │ └── index.html │ ├── adding(_:at:) │ │ └── index.html │ ├── array(_:) │ │ └── index.html │ ├── array(of:) │ │ └── index.html │ ├── array │ │ └── index.html │ ├── arrayvalue │ │ └── index.html │ ├── bool(_:) │ │ └── index.html │ ├── bool │ │ └── index.html │ ├── customdebugstringconvertible-implementations │ │ └── index.html │ ├── customstringconvertible-implementations │ │ └── index.html │ ├── data(_:) │ │ └── index.html │ ├── data │ │ └── index.html │ ├── date(_:) │ │ └── index.html │ ├── date │ │ └── index.html │ ├── debugdescription │ │ └── index.html │ ├── decodable-implementations │ │ └── index.html │ ├── delete(_:) │ │ └── index.html │ ├── delete(_:deleteifempty:)-215jh │ │ └── index.html │ ├── delete(_:deleteifempty:)-55slk │ │ └── index.html │ ├── delete(_:deleteifempty:)-5j8qh │ │ └── index.html │ ├── deleting(_:deleteifempty:) │ │ └── index.html │ ├── description │ │ └── index.html │ ├── dictionary(_:) │ │ └── index.html │ ├── dictionary(of:) │ │ └── index.html │ ├── dictionary │ │ └── index.html │ ├── dictionaryvalue │ │ └── index.html │ ├── double(_:) │ │ └── index.html │ ├── double │ │ └── index.html │ ├── encodable-implementations │ │ └── index.html │ ├── encode(to:) │ │ └── index.html │ ├── equatable-implementations │ │ └── index.html │ ├── expressiblebyarrayliteral-implementations │ │ └── index.html │ ├── expressiblebybooleanliteral-implementations │ │ └── index.html │ ├── expressiblebydictionaryliteral-implementations │ │ └── index.html │ ├── expressiblebyextendedgraphemeclusterliteral-implementations │ │ └── index.html │ ├── expressiblebyfloatliteral-implementations │ │ └── index.html │ ├── expressiblebyintegerliteral-implementations │ │ └── index.html │ ├── expressiblebystringliteral-implementations │ │ └── index.html │ ├── expressiblebyunicodescalarliteral-implementations │ │ └── index.html │ ├── get(_:) │ │ └── index.html │ ├── index.html │ ├── init(arrayliteral:) │ │ └── index.html │ ├── init(booleanliteral:) │ │ └── index.html │ ├── init(dictionaryliteral:) │ │ └── index.html │ ├── init(extendedgraphemeclusterliteral:) │ │ └── index.html │ ├── init(floatliteral:) │ │ └── index.html │ ├── init(from:) │ │ └── index.html │ ├── init(integerliteral:) │ │ └── index.html │ ├── init(stringliteral:) │ │ └── index.html │ ├── init(unicodescalarliteral:) │ │ └── index.html │ ├── init(value:) │ │ └── index.html │ ├── init(value:name:) │ │ └── index.html │ ├── int(_:) │ │ └── index.html │ ├── int │ │ └── index.html │ ├── isgroup │ │ └── index.html │ ├── issingle │ │ └── index.html │ ├── listpaths(startingat:) │ │ └── index.html │ ├── listpaths(startingat:filter:) │ │ └── index.html │ ├── pathexplorer-implementations │ │ └── index.html │ ├── real │ │ └── index.html │ ├── set(_:keynameto:)-71khn │ │ └── index.html │ ├── set(_:keynameto:)-7cmde │ │ └── index.html │ ├── set(_:keynameto:)-9elrr │ │ └── index.html │ ├── set(_:to:)-1osuj │ │ └── index.html │ ├── set(_:to:)-1p08w │ │ └── index.html │ ├── set(_:to:)-85z1n │ │ └── index.html │ ├── set(_:to:)-neu9 │ │ └── index.html │ ├── setting(_:keynameto:) │ │ └── index.html │ ├── setting(_:to:) │ │ └── index.html │ ├── string(_:) │ │ └── index.html │ └── string │ │ └── index.html │ ├── explorervalueconvertible │ └── index.html │ ├── explorervaluecreatable │ ├── index.html │ ├── init(from:)-2m6tw │ │ └── index.html │ └── init(from:)-7khyl │ │ └── index.html │ ├── explorervaluerepresentable │ ├── explorervalue()-1gz0u │ │ └── index.html │ ├── explorervalue()-9wvc3 │ │ └── index.html │ └── index.html │ ├── explorerxml │ ├── add(_:at:)-1bcbx │ │ └── index.html │ ├── add(_:at:)-1pzz6 │ │ └── index.html │ ├── add(_:at:)-1vd0k │ │ └── index.html │ ├── add(_:at:)-4t6ia │ │ └── index.html │ ├── add(_:at:)-4y7o0 │ │ └── index.html │ ├── add(_:at:)-5c99x │ │ └── index.html │ ├── adding(_:at:)-1pus │ │ └── index.html │ ├── adding(_:at:)-3bl3a │ │ └── index.html │ ├── adding(_:at:)-4y55p │ │ └── index.html │ ├── adding(_:at:)-5hn92 │ │ └── index.html │ ├── adding(_:at:)-9e3bi │ │ └── index.html │ ├── adding(_:at:)-cwm8 │ │ └── index.html │ ├── array(of:) │ │ └── index.html │ ├── array(of:keepingattributes:singlechildstrategy:) │ │ └── index.html │ ├── bool │ │ └── index.html │ ├── data │ │ └── index.html │ ├── date │ │ └── index.html │ ├── debugdescription │ │ └── index.html │ ├── delete(_:) │ │ └── index.html │ ├── delete(_:deleteifempty:)-3fqmj │ │ └── index.html │ ├── delete(_:deleteifempty:)-9oiah │ │ └── index.html │ ├── delete(_:deleteifempty:)-9pz8 │ │ └── index.html │ ├── deleting(_:deleteifempty:) │ │ └── index.html │ ├── description │ │ └── index.html │ ├── dictionary(of:) │ │ └── index.html │ ├── dictionary(of:keepingattributes:singlechildstrategy:) │ │ └── index.html │ ├── double │ │ └── index.html │ ├── element │ │ └── index.html │ ├── explorervalue(keepingattributes:singlechildstrategy:) │ │ └── index.html │ ├── exportcsv() │ │ └── index.html │ ├── exportcsv(separator:) │ │ └── index.html │ ├── exportdata() │ │ └── index.html │ ├── exportdata(to:) │ │ └── index.html │ ├── exportdata(to:rootname:) │ │ └── index.html │ ├── exportfoldedstring(upto:) │ │ └── index.html │ ├── exportstring() │ │ └── index.html │ ├── exportstring(to:) │ │ └── index.html │ ├── exportstring(to:rootname:) │ │ └── index.html │ ├── expressiblebyextendedgraphemeclusterliteral-implementations │ │ └── index.html │ ├── expressiblebyunicodescalarliteral-implementations │ │ └── index.html │ ├── folded(upto:) │ │ └── index.html │ ├── format │ │ └── index.html │ ├── fromcsv(string:separator:hasheaders:) │ │ └── index.html │ ├── get(_:) │ │ └── index.html │ ├── index.html │ ├── init(booleanliteral:) │ │ └── index.html │ ├── init(data:) │ │ └── index.html │ ├── init(extendedgraphemeclusterliteral:) │ │ └── index.html │ ├── init(floatliteral:) │ │ └── index.html │ ├── init(integerliteral:) │ │ └── index.html │ ├── init(stringliteral:) │ │ └── index.html │ ├── init(unicodescalarliteral:) │ │ └── index.html │ ├── init(value:) │ │ └── index.html │ ├── init(value:name:) │ │ └── index.html │ ├── int │ │ └── index.html │ ├── isgroup │ │ └── index.html │ ├── issingle │ │ └── index.html │ ├── listpaths(startingat:) │ │ └── index.html │ ├── listpaths(startingat:filter:) │ │ └── index.html │ ├── pathexplorer-implementations │ │ └── index.html │ ├── real │ │ └── index.html │ ├── serializablepathexplorer-implementations │ │ └── index.html │ ├── set(_:keynameto:)-1bi3d │ │ └── index.html │ ├── set(_:keynameto:)-3whe6 │ │ └── index.html │ ├── set(_:keynameto:)-8bycm │ │ └── index.html │ ├── set(_:to:)-2wq5w │ │ └── index.html │ ├── set(_:to:)-3d1tv │ │ └── index.html │ ├── set(_:to:)-45huy │ │ └── index.html │ ├── set(_:to:)-54j6g │ │ └── index.html │ ├── set(_:to:)-8wtzf │ │ └── index.html │ ├── set(_:to:)-ofo9 │ │ └── index.html │ ├── setting(_:keynameto:) │ │ └── index.html │ ├── setting(_:to:)-1eczh │ │ └── index.html │ ├── setting(_:to:)-2pw3q │ │ └── index.html │ ├── setting(_:to:)-4m6ll │ │ └── index.html │ ├── setting(_:to:)-4xlv9 │ │ └── index.html │ ├── setting(_:to:)-5h22p │ │ └── index.html │ ├── setting(_:to:)-7elcu │ │ └── index.html │ ├── singlechildstrategy │ │ ├── array │ │ │ └── index.html │ │ ├── custom(_:) │ │ │ └── index.html │ │ ├── default │ │ │ └── index.html │ │ ├── dictionary │ │ │ └── index.html │ │ ├── index.html │ │ └── transform │ │ │ └── index.html │ └── string │ │ └── index.html │ ├── getting-started │ └── index.html │ ├── index.html │ ├── mastering-paths │ └── index.html │ ├── new-4.0.0 │ └── index.html │ ├── path │ ├── !=(_:_:) │ │ └── index.html │ ├── +(_:_:)-1mpyt │ │ └── index.html │ ├── +(_:_:)-4knou │ │ └── index.html │ ├── +(_:_:)-wurs │ │ └── index.html │ ├── +=(_:_:) │ │ └── index.html │ ├── allsatisfy(_:) │ │ └── index.html │ ├── append(_:)-6mddf │ │ └── index.html │ ├── append(_:)-9l194 │ │ └── index.html │ ├── append(contentsof:) │ │ └── index.html │ ├── appending(_:)-2ptn6 │ │ └── index.html │ ├── appending(_:)-3mvwq │ │ └── index.html │ ├── applying(_:) │ │ └── index.html │ ├── arrayliteralelement │ │ └── index.html │ ├── bidirectionalcollection-implementations │ │ └── index.html │ ├── collection-implementations │ │ └── index.html │ ├── commonprefix(with:) │ │ └── index.html │ ├── compactmap(_:) │ │ └── index.html │ ├── compactmapfilter │ │ └── index.html │ ├── compactmapindexes │ │ └── index.html │ ├── compactmapkeys │ │ └── index.html │ ├── compactmapslices │ │ └── index.html │ ├── compare(_:_:) │ │ └── index.html │ ├── comparedbykeyandindexes(with:) │ │ └── index.html │ ├── contains(_:) │ │ └── index.html │ ├── contains(where:) │ │ └── index.html │ ├── count │ │ └── index.html │ ├── debugdescription │ │ └── index.html │ ├── defaultseparator │ │ └── index.html │ ├── description │ │ └── index.html │ ├── difference(from:) │ │ └── index.html │ ├── difference(from:by:) │ │ └── index.html │ ├── drop(while:) │ │ └── index.html │ ├── dropfirst(_:) │ │ └── index.html │ ├── droplast(_:) │ │ └── index.html │ ├── elementsequal(_:) │ │ └── index.html │ ├── elementsequal(_:by:) │ │ └── index.html │ ├── empty │ │ └── index.html │ ├── endindex │ │ └── index.html │ ├── enumerated() │ │ └── index.html │ ├── equatable-implementations │ │ └── index.html │ ├── expressiblebyarrayliteral-implementations │ │ └── index.html │ ├── filter(_:) │ │ └── index.html │ ├── first(where:) │ │ └── index.html │ ├── first │ │ └── index.html │ ├── firstindex(of:) │ │ └── index.html │ ├── firstindex(where:) │ │ └── index.html │ ├── firstrange(of:) │ │ └── index.html │ ├── flatmap(_:)-4dfav │ │ └── index.html │ ├── flatmap(_:)-658d │ │ └── index.html │ ├── flattened() │ │ └── index.html │ ├── foreach(_:) │ │ └── index.html │ ├── formatted(_:) │ │ └── index.html │ ├── formindex(_:offsetby:) │ │ └── index.html │ ├── formindex(_:offsetby:limitedby:) │ │ └── index.html │ ├── formindex(after:) │ │ └── index.html │ ├── formindex(before:) │ │ └── index.html │ ├── index(_:offsetby:limitedby:) │ │ └── index.html │ ├── index(after:) │ │ └── index.html │ ├── index(of:) │ │ └── index.html │ ├── index.html │ ├── init() │ │ └── index.html │ ├── init(_:)-1b2iy │ │ └── index.html │ ├── init(_:)-3ayg2 │ │ └── index.html │ ├── init(_:)-cgb7 │ │ └── index.html │ ├── init(arrayliteral:) │ │ └── index.html │ ├── init(elements:)-8dch4 │ │ └── index.html │ ├── init(elements:)-9i64v │ │ └── index.html │ ├── init(repeating:count:) │ │ └── index.html │ ├── init(string:separator:) │ │ └── index.html │ ├── insert(_:at:) │ │ └── index.html │ ├── insert(contentsof:at:) │ │ └── index.html │ ├── isempty │ │ └── index.html │ ├── last(where:) │ │ └── index.html │ ├── last │ │ └── index.html │ ├── lastindex(of:) │ │ └── index.html │ ├── lastindex(where:) │ │ └── index.html │ ├── lazy │ │ └── index.html │ ├── lexicographicallyprecedes(_:by:) │ │ └── index.html │ ├── makeiterator() │ │ └── index.html │ ├── map(_:)-1pyvn │ │ └── index.html │ ├── map(_:)-3bvvx │ │ └── index.html │ ├── max(by:) │ │ └── index.html │ ├── min(by:) │ │ └── index.html │ ├── mutablecollection-implementations │ │ └── index.html │ ├── parser(separator:keyforbiddencharacters:) │ │ └── index.html │ ├── partition(by:)-5mp72 │ │ └── index.html │ ├── partition(by:)-70krf │ │ └── index.html │ ├── poplast() │ │ └── index.html │ ├── prefix(_:) │ │ └── index.html │ ├── prefix(through:) │ │ └── index.html │ ├── prefix(upto:) │ │ └── index.html │ ├── prefix(while:) │ │ └── index.html │ ├── publisher │ │ └── index.html │ ├── randomaccesscollection-implementations │ │ └── index.html │ ├── randomelement() │ │ └── index.html │ ├── randomelement(using:) │ │ └── index.html │ ├── rangereplaceablecollection-implementations │ │ └── index.html │ ├── ranges(of:) │ │ └── index.html │ ├── reduce(_:_:) │ │ └── index.html │ ├── reduce(into:_:) │ │ └── index.html │ ├── remove(at:) │ │ └── index.html │ ├── removeall(keepingcapacity:) │ │ └── index.html │ ├── removeall(where:)-13bwz │ │ └── index.html │ ├── removeall(where:)-6oyg2 │ │ └── index.html │ ├── removefirst() │ │ └── index.html │ ├── removefirst(_:) │ │ └── index.html │ ├── removelast() │ │ └── index.html │ ├── removelast(_:) │ │ └── index.html │ ├── removesubrange(_:)-28mkd │ │ └── index.html │ ├── removesubrange(_:)-3w6oh │ │ └── index.html │ ├── replace(_:with:maxreplacements:) │ │ └── index.html │ ├── replacesubrange(_:with:)-69vd1 │ │ └── index.html │ ├── replacesubrange(_:with:)-8jwu3 │ │ └── index.html │ ├── replacesubrange(_:with:)-8v4n8 │ │ └── index.html │ ├── replacing(_:with:maxreplacements:) │ │ └── index.html │ ├── replacing(_:with:subrange:maxreplacements:) │ │ └── index.html │ ├── reservecapacity(_:) │ │ └── index.html │ ├── reverse() │ │ └── index.html │ ├── reversed() │ │ └── index.html │ ├── sequence-implementations │ │ └── index.html │ ├── shuffle() │ │ └── index.html │ ├── shuffle(using:) │ │ └── index.html │ ├── shuffled() │ │ └── index.html │ ├── shuffled(using:) │ │ └── index.html │ ├── sort(by:) │ │ └── index.html │ ├── sort(using:)-20eip │ │ └── index.html │ ├── sort(using:)-7hq1j │ │ └── index.html │ ├── sorted(by:) │ │ └── index.html │ ├── sorted(using:)-1q9xt │ │ └── index.html │ ├── sorted(using:)-2epe7 │ │ └── index.html │ ├── split(maxsplits:omittingemptysubsequences:whereseparator:) │ │ └── index.html │ ├── split(separator:maxsplits:omittingemptysubsequences:) │ │ └── index.html │ ├── startindex │ │ └── index.html │ ├── starts(with:) │ │ └── index.html │ ├── starts(with:by:) │ │ └── index.html │ ├── subscript(_:) │ │ └── index.html │ ├── suffix(_:) │ │ └── index.html │ ├── suffix(from:) │ │ └── index.html │ ├── swapat(_:_:) │ │ └── index.html │ ├── trimmingprefix(_:) │ │ └── index.html │ ├── trimmingprefix(while:) │ │ └── index.html │ ├── trimprefix(_:) │ │ └── index.html │ ├── trimprefix(while:) │ │ └── index.html │ ├── underestimatedcount │ │ └── index.html │ ├── withcontiguousmutablestorageifavailable(_:) │ │ └── index.html │ └── withcontiguousstorageifavailable(_:) │ │ └── index.html │ ├── pathelement │ ├── !=(_:_:) │ │ └── index.html │ ├── count │ │ └── index.html │ ├── customstringconvertible-implementations │ │ └── index.html │ ├── description │ │ └── index.html │ ├── equatable-implementations │ │ └── index.html │ ├── expressiblebyextendedgraphemeclusterliteral-implementations │ │ └── index.html │ ├── expressiblebyintegerliteral-implementations │ │ └── index.html │ ├── expressiblebystringliteral-implementations │ │ └── index.html │ ├── expressiblebyunicodescalarliteral-implementations │ │ └── index.html │ ├── filter(_:) │ │ └── index.html │ ├── index(_:) │ │ └── index.html │ ├── index.html │ ├── init(extendedgraphemeclusterliteral:) │ │ └── index.html │ ├── init(integerliteral:) │ │ └── index.html │ ├── init(stringliteral:) │ │ └── index.html │ ├── init(unicodescalarliteral:) │ │ └── index.html │ ├── integerliteraltype │ │ └── index.html │ ├── key(_:) │ │ └── index.html │ ├── keyslist │ │ └── index.html │ ├── pathelementrepresentable-implementations │ │ └── index.html │ ├── pathvalue │ │ └── index.html │ ├── slice(_:) │ │ └── index.html │ ├── slice(_:_:) │ │ └── index.html │ └── stringliteraltype │ │ └── index.html │ ├── pathelementrepresentable │ ├── index.html │ └── pathvalue │ │ └── index.html │ ├── pathexplorer │ ├── add(_:at:)-2kii6 │ │ └── index.html │ ├── add(_:at:)-2zxor │ │ └── index.html │ ├── add(_:at:)-6wo3i │ │ └── index.html │ ├── add(_:at:)-861h4 │ │ └── index.html │ ├── adding(_:at:)-4ju9b │ │ └── index.html │ ├── adding(_:at:)-5uv86 │ │ └── index.html │ ├── adding(_:at:)-68mxp │ │ └── index.html │ ├── adding(_:at:)-7fd9c │ │ └── index.html │ ├── array(of:) │ │ └── index.html │ ├── bool │ │ └── index.html │ ├── data │ │ └── index.html │ ├── date │ │ └── index.html │ ├── delete(_:) │ │ └── index.html │ ├── delete(_:deleteifempty:)-2uxwq │ │ └── index.html │ ├── delete(_:deleteifempty:)-40w9g │ │ └── index.html │ ├── delete(_:deleteifempty:)-g45f │ │ └── index.html │ ├── deleting(_:deleteifempty:)-1byw9 │ │ └── index.html │ ├── deleting(_:deleteifempty:)-2u4ud │ │ └── index.html │ ├── deleting(_:deleteifempty:)-32ufs │ │ └── index.html │ ├── dictionary(of:) │ │ └── index.html │ ├── double │ │ └── index.html │ ├── get(_:)-2ghf1 │ │ └── index.html │ ├── get(_:)-6pa9h │ │ └── index.html │ ├── get(_:)-8vyte │ │ └── index.html │ ├── index.html │ ├── init(value:) │ │ └── index.html │ ├── init(value:name:) │ │ └── index.html │ ├── int │ │ └── index.html │ ├── isgroup │ │ └── index.html │ ├── issingle │ │ └── index.html │ ├── listpaths(startingat:) │ │ └── index.html │ ├── listpaths(startingat:filter:)-4tkeq │ │ └── index.html │ ├── listpaths(startingat:filter:)-8y0x2 │ │ └── index.html │ ├── real │ │ └── index.html │ ├── set(_:keynameto:)-1zwfv │ │ └── index.html │ ├── set(_:keynameto:)-5j60r │ │ └── index.html │ ├── set(_:keynameto:)-9i6hd │ │ └── index.html │ ├── set(_:to:)-376n0 │ │ └── index.html │ ├── set(_:to:)-5fgny │ │ └── index.html │ ├── set(_:to:)-6yk0i │ │ └── index.html │ ├── set(_:to:)-9d877 │ │ └── index.html │ ├── setting(_:keynameto:)-1fmyp │ │ └── index.html │ ├── setting(_:keynameto:)-1vrh │ │ └── index.html │ ├── setting(_:keynameto:)-7ar89 │ │ └── index.html │ ├── setting(_:to:)-5tdzy │ │ └── index.html │ ├── setting(_:to:)-7q3g │ │ └── index.html │ ├── setting(_:to:)-9vtr8 │ │ └── index.html │ ├── setting(_:to:)-n2ij │ │ └── index.html │ └── string │ │ └── index.html │ ├── pathexplorers │ ├── index.html │ ├── json │ │ └── index.html │ ├── plist │ │ └── index.html │ ├── xml │ │ └── index.html │ └── yaml │ │ └── index.html │ ├── paths-listing │ └── index.html │ ├── pathsfilter │ ├── expressionpredicate │ │ ├── evaluate(with:) │ │ │ └── index.html │ │ ├── index.html │ │ └── init(format:) │ │ │ └── index.html │ ├── functionpredicate │ │ ├── evaluate(with:) │ │ │ └── index.html │ │ ├── evaluation-swift.property │ │ │ └── index.html │ │ ├── evaluation-swift.typealias │ │ │ └── index.html │ │ ├── index.html │ │ └── init(evaluation:) │ │ │ └── index.html │ ├── index.html │ ├── key(pattern:target:) │ │ └── index.html │ ├── key(regex:) │ │ └── index.html │ ├── key(regex:target:) │ │ └── index.html │ ├── keyandvalue(keyregex:valuepredicate:) │ │ └── index.html │ ├── keyandvalue(keyregex:valuepredicates:) │ │ └── index.html │ ├── keyandvalue(keyregex:valuepredicates:_:) │ │ └── index.html │ ├── keyandvalue(pattern:valuepredicate:) │ │ └── index.html │ ├── keyandvalue(pattern:valuepredicatesformat:_:) │ │ └── index.html │ ├── nofilter │ │ └── index.html │ ├── targetonly(_:) │ │ └── index.html │ ├── value(_:) │ │ └── index.html │ ├── value(_:_:)-2wxh0 │ │ └── index.html │ ├── value(_:_:)-8tfx1 │ │ └── index.html │ └── valuetarget │ │ ├── !=(_:_:) │ │ └── index.html │ │ ├── equatable-implementations │ │ └── index.html │ │ ├── group │ │ └── index.html │ │ ├── hash(into:) │ │ └── index.html │ │ ├── hashvalue │ │ └── index.html │ │ ├── index.html │ │ ├── init(rawvalue:) │ │ └── index.html │ │ ├── rawrepresentable-implementations │ │ └── index.html │ │ ├── single │ │ └── index.html │ │ └── singleandgroup │ │ └── index.html │ ├── serializablepathexplorer │ ├── exportcsv() │ │ └── index.html │ ├── exportcsv(separator:) │ │ └── index.html │ ├── exportdata() │ │ └── index.html │ ├── exportdata(to:) │ │ └── index.html │ ├── exportdata(to:rootname:) │ │ └── index.html │ ├── exportfoldedstring(upto:) │ │ └── index.html │ ├── exportstring() │ │ └── index.html │ ├── exportstring(to:) │ │ └── index.html │ ├── exportstring(to:rootname:) │ │ └── index.html │ ├── folded(upto:) │ │ └── index.html │ ├── format │ │ └── index.html │ ├── fromcsv(string:separator:hasheaders:) │ │ └── index.html │ ├── index.html │ └── init(data:) │ │ └── index.html │ ├── serializationerror │ ├── datatostring │ │ └── index.html │ ├── error-implementations │ │ └── index.html │ ├── errordescription │ │ └── index.html │ ├── failurereason │ │ └── index.html │ ├── helpanchor │ │ └── index.html │ ├── index.html │ ├── localizeddescription │ │ └── index.html │ ├── localizederror-implementations │ │ └── index.html │ ├── notcsvexportable(description:) │ │ └── index.html │ ├── recoverysuggestion │ │ └── index.html │ └── stringtodata │ │ └── index.html │ └── valuepredicate │ ├── evaluate(with:) │ └── index.html │ └── index.html ├── favicon.ico ├── favicon.svg ├── img ├── added-icon.d6f7e47d.svg ├── deprecated-icon.015b4f17.svg ├── modified-icon.f496e73d.svg └── no-image@2x.df2a0a50.png ├── index.html ├── index └── index.json ├── js ├── chunk-2d0d3105.cd72cc8e.js ├── chunk-c0335d80.76a68cc5.js ├── chunk-vendors.ba2dd0cb.js ├── documentation-topic.57e91f8a.js ├── documentation-topic~topic.1679ec90.js ├── documentation-topic~topic~tutorials-overview.90c61522.js ├── highlight-js-bash.1b52852f.js ├── highlight-js-c.d1db3f17.js ├── highlight-js-cpp.eaddddbe.js ├── highlight-js-css.75eab1fe.js ├── highlight-js-custom-markdown.7cffc4b3.js ├── highlight-js-custom-swift.5cda5c20.js ├── highlight-js-diff.62d66733.js ├── highlight-js-http.163e45b6.js ├── highlight-js-java.8326d9d8.js ├── highlight-js-javascript.acb8a8eb.js ├── highlight-js-json.471128d2.js ├── highlight-js-llvm.6100b125.js ├── highlight-js-markdown.90077643.js ├── highlight-js-objectivec.bcdf5156.js ├── highlight-js-perl.757d7b6f.js ├── highlight-js-php.cc8d6c27.js ├── highlight-js-python.c214ed92.js ├── highlight-js-ruby.f889d392.js ├── highlight-js-scss.62ee18da.js ├── highlight-js-shell.dd7f411f.js ├── highlight-js-swift.84f3e88c.js ├── highlight-js-xml.9c3688c7.js ├── index.e8a5d294.js ├── topic.8cd0c0c4.js └── tutorials-overview.2a32cd6f.js └── metadata.json /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | :warning: 2 | 3 | New issue checklist: 4 | 5 | - [ ] Issue tracker does not already contain the same (or a very similar) issue 6 | - [ ] Title must be clear about what is the issue 7 | - [ ] All relevant fields of the description are filled 8 | - [ ] Issue is following the [CODE OF CONDUCT](https://github.com/ABridoux/scout/blob/master/CODE_OF_CONDUCT.md) 9 | 10 | **Please delete this section once you're ready to finally create the issue.** 11 | 12 | :warning: 13 | 14 | # Short description 15 | 16 | _Please fill this section with a short description of your issue / new feature._ 17 | 18 | --- 19 | 20 | **If the ticket is about an issue, use the following sections to give more details about the issue you're facing.** 21 | 22 | ### Expected outcome 23 | 24 | _Please fill this section with a description of what you're expecting to happen._ 25 | 26 | ### Actual outcome 27 | 28 | _Please fill the following section with a description of what is actually happening. Please add as much information as you can (how easy it is to reproduce, steps, etc.)._ 29 | 30 | --- 31 | 32 | **If the ticket is about a new feature, use the following sections to give more details about the changes you ask for / want to implement.** 33 | 34 | ### Missing functionnality 35 | 36 | _Please fill this section with a description of what's missing for you._ 37 | 38 | ### Implementation 39 | 40 | _Please fill this section with details of the implementation you expect or plan to do._ 41 | 42 | ## Miscellaneous 43 | 44 | | Information | Value | 45 | | ---------------- | ---------------- | 46 | | Scout version | e.g. 1.0.0 | 47 | | Platform | e.g. macOS/linux | 48 | | Platform version | e.g. 9.0 | 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug with details 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Current behavior** 20 | What actually happened 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. *I'm always frustrated when [...]* 12 | 13 | **Describe your idea briefly.** 14 | A general idea of the new feature the program/library could offer. 15 | 16 | **Describe the solution you'd like** 17 | A clear and concise description of what you want to happen. Don't hesitate to give examples of possible usage. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | *Please fill this section with information related to the changes / fixes you introduced.* 4 | 5 | ## Miscellaneous 6 | 7 | *Please fill this section with anything else that can be relevant to the review of your pull request (benchmarks, blogs, StackOverflow threads, etc.).* 8 | -------------------------------------------------------------------------------- /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | name: Swift 2 | 3 | on: [push, pull_request] 4 | 5 | 6 | jobs: 7 | build_and_test: 8 | runs-on: macos-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build 13 | run: xcodebuild -scheme Scout 14 | - name: Run tests 15 | run: xcodebuild test -scheme Scout 16 | - name: Code coverage 17 | run: bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.2 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Sources 3 | - Tests 4 | 5 | disabled_rules: 6 | - xctfail_message 7 | line_length: 200 8 | identifier_name: 9 | # identifiers like id 10 | min_length: 2 11 | max_length: 50 12 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDETemplateMacros.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FILEHEADER 6 | 7 | // Scout 8 | // Copyright (c) 2020-present Alexis Bridoux 9 | // MIT license, see LICENSE file for details 10 | 11 | 12 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Highlight-presets/Colors-Homebrew.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | json 6 | 7 | keyName 8 | 187 9 | 10 | plist 11 | 12 | keyName 13 | 187 14 | tag 15 | 245 16 | header 17 | 239 18 | 19 | xml 20 | 21 | openingTag 22 | 187 23 | header 24 | 239 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Highlight-presets/Colors-Novel.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | json 6 | 7 | keyName 8 | 168 9 | punctuation 10 | 247 11 | 12 | plist 13 | 14 | keyName 15 | 168 16 | tag 17 | 247 18 | header 19 | 138 20 | 21 | xml 22 | 23 | openingTag 24 | 168 25 | header 26 | 138 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Highlight-presets/Colors-Ocean.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | json 6 | 7 | keyName 8 | 113 9 | punctuation 10 | 66 11 | 12 | plist 13 | 14 | keyName 15 | 113 16 | tag 17 | 68 18 | header 19 | 25 20 | 21 | xml 22 | 23 | openingTag 24 | 168 25 | header 26 | 138 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Highlight-presets/README.md: -------------------------------------------------------------------------------- 1 | # Highlight presets 2 | 3 | Those files are highlight colors presets for **Scout**. I tried to make them useful for some macOS terminal default styles. 4 | 5 | To use a preset, download it and put it in the folder *~/.scout/*. Then change its name to *Colors.plist*. You can find more information about how to customise highlight colors [here](https://github.com/ABridoux/scout/wiki/%5B30%5D-Syntax-highlighting:-custom-colors). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2020] Alexis Bridoux 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Playground/People.json: -------------------------------------------------------------------------------- 1 | { 2 | "Tom" : { 3 | "age" : 68, 4 | "hobbies" : [ 5 | "cooking", 6 | "guitar" 7 | ], 8 | "height" : 175 9 | }, 10 | "Robert" : { 11 | "age" : 23, 12 | "hobbies" : [ 13 | "video games", 14 | "party", 15 | "tennis" 16 | ], 17 | "running_records" : [ 18 | [ 19 | 10, 20 | 12, 21 | 9, 22 | 10 23 | ], 24 | [ 25 | 9, 26 | 12, 27 | 11 28 | ] 29 | ], 30 | "height" : 181 31 | }, 32 | "Suzanne" : { 33 | "job" : "actress", 34 | "movies" : [ 35 | { 36 | "title" : "Tomorrow is so far", 37 | "awards" : "Best speech for a silent movie" 38 | }, 39 | { 40 | "title" : "Yesterday will never go", 41 | "awards" : "Best title" 42 | }, 43 | { 44 | "title" : "What about today?" 45 | } 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Playground/People.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Robert 6 | 7 | age 8 | 23 9 | height 10 | 181 11 | hobbies 12 | 13 | video games 14 | party 15 | tennis 16 | 17 | running_records 18 | 19 | 20 | 10 21 | 12 22 | 9 23 | 10 24 | 25 | 26 | 9 27 | 12 28 | 11 29 | 30 | 31 | 32 | Suzanne 33 | 34 | job 35 | actress 36 | movies 37 | 38 | 39 | awards 40 | Best speech for a silent movie 41 | title 42 | Tomorrow is so far 43 | 44 | 45 | awards 46 | Best title 47 | title 48 | Yesterday will never go 49 | 50 | 51 | title 52 | What about today? 53 | 54 | 55 | 56 | Tom 57 | 58 | age 59 | 68 60 | height 61 | 175 62 | hobbies 63 | 64 | cooking 65 | guitar 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Playground/People.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 175 5 | 68 6 | 7 | cooking 8 | guitar 9 | 10 | 11 | 12 | 13 | 181 14 | 23 15 | 16 | video games 17 | party 18 | tennis 19 | 20 | 21 | 22 | 10 23 | 12 24 | 9 25 | 10 26 | 27 | 28 | 9 29 | 12 30 | 11 31 | 32 | 33 | 34 | 35 | 36 | actress 37 | 38 | 39 | Tomorrow is so far 40 | Best speech for a silent movie 41 | 42 | 43 | Yesterday will never go 44 | Best title 45 | 46 | 47 | What about today? 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Playground/People.yml: -------------------------------------------------------------------------------- 1 | Robert: 2 | age: 23 3 | height: 181 4 | hobbies: 5 | - video games 6 | - party 7 | - tennis 8 | running_records: 9 | - - 10 10 | - 12 11 | - 9 12 | - 10 13 | - - 9 14 | - 12 15 | - 11 16 | Suzanne: 17 | job: actress 18 | movies: 19 | - awards: Best speech for a silent movie 20 | title: Tomorrow is so far 21 | - awards: Best title 22 | title: Yesterday will never go 23 | - title: What about today? 24 | Tom: 25 | age: 68 26 | height: 175 27 | hobbies: 28 | - cooking 29 | - guitar 30 | 31 | -------------------------------------------------------------------------------- /Resources/scout-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/Resources/scout-logo.png -------------------------------------------------------------------------------- /Resources/syntax-highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/Resources/syntax-highlight.png -------------------------------------------------------------------------------- /Resources/syntax-highlighting-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/Resources/syntax-highlighting-2.png -------------------------------------------------------------------------------- /Sources/Parsing/Character+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Character { 9 | 10 | var isDecimalDigit: Bool { 11 | let zero: Character = "0" 12 | let nine: Character = "9" 13 | return (zero...nine).contains(self) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Parsing/Parser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | /// Parse a string to an array of `PathElement`s 9 | /// 10 | /// - note: Inspired from [functional Swift](https://www.objc.io/books/functional-swift/) 11 | /// *Parser Combinators* chapter 12 | public struct Parser { 13 | let parse: (Substring) -> (R, Substring)? 14 | 15 | public init(parse: @escaping (Substring) -> (R, Substring)?) { 16 | self.parse = parse 17 | } 18 | } 19 | 20 | public extension Parser { 21 | 22 | func run(_ string: String) -> (result: R, remainder: String)? { 23 | guard let (result, remainder) = parse(Substring(string)) else { return nil } 24 | return (result, String(remainder)) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Scout/Constants/DataFormat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | /// Unique identifier of a data format. 7 | public enum DataFormat: String, CaseIterable { 8 | case json 9 | case plist 10 | case xml 11 | case yaml 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Scout/Constants/Folding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - Folding 7 | 8 | enum Folding { 9 | 10 | /// Used to name the single key when folding a dictionary 11 | static let foldedKey = "Folded" 12 | 13 | /// Used to replace the content of a dictionary or array when folding it 14 | static let foldedMark = "~~SCOUT_FOLDED~~" 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Scout/Constants/ScoutVersion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - ScoutVersion 7 | 8 | public enum ScoutVersion { 9 | public static let current = "4.1.0" 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValue/CSV/ExplorerValue+CSVImport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import SwiftCSV 8 | 9 | // MARK: - CSV import 10 | 11 | extension ExplorerValue { 12 | 13 | private typealias Tree = PathTree 14 | 15 | static func fromCSV(string: String, separator: Character, hasHeaders: Bool) throws -> ExplorerValue { 16 | let csv = try CSV(string: string, delimiter: separator, loadColumns: hasHeaders) 17 | return try from(csv: csv, headers: hasHeaders) 18 | } 19 | 20 | private static func from(csv: CSV, headers: Bool) throws -> ExplorerValue { 21 | if headers { 22 | return try fromArrayOfDictionaries(csv: csv) 23 | } else if csv.enumeratedRows.count == 1 { 24 | return .array(csv.enumeratedRows[0].map(ExplorerValue.singleFrom)) 25 | } else { 26 | return array <^> ([csv.header] + csv.enumeratedRows).map { array <^> $0.map(ExplorerValue.singleFrom) } 27 | } 28 | } 29 | 30 | private static func fromArrayOfDictionaries(csv: CSV) throws -> ExplorerValue { 31 | let rootTree = Tree.root() 32 | let headers = try csv.header 33 | .map { try (key: $0, path: Path(string: $0)) } // transform keys to paths 34 | .sorted { $0.path.comparedByKeyAndIndexes(with: $1.path) } // sort by path 35 | .map { ($0.key, rootTree.insert(path: $0.path)) } // insert paths in the PathTree 36 | 37 | let dicts = try csv.namedRows.compactMap { row -> ExplorerValue? in 38 | try from(row: row, with: headers, rootTree: rootTree) 39 | } 40 | 41 | return .array(dicts) 42 | } 43 | 44 | private static func from(row: [String: String], with keysTrees: [(key: String, path: Tree)], rootTree: Tree) throws -> ExplorerValue? { 45 | keysTrees.forEach { (key, tree) in 46 | if let value = row[key] { 47 | tree.value = .leaf(value: .singleFrom(string: value)) 48 | } else { 49 | tree.value = .leaf(value: nil) 50 | } 51 | } 52 | 53 | return try ExplorerValue.newValue(exploring: rootTree) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValue/ExplorerValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - ExplorerValue 9 | 10 | /// The values a `PathExplorer` can take 11 | public enum ExplorerValue: Sendable { 12 | 13 | // single 14 | case int(Int) 15 | case double(Double) 16 | case string(String) 17 | case bool(Bool) 18 | case data(Data) 19 | case date(Date) 20 | 21 | // group 22 | case array(ArrayValue) 23 | case dictionary(DictionaryValue) 24 | } 25 | 26 | // MARK: - Type aliases 27 | 28 | extension ExplorerValue { 29 | 30 | public typealias ArrayValue = [ExplorerValue] 31 | public typealias DictionaryValue = [String: ExplorerValue] 32 | typealias SlicePath = Slice 33 | } 34 | 35 | // MARK: - Hashable 36 | 37 | extension ExplorerValue: Hashable {} 38 | 39 | // MARK: - Special init 40 | 41 | extension ExplorerValue { 42 | 43 | init(value: Any) throws { 44 | if let int = value as? Int { 45 | self = .int(int) 46 | } else if let double = value as? Double { 47 | self = .double(double) 48 | } else if let string = value as? String { 49 | self = .string(string) 50 | } else if let bool = value as? Bool { 51 | self = .bool(bool) 52 | } else if let data = value as? Data { 53 | self = .data(data) 54 | } else if let date = value as? Date { 55 | self = .date(date) 56 | } else if let dict = value as? [String: Any] { 57 | self = try .dictionary(dict.mapValues { try ExplorerValue(value: $0) }) 58 | } else if let array = value as? [Any] { 59 | self = try .array(array.map { try ExplorerValue(value: $0) }) 60 | } else { 61 | throw ExplorerError.invalid(value: value) 62 | } 63 | } 64 | 65 | static func singleFrom(string: String) -> ExplorerValue { 66 | if let int = Int(string) { 67 | return .int(int) 68 | } else if let double = Double(string) { 69 | return .double(double) 70 | } else if let bool = Bool(string) { 71 | return .bool(bool) 72 | } else { 73 | return .string(string) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValue/Other/ExplorerValue+CustomStringConvertible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - CustomStringConvertible 7 | 8 | extension ExplorerValue: CustomStringConvertible { 9 | 10 | public var description: String { 11 | switch self { 12 | case .int(let int): return int.description 13 | case .double(let double): return double.description 14 | case .string(let string): return string 15 | case .bool(let bool): return bool.description 16 | case .data(let data): return data.base64EncodedString() 17 | case .date(let date): return date.description 18 | case .array(let array): 19 | let elements = array.map(\.description).joined(separator: ",") 20 | return "[\(elements)]" 21 | case .dictionary(let dict): 22 | let elements = dict.map { "\($0.key): \($0.value)" }.joined(separator: ",") 23 | return "[\(elements)]" 24 | } 25 | } 26 | } 27 | 28 | // MARK: - CustomDebugStringConvertible 29 | 30 | extension ExplorerValue: CustomDebugStringConvertible { 31 | 32 | public var debugDescription: String { description } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValue/Other/ExplorerValue+ExpressibleBy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - ExpressibleByStringLiteral 7 | 8 | extension ExplorerValue: ExpressibleByStringLiteral { 9 | 10 | public init(stringLiteral value: String) { 11 | self = .string(value) 12 | } 13 | } 14 | 15 | // MARK: - ExpressibleByIntegerLiteral 16 | 17 | extension ExplorerValue: ExpressibleByIntegerLiteral { 18 | 19 | public init(integerLiteral value: Int) { 20 | self = .int(value) 21 | } 22 | } 23 | 24 | // MARK: - ExpressibleByFloatLiteral 25 | 26 | extension ExplorerValue: ExpressibleByFloatLiteral { 27 | 28 | public init(floatLiteral value: Double) { 29 | self = .double(value) 30 | } 31 | } 32 | 33 | // MARK: - ExpressibleByBooleanLiteral 34 | 35 | extension ExplorerValue: ExpressibleByBooleanLiteral { 36 | 37 | public init(booleanLiteral value: Bool) { 38 | self = .bool(value) 39 | } 40 | } 41 | 42 | // MARK: - ExpressibleByArrayLiteral 43 | 44 | extension ExplorerValue: ExpressibleByArrayLiteral { 45 | 46 | public init(arrayLiteral elements: ExplorerValue...) { 47 | self = .array(elements) 48 | } 49 | } 50 | 51 | // MARK: - ExpressibleByDictionaryLiteral 52 | 53 | extension ExplorerValue: ExpressibleByDictionaryLiteral { 54 | 55 | public init(dictionaryLiteral elements: (String, ExplorerValue)...) { 56 | self = .dictionary(Dictionary(uniqueKeysWithValues: elements)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValue/Other/ExplorerValue+Folded.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - Folding 9 | 10 | extension ExplorerValue { 11 | 12 | // MARK: Constants 13 | 14 | private var foldedKey: String { Folding.foldedKey } 15 | private var foldedMark: String { Folding.foldedMark } 16 | 17 | // MARK: Fold 18 | 19 | func folded(upTo level: Int) -> Self { 20 | switch self { 21 | case .string, .int, .double, .bool, .data, .date: 22 | return self 23 | 24 | case .array(let array): 25 | if level <= 0 { 26 | return self.array <^> [Self.string(foldedMark)] 27 | } else { 28 | return self.array <^> array.map { $0.folded(upTo: level - 1) } 29 | } 30 | 31 | case .dictionary(let dict): 32 | if level <= 0 { 33 | return dictionary <^> [foldedKey: .string(foldedMark)] 34 | } else { 35 | return dictionary <^> dict.mapValues { $0.folded(upTo: level - 1) } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValue/Other/ExplorerValue+Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - Compute index 9 | 10 | extension PathExplorer { 11 | 12 | /// Compute the index, positive or negative. Negative index uses the array count. 13 | /// - Parameters: 14 | /// - index: Index to compute 15 | /// - arrayCount: Array count 16 | static func computeIndex(from index: Int, arrayCount: Int) throws -> Int { 17 | let computedIndex = index < 0 ? arrayCount + index : index 18 | 19 | guard 0 <= computedIndex, computedIndex < arrayCount else { 20 | throw ExplorerError.wrong(index: index, arrayCount: arrayCount) 21 | } 22 | 23 | return computedIndex 24 | } 25 | } 26 | 27 | // MARK: - Operators 28 | 29 | infix operator <^> 30 | 31 | /// Apply the left function to the right operand. 32 | /// - note: Mainly used as synthetic sugar to avoid over use of brackets. 33 | func <^>(lhs: (A) -> B, rhs: A) -> B { lhs(rhs) } 34 | 35 | extension ExplorerValue: EquatablePathExplorer { 36 | public init(value: ExplorerValue, name: String?) { 37 | self = value 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/CodableFormat/CodableFormat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - CodableFormat 9 | 10 | public protocol CodableFormat { 11 | 12 | // MARK: Properties 13 | 14 | static var dataFormat: DataFormat { get } 15 | 16 | /// Regex used to find folded marks in the description of a folded explorer 17 | static var foldedRegexPattern: String { get } 18 | 19 | // MARK: Encode 20 | 21 | static func encode(_ value: E, rootName: String?) throws -> Data 22 | 23 | // MARK: Decode 24 | 25 | static func decode(_ type: D.Type, from data: Data) throws -> D 26 | } 27 | 28 | // MARK: Encode 29 | 30 | public extension CodableFormat { 31 | 32 | static func encode(_ value: E) throws -> Data { 33 | try encode(value, rootName: nil) 34 | } 35 | } 36 | 37 | // MARK: - Constants 38 | 39 | extension CodableFormat { 40 | 41 | static var foldedKey: String { Folding.foldedKey } 42 | static var foldedMark: String { Folding.foldedMark } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/CodableFormat/CodableFormats+JsonDateIso8601.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - JsonDateIso8601 9 | 10 | extension CodableFormats { 11 | 12 | public enum JsonDateIso8601: CodableFormat { 13 | 14 | // MARK: Constants 15 | 16 | public static let dataFormat: DataFormat = .json 17 | public static var foldedRegexPattern: String { JsonDefault.foldedRegexPattern } 18 | 19 | private static let decoder: JSONDecoder = { 20 | let decoder = JSONDecoder() 21 | decoder.dateDecodingStrategy = .iso8601 22 | return decoder 23 | }() 24 | 25 | private static let encoder: JSONEncoder = { 26 | let encoder = JSONEncoder() 27 | encoder.dateEncodingStrategy = .iso8601 28 | encoder.outputFormatting = .prettyPrinted 29 | return encoder 30 | }() 31 | 32 | // MARK: Encode 33 | 34 | public static func decode(_ type: D.Type, from data: Data) throws -> D where D: Decodable { 35 | try decoder.decode(type, from: data) 36 | } 37 | 38 | // MARK: Decode 39 | 40 | public static func encode(_ value: E, rootName: String?) throws -> Data where E: Encodable { 41 | try encoder.encode(value) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/CodableFormat/CodableFormats+JsonDefault.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - JsonDefault 9 | 10 | public extension CodableFormats { 11 | 12 | enum JsonDefault: CodableFormat { 13 | 14 | // MARK: Constants 15 | 16 | public static var dataFormat: DataFormat { .json } 17 | public static var foldedRegexPattern: String { 18 | #"(?<=\[)\s*"\#(foldedMark)"\s*(?=\])"# // array 19 | + #"|(?<=\{)\s*"\#(foldedKey)"\s*:\s*"\#(foldedMark)"\s*(?=\})"# // dict 20 | } 21 | 22 | private static let encoder: JSONEncoder = { 23 | let encoder = JSONEncoder() 24 | encoder.outputFormatting = .prettyPrinted 25 | return encoder 26 | }() 27 | 28 | private static let decoder: JSONDecoder = JSONDecoder() 29 | 30 | // MARK: Encode 31 | 32 | public static func encode(_ value: E, rootName: String?) throws -> Data { 33 | try encoder.encode(value) 34 | } 35 | 36 | // MARK: Decode 37 | 38 | public static func decode(_ type: D.Type, from data: Data) throws -> D where D: Decodable { 39 | try decoder.decode(type, from: data) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/CodableFormat/CodableFormats+Namespace.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - CodableFormats 7 | 8 | /// Namespace for types implementing ``CodableFormat``. 9 | public enum CodableFormats {} 10 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/CodableFormat/CodableFormats+PlistDefault.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - PlistDefault 9 | 10 | public extension CodableFormats { 11 | 12 | enum PlistDefault: CodableFormat { 13 | 14 | // MARK: Constants 15 | 16 | public static var dataFormat: DataFormat { .plist } 17 | 18 | public static var foldedRegexPattern: String { 19 | #"(?<=)\s*\#(foldedMark)\s*(?=)"# // array 20 | + #"|(?<=)\s*\#(foldedKey)\s*\#(foldedMark)\s*(?=)"# // dict 21 | } 22 | 23 | private static let encoder: PropertyListEncoder = { 24 | let encoder = PropertyListEncoder() 25 | encoder.outputFormat = .xml 26 | return encoder 27 | }() 28 | 29 | private static let decoder: PropertyListDecoder = PropertyListDecoder() 30 | 31 | // MARK: Encode 32 | 33 | public static func encode(_ value: E, rootName: String?) throws -> Data where E: Encodable { 34 | try encoder.encode(value) 35 | } 36 | 37 | // MARK: Decode 38 | 39 | public static func decode(_ type: D.Type, from data: Data) throws -> D where D: Decodable { 40 | try decoder.decode(type, from: data) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/CodableFormat/CodableFormats+YamlDefault.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Yams 7 | import Foundation 8 | 9 | // MARK: - YamlDefault 10 | 11 | public extension CodableFormats { 12 | 13 | enum YamlDefault: CodableFormat { 14 | 15 | // MARK: Constants 16 | 17 | public static var dataFormat: DataFormat { .yaml } 18 | 19 | public static var foldedRegexPattern: String { 20 | #"\#(foldedMark)\s*(?=\n)"# // array 21 | + #"|\#(foldedKey)\s*:\s*\#(foldedMark)\s*(?=\n)"# // dict 22 | } 23 | 24 | private static let encoder = YAMLEncoder() 25 | private static let decoder = YAMLDecoder() 26 | 27 | // MARK: Encode 28 | 29 | public static func encode(_ value: E, rootName: String?) throws -> Data where E: Encodable { 30 | try encoder.encode(value).data(using: .utf8).unwrapOrThrow(.stringToData) 31 | } 32 | 33 | // MARK: Decode 34 | 35 | public static func decode(_ type: D.Type, from data: Data) throws -> D where D: Decodable { 36 | try decoder.decode(type, from: data) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/Decoding/ExplorerValueDecoder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - ExplorerValueDecoder 9 | 10 | final class ExplorerValueDecoder: Decoder { 11 | 12 | // MARK: Properties 13 | 14 | var codingPath: [CodingKey] 15 | var userInfo: [CodingUserInfoKey: Any] = [:] 16 | let value: ExplorerValue 17 | 18 | // MARK: Init 19 | 20 | init(_ value: ExplorerValue, codingPath: [CodingKey] = []) { 21 | self.value = value 22 | self.codingPath = codingPath 23 | } 24 | } 25 | 26 | // MARK: - Containers 27 | 28 | extension ExplorerValueDecoder { 29 | 30 | func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer where Key: CodingKey { 31 | KeyedDecodingContainer(Container(value: value, codingPath: codingPath, decoder: self)) 32 | } 33 | 34 | func unkeyedContainer() throws -> UnkeyedDecodingContainer { 35 | let array = try value.array.unwrapOrThrow(error: valueTypeError(type: [ExplorerValue].self)) 36 | return UnkeyedContainer(array: array, codingPath: codingPath, decoder: self) 37 | } 38 | 39 | func singleValueContainer() throws -> SingleValueDecodingContainer { 40 | SingleValueContainer(value: value, codingPath: codingPath, decoder: self) 41 | } 42 | } 43 | 44 | // MARK: - Error 45 | 46 | extension ExplorerValueDecoder { 47 | 48 | func valueTypeError(type: T.Type) -> DecodingError { 49 | DecodingError.typeMismatch( 50 | T.self, 51 | DecodingError.Context(codingPath: codingPath, debugDescription: "")) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/DecodingError+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - typeMismatch 9 | 10 | extension DecodingError { 11 | 12 | static func typeMismatch(_ type: T.Type, codingPath: [CodingKey]) -> DecodingError { 13 | DecodingError.typeMismatch( 14 | T.self, 15 | DecodingError.Context(codingPath: codingPath, debugDescription: "")) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible+Codable/Encoding/ExplorerValueEncoder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - ExplorerValueEncoder 9 | 10 | final class ExplorerValueEncoder: Encoder { 11 | 12 | // MARK: Properties 13 | 14 | var codingPath: [CodingKey] 15 | var userInfo: [CodingUserInfoKey: Any] = [:] 16 | var value: ExplorerValue! 17 | 18 | // MARK: Init 19 | 20 | init(codingPath: [CodingKey] = []) { 21 | self.codingPath = codingPath 22 | } 23 | } 24 | 25 | // MARK: - Containers 26 | 27 | extension ExplorerValueEncoder { 28 | 29 | func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { 30 | value = .dictionary([:]) 31 | return KeyedEncodingContainer(Container(codingPath: codingPath, encoder: self, path: .empty)) 32 | } 33 | 34 | func unkeyedContainer() -> UnkeyedEncodingContainer { 35 | value = .array([]) 36 | return UnkeyedContainer(codingPath: codingPath, encoder: self, path: .empty) 37 | } 38 | 39 | func singleValueContainer() -> SingleValueEncodingContainer { 40 | value = .bool(false) 41 | return SingleContainer(codingPath: codingPath, encoder: self, path: .empty) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/ExplorerValueConvertible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - ExplorerValueRepresentable 9 | 10 | /// Can be represented as an `ExplorerValue` 11 | /// - note: Default implementation provided for types conforming to `Encodable` 12 | public protocol ExplorerValueRepresentable { 13 | 14 | /// Convert `self` to an ``ExplorerValue`` 15 | func explorerValue() throws -> ExplorerValue 16 | } 17 | 18 | // MARK: - ExplorerValueCreatable 19 | 20 | /// Can be instantiated from an ``ExplorerValue`` 21 | /// - note: Default implementation provided for types conforming to `Decodable` 22 | public protocol ExplorerValueCreatable { 23 | 24 | /// Instantiate a new value from an ``ExplorerValue`` 25 | init(from explorerValue: ExplorerValue) throws 26 | } 27 | 28 | // MARK: - ExplorerValueConvertible 29 | 30 | /// Can be represented *as* and instantiated *from* an ``ExplorerValue`` 31 | /// - note: Default implementation provided for types conforming to `Codable` 32 | public typealias ExplorerValueConvertible = ExplorerValueRepresentable & ExplorerValueCreatable 33 | 34 | // MARK: - Encodable 35 | 36 | public extension ExplorerValueRepresentable where Self: Encodable { 37 | 38 | func explorerValue() throws -> ExplorerValue { 39 | let encoder = ExplorerValueEncoder() 40 | try encode(to: encoder) 41 | return encoder.value 42 | } 43 | } 44 | 45 | // MARK: - Decodable 46 | 47 | public extension ExplorerValueCreatable where Self: Decodable { 48 | 49 | init(from explorerValue: ExplorerValue) throws { 50 | let decoder = ExplorerValueDecoder(explorerValue) 51 | try self.init(from: decoder) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerValueSerialization/SerializationError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - SerializationError 9 | 10 | /// Error that can be thrown during serialization operations. 11 | public enum SerializationError { 12 | 13 | case dataToString 14 | case stringToData 15 | case notCSVExportable(description: String) 16 | } 17 | 18 | // MARK: - LocalizedError 19 | 20 | extension SerializationError: LocalizedError { 21 | 22 | public var errorDescription: String? { 23 | switch self { 24 | case .dataToString: return "The data value cannot be represented as a String" 25 | case .stringToData: return "The string value cannot be represented as Data" 26 | case .notCSVExportable(let description): return "The value is not properly exportable to CSV. \(description)" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerXML/ExplorerXML+Fold.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension ExplorerXML { 9 | 10 | private var foldedKey: String { Folding.foldedKey } 11 | private var foldedMark: String { Folding.foldedMark } 12 | var foldedRegexPattern: String { #"(?<=>)\s*<\#(foldedKey)>\#(foldedMark)\s*(?=<)"# } 13 | 14 | public func folded(upTo level: Int) -> Self { 15 | guard level > 0 else { 16 | if children.isEmpty { 17 | return copy() 18 | } else { 19 | let copy = copyWithoutChildren() 20 | copy.addChild(ExplorerXML(name: foldedKey, value: foldedMark)) 21 | return copy 22 | } 23 | } 24 | 25 | return copyMappingChildren { $0.folded(upTo: level - 1) } 26 | } 27 | 28 | public func exportFoldedString(upTo level: Int) throws -> String { 29 | try folded(upTo: level) 30 | .exportString() 31 | .replacingOccurrences(of: foldedRegexPattern, with: "...", options: .regularExpression) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerXML/ExplorerXML+Serialization.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import AEXML 8 | 9 | extension ExplorerXML: SerializablePathExplorer { 10 | 11 | public static var format: DataFormat { .xml } 12 | 13 | public init(data: Data) throws { 14 | let document = try AEXMLDocument(xml: data) 15 | self.init(element: document.root) 16 | } 17 | 18 | /// Export the path explorer value to data 19 | public func exportData() throws -> Data { 20 | try description.data(using: .utf8).unwrapOrThrow(.dataToString) 21 | } 22 | 23 | public func exportString() throws -> String { description } 24 | 25 | public func exportData(to format: DataFormat, rootName: String?) throws -> Data { 26 | switch format { 27 | case .json: return try CodableFormats.JsonDefault.encode(explorerValue(), rootName: rootName) 28 | case .plist: return try CodableFormats.PlistDefault.encode(explorerValue(), rootName: rootName) 29 | case .yaml: return try CodableFormats.YamlDefault.encode(explorerValue(), rootName: rootName) 30 | case .xml: return try exportData() 31 | } 32 | } 33 | 34 | public func exportString(to format: DataFormat, rootName: String?) throws -> String { 35 | switch format { 36 | case .json: return try PathExplorers.Json(value: explorerValue()).exportString() 37 | case .plist: return try PathExplorers.Plist(value: explorerValue()).exportString() 38 | case .yaml: return try PathExplorers.Yaml(value: explorerValue()).exportString() 39 | case .xml: return try exportString() 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerXML/ExplorerXML+SingleChildStrategy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - SingleChildStrategy 7 | 8 | extension ExplorerXML { 9 | 10 | public struct SingleChildStrategy { 11 | 12 | // MARK: Type alias 13 | 14 | public typealias Transform = (_ key: String, _ value: ExplorerValue) -> ExplorerValue 15 | 16 | // MARK: Properties 17 | 18 | var transform: Transform 19 | 20 | // MARK: Init 21 | 22 | init(transform: @escaping Transform) { 23 | self.transform = transform 24 | } 25 | } 26 | } 27 | 28 | // MARK: - Static 29 | 30 | extension ExplorerXML.SingleChildStrategy { 31 | 32 | public static let dictionary = ExplorerXML.SingleChildStrategy { (key, value) -> ExplorerValue in .dictionary([key: value]) } 33 | public static let array = ExplorerXML.SingleChildStrategy { (_, value) -> ExplorerValue in .array([value]) } 34 | public static func custom(_ transform: @escaping Transform) -> ExplorerXML.SingleChildStrategy { 35 | ExplorerXML.SingleChildStrategy { (key, value) in transform(key, value) } 36 | } 37 | 38 | /// Check the the element name. With a default name, an array is returned. 39 | /// Otherwise a dictionary 40 | public static let `default` = ExplorerXML.SingleChildStrategy { (key, value) in 41 | if key == ExplorerXML.Element.defaultName { 42 | return array.transform(key, value) 43 | } else { 44 | return dictionary.transform(key, value) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Scout/ExplorerXML/ExplorerXML+ValueSetter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - ValueSetter 7 | 8 | extension ExplorerXML { 9 | 10 | /// Wrapper to more easily handle setting an ExplorerValue or Element. 11 | enum ValueSetter { 12 | case explorerValue(ExplorerValue) 13 | case explorerXML(ExplorerXML) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/AEXML/AEXMLElement+Equal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import AEXML 7 | 8 | extension AEXMLElement { 9 | 10 | static let defaultName = "element" 11 | static let root = "root" 12 | 13 | func isEqual(to other: AEXMLElement) -> Bool { 14 | 15 | if children.count != other.children.count { 16 | return false 17 | } 18 | 19 | if children.isEmpty, other.children.isEmpty { 20 | return attributes == other.attributes 21 | && (name == other.name || [name, other.name].contains("root") || [name, other.name].contains(Self.defaultName)) // root names are not always the same 22 | && value == other.value 23 | } 24 | 25 | var sortedChildren: [AEXMLElement] 26 | var otherSortedChildren: [AEXMLElement] 27 | 28 | if commonChildrenName != nil { // array 29 | // sort by value 30 | sortedChildren = children.sorted { $0.string < $1.string } 31 | otherSortedChildren = other.children.sorted { $0.string < $1.string } 32 | } else { 33 | // sort by key 34 | sortedChildren = children.sorted { $0.name < $1.name } 35 | otherSortedChildren = other.children.sorted { $0.name < $1.name } 36 | } 37 | 38 | return zip(sortedChildren, otherSortedChildren).first { !$0.isEqual(to: $1) } == nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/AEXML/AEXMLElement+Group.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import AEXML 7 | 8 | extension AEXMLElement { 9 | 10 | /// Array or dictionary value type 11 | enum GroupValue: String { 12 | case array, dictionary 13 | } 14 | 15 | private struct GroupCount { 16 | var arrays = 0 17 | var dictionaries = 0 18 | 19 | var max: GroupValue { 20 | if arrays > dictionaries { 21 | return .array 22 | } 23 | return .dictionary // dictionary in case of equality (arbitrary) 24 | } 25 | } 26 | 27 | /// Indicates whether the children are most likely to be arrays or dictionaries 28 | /// 29 | /// #### Complexity 30 | /// O(nm) where 31 | /// - n: Children count 32 | /// - m: Maximum children's children count 33 | var bestChildrenGroupFit: GroupValue { 34 | var groupCounts = GroupCount() 35 | 36 | children.forEach { child in 37 | if child.children.count > 1, child.commonChildrenName != nil { 38 | groupCounts.arrays += 1 39 | } else { 40 | groupCounts.dictionaries += 1 41 | } 42 | } 43 | 44 | return groupCounts.max 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Array+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Array { 9 | 10 | func getIfPresent(at index: Int) -> Element? { 11 | guard index >= 0, index < count else { return nil } 12 | 13 | return self[index] 14 | } 15 | 16 | func remove(in range: ClosedRange) -> Self { 17 | assert(range.lowerBound >= 0) 18 | assert(range.upperBound < count) 19 | 20 | let leftPart = self[0.. Void) rethrows { 33 | try self = map { element in 34 | var element = element 35 | try modify(&element) 36 | return element 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/CodingKey+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension CodingKey { 9 | 10 | /// Path element string description 11 | var pathDescription: String { 12 | let split = stringValue.components(separatedBy: " ") 13 | 14 | if split.count == 2, split[0] == "Index", let index = Int(split[1]) { 15 | return "[\(index)]" 16 | } else { 17 | return stringValue 18 | } 19 | } 20 | } 21 | 22 | extension Array where Element == CodingKey { 23 | 24 | /// String description of the coding path 25 | var pathDescription: String { 26 | var path = reduce("") { "\($0)\($1.pathDescription)" } 27 | 28 | if path.hasPrefix(".") { 29 | path.removeFirst() 30 | } 31 | 32 | return path 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Collection+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension RandomAccessCollection { 9 | 10 | /// When not empty, return the first element and self without the first element 11 | func headAndTail() -> (head: Element, tail: SubSequence)? { 12 | guard let head = first else { return nil } 13 | return (head, dropFirst()) 14 | } 15 | } 16 | 17 | extension Collection { 18 | 19 | /// Unwrap all the elements mapped by the provided function. If one unwrap fails, `nil` is returned 20 | func unwrapAll(_ transform: (Element) throws -> T?) rethrows -> [T]? { 21 | var unwrapped: [T] = [] 22 | 23 | for element in self { 24 | if let transformed = try transform(element) { 25 | unwrapped.append(transformed) 26 | } else { 27 | return nil 28 | } 29 | } 30 | 31 | return unwrapped 32 | } 33 | 34 | /// Unwrap all the elements mapped by the provided key path. If one unwrap fails, `nil` is returned 35 | func unwrapAll(_ keyPath: KeyPath) -> [T]? { 36 | unwrapAll { $0[keyPath: keyPath] } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Collection+Path.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | public extension Collection where Element == PathElement { 9 | 10 | /// Compare key or index when found at the same position 11 | func comparedByKeyAndIndexes(with otherPath: Path) -> Bool { 12 | var lhsIterator = makeIterator() 13 | var rhsIterator = otherPath.makeIterator() 14 | 15 | while let lhsElement = lhsIterator.next(), let rhsElement = rhsIterator.next() { 16 | switch (lhsElement, rhsElement) { 17 | 18 | case (.key(let lhsLabel), .key(let rhsLabel)): 19 | if lhsLabel != rhsLabel { 20 | return lhsLabel < rhsLabel 21 | } 22 | 23 | case (.index(let lhsIndex), .index(let rhsIndex)): 24 | if lhsIndex != rhsIndex { 25 | return lhsIndex < rhsIndex 26 | } 27 | 28 | default: 29 | return true 30 | } 31 | } 32 | 33 | return count < otherPath.count // put the shorter path before 34 | } 35 | } 36 | 37 | public extension Collection where Element == Path { 38 | 39 | /// Sort by key or index when found at the same position 40 | func sortedByKeysAndIndexes() -> [Path] { 41 | sorted { (lhs, rhs) in lhs.comparedByKeyAndIndexes(with: rhs) } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Dictionary+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Dictionary where Key == String { 9 | 10 | /// Return the value for the key if it exists. Otherwise throw an error `missingKey` with the best Jaro-Winkler match found 11 | func jaroWinkler(key: String) throws -> Value { 12 | try self[key] 13 | .unwrapOrThrow( 14 | .missing( 15 | key: key, 16 | bestMatch: key.bestJaroWinklerMatchIn(propositions: Set(keys)) 17 | ) 18 | ) 19 | } 20 | } 21 | 22 | extension Dictionary { 23 | 24 | mutating func modifyEachValue(_ modify: (inout Value) throws -> Void) rethrows { 25 | self = try mapValues { value in 26 | var value = value 27 | try modify(&value) 28 | return value 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Int+LastIndex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Int { 9 | /// Represents the last index in an array 10 | static let lastIndex = -1 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/NSRegularExpression+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension NSRegularExpression { 9 | 10 | convenience init(with pattern: String) throws { 11 | do { 12 | try self.init(pattern: pattern) 13 | } catch { 14 | throw ExplorerError.wrong(regexPattern: pattern) 15 | } 16 | } 17 | 18 | /// Validate a string if the first match found by the regex is the overall string 19 | func validate(_ string: String) -> Bool { 20 | guard 21 | let firstMatch = firstMatch(in: string, options: [], range: NSRange(location: 0, length: string.count)), 22 | firstMatch.range.length >= 0 23 | else { 24 | return false 25 | } 26 | 27 | if firstMatch.range.length == 0 { 28 | if string.isEmpty { 29 | return true 30 | } else { 31 | return false 32 | } 33 | } 34 | 35 | return string[firstMatch.range] == string 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Optional+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | infix operator !! 9 | 10 | /// Force unwrap an optional when required, with a relevant error message if the optional is `nil` 11 | /// - Parameters: 12 | /// - optional: The optional to unwrap 13 | /// - errorMessage: An error message 14 | /// - Returns: The unwrapped optional 15 | /// - note: Idea from [Advanced Swift](https://www.objc.io/books/advanced-swift/) 16 | func !!(optional: T?, errorMessage: @autoclosure () -> String) -> T { 17 | if let unwrapped = optional { 18 | return unwrapped 19 | } 20 | fatalError(errorMessage()) 21 | } 22 | 23 | extension Optional { 24 | 25 | func unwrapOrThrow(error: Error) throws -> Wrapped { 26 | guard let wrapped = self else { 27 | throw error 28 | } 29 | return wrapped 30 | } 31 | 32 | func unwrapOrThrow(_ error: ExplorerError) throws -> Wrapped { 33 | try unwrapOrThrow(error: error) 34 | } 35 | 36 | func unwrapOrThrow(_ error: DecodingError) throws -> Wrapped { 37 | try unwrapOrThrow(error: error) 38 | } 39 | 40 | func unwrapOrThrow(_ error: SerializationError) throws -> Wrapped { 41 | try unwrapOrThrow(error: error) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Scout/Extensions/Slice+Etensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Slice where Base == Path { 9 | 10 | /// The part from base start to the beginning of the slice 11 | var leftPart: Self { 12 | base[.. Substring { 16 | let sliceStartIndex = index(startIndex, offsetBy: range.location) 17 | let sliceEndIndex = index(startIndex, offsetBy: range.upperBound - 1) 18 | 19 | return self[sliceStartIndex...sliceEndIndex] 20 | } 21 | 22 | func isEnclosed(by string: String) -> Bool { hasPrefix(string) && hasSuffix(string) } 23 | 24 | /// Remove the enclosing brackets '(' ')' if found 25 | func removingEnclosingBrackets() -> String { 26 | if hasPrefix("("), hasSuffix(")") { 27 | return String(self[index(after: startIndex).. String { 34 | if contains(string) { 35 | return #""\#(self)""# 36 | } else { 37 | return self 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Scout/Models/Error/PathError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - PathError 9 | 10 | enum PathError { 11 | 12 | case invalidStringPath(_ string: String) 13 | case invalidSeparator(String) 14 | case invalidRegex(pattern: String) 15 | } 16 | 17 | // MARK: - LocalizedError 18 | 19 | extension PathError: LocalizedError { 20 | 21 | var errorDescription: String? { 22 | switch self { 23 | case .invalidStringPath(let string): return "The part '\(string)' of the path is invalid" 24 | case .invalidSeparator(let separator): return "The separator \(separator) is not forbidden or must be escaped" 25 | case .invalidRegex(let pattern): return "The regular expression '\(pattern)' to split the path string is not valid." 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Scout/Models/Path/Bounds+Bound.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - Bound 7 | 8 | public extension Bounds { 9 | 10 | struct Bound: ExpressibleByIntegerLiteral, Hashable { 11 | 12 | // MARK: Type alias 13 | 14 | public typealias IntegerLiteralType = Int 15 | 16 | // MARK: Constants 17 | 18 | public static let first = Bound(0, identifier: "first") 19 | public static let last = Bound(-1, identifier: "last") 20 | 21 | // MARK: Properties 22 | 23 | var value: Int 24 | private(set) var identifier: String? 25 | 26 | // MARK: Init 27 | 28 | public init(integerLiteral value: Int) { 29 | self.value = value 30 | } 31 | 32 | public init(_ value: Int) { 33 | self.value = value 34 | } 35 | 36 | private init(_ value: Int, identifier: String) { 37 | self.value = value 38 | self.identifier = identifier 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Scout/Models/Path/Bounds+IntWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - IntWrapper 7 | 8 | extension Bounds { 9 | 10 | /// Wrapper around an `Int` value to avoid to make all the `Bounds` mutable. 11 | /// - note: `Bounds` will only mutate those `IntWrapper` values internally. 12 | @propertyWrapper 13 | final class IntWrapper { 14 | 15 | // MARK: Properties 16 | 17 | var wrappedValue: Int? 18 | } 19 | } 20 | 21 | // MARK: - Hashable 22 | 23 | extension Bounds.IntWrapper: Hashable { 24 | 25 | static func == (lhs: Bounds.IntWrapper, rhs: Bounds.IntWrapper) -> Bool { 26 | lhs.wrappedValue == rhs.wrappedValue 27 | } 28 | 29 | func hash(into hasher: inout Hasher) { 30 | hasher.combine(wrappedValue) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Scout/Models/Path/Path+Miscellaneous.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | public extension Collection where Element == PathElement { 9 | 10 | /// Retrieve all the index elements 11 | var compactMapIndexes: [Int] { compactMap(\.index) } 12 | 13 | /// Retrieve all the key elements 14 | var compactMapKeys: [String] { compactMap(\.key) } 15 | 16 | /// Retrieve all the slices bounds elements 17 | var compactMapSlices: [Bounds] { 18 | compactMap { 19 | if case let .slice(bounds) = $0 { 20 | return bounds 21 | } 22 | return nil 23 | } 24 | } 25 | 26 | /// Retrieve all the filter elements 27 | var compactMapFilter: [String] { 28 | compactMap { 29 | if case let .filter(pattern) = $0 { 30 | return pattern 31 | } 32 | return nil 33 | } 34 | } 35 | } 36 | 37 | public extension Collection where SubSequence == Slice { 38 | 39 | /// The greatest prefix that both paths have in common 40 | func commonPrefix(with otherPath: Self) -> Slice { 41 | var iterator = makeIterator() 42 | var otherIterator = otherPath.makeIterator() 43 | var lastIndex = 0 44 | 45 | while 46 | let element = iterator.next(), let otherElement = otherIterator.next(), 47 | element == otherElement { 48 | lastIndex += 1 49 | } 50 | 51 | return self[0.. PathElement { 12 | .slice(Bounds(lower: lower, upper: upper)) 13 | } 14 | 15 | /// Get all elements (convenience for testing) 16 | static var sliceAll: PathElement { .slice(.first, .last) } 17 | 18 | /// Get all elements (convenience for testing) 19 | static var filterAll: PathElement { .filter(".*") } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Scout/Models/Path/PathElementRepresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | /// Protocol to allow to subscript a `PathExplorer` without using directly the ``PathElement`` enum. 7 | /// 8 | /// As `PathElement` already conforms to `ExpressibleByStringLiteral` and `ExpressibleByIntegerLiteral`, 9 | /// it is possible to instantiate a Path without the need of using the `PathElementRepresentable` protocol: 10 | /// ``` 11 | /// let path: Path = ["people", "Tom", "hobbies", 1] 12 | /// ``` 13 | /// But the "Expressible" protocols do not allow to do the same with variables. 14 | /// Thus, using `PathElementRepresentable` allows to instantiate a Path from a mix of Strings and Integers variables: 15 | /// ```swift 16 | /// let tom = "Tom" 17 | /// let hobbies = "hobbies" 18 | /// let index = 1 19 | /// let path: Path = [tom, hobbies, index] 20 | /// ``` 21 | /// - note: This only works for keys and indexes. When dealing with other elements like `.count` or `.slice`, 22 | /// it's required to use the full name `PathElement.count`, `PathElement.slice`. Otherwise, 23 | /// the `Path.init(element:)` works with `PathElement` directly although the possibility to use variables 24 | /// without the `PathElement` specification becomes unavailable. 25 | public protocol PathElementRepresentable { 26 | var pathValue: PathElement { get } 27 | } 28 | 29 | extension String: PathElementRepresentable { 30 | public var pathValue: PathElement { .key(self) } 31 | } 32 | 33 | extension Int: PathElementRepresentable { 34 | public var pathValue: PathElement { .index(self) } 35 | } 36 | 37 | extension PathElement: PathElementRepresentable { 38 | public var pathValue: PathElement { self } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Scout/Models/Path/PathTree+ValueType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | // MARK: - ValueType 7 | 8 | extension PathTree { 9 | 10 | enum ValueType: Equatable { 11 | case uninitializedLeaf 12 | case leaf(value: Value) 13 | case node(children: [PathTree]) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathExplorer/CodablePathExplorer+Serialization.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension CodablePathExplorer: SerializablePathExplorer { 9 | 10 | public static var format: DataFormat { Format.dataFormat } 11 | 12 | public init(data: Data) throws { 13 | let value = try Format.decode(ExplorerValue.self, from: data) 14 | self.init(value: value) 15 | } 16 | 17 | public func exportData() throws -> Data { 18 | try Format.encode(value) 19 | } 20 | 21 | public func exportString() throws -> String { 22 | try String(data: exportData(), encoding: .utf8) 23 | .unwrapOrThrow(.dataToString) 24 | } 25 | 26 | public func exportData(to format: DataFormat, rootName: String?) throws -> Data { 27 | switch format { 28 | case .json: return try CodableFormats.JsonDefault.encode(value) 29 | case .plist: return try CodableFormats.PlistDefault.encode(value) 30 | case .yaml: return try CodableFormats.YamlDefault.encode(value) 31 | case .xml: return try ExplorerXML(value: value, name: rootName).exportData() 32 | } 33 | } 34 | 35 | public func exportString(to format: DataFormat, rootName: String?) throws -> String { 36 | switch format { 37 | case .json, .plist, .yaml: 38 | return try String(data: exportData(to: format, rootName: rootName), encoding: .utf8).unwrapOrThrow(.dataToString) 39 | 40 | case .xml: return try ExplorerXML(value: value, name: rootName).exportString() 41 | } 42 | } 43 | 44 | public func exportCSV(separator: String?) throws -> String { 45 | try value.exportCSV(separator: separator ?? defaultCSVSeparator) 46 | } 47 | 48 | public static func fromCSV(string: String, separator: Character, hasHeaders: Bool) throws -> CodablePathExplorer { 49 | try Self(value: .fromCSV(string: string, separator: separator, hasHeaders: hasHeaders)) 50 | } 51 | 52 | public func folded(upTo level: Int) -> Self { 53 | Self(value: value.folded(upTo: level)) 54 | } 55 | 56 | public func exportFoldedString(upTo level: Int) throws -> String { 57 | try folded(upTo: level) 58 | .exportString() 59 | .replacingOccurrences(of: Format.foldedRegexPattern, with: "...", options: .regularExpression) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathExplorer/EquatablePathExplorer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - EquatablePathExplorer 9 | 10 | /// Internal protocol to declare how to test equality to another PathExplorer of the same type without publicly declare conformance to `Equatable`. 11 | protocol EquatablePathExplorer: PathExplorer { 12 | 13 | /// `true` when self is equal to the provided other element. 14 | /// 15 | /// ### Complexity 16 | /// Most often `O(n)` where `n` is the children count. 17 | func isEqual(to other: Self) -> Bool 18 | } 19 | 20 | // MARK: - Default implementation 21 | 22 | extension EquatablePathExplorer where Self: Equatable { 23 | 24 | func isEqual(to other: Self) -> Bool { self == other } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathExplorer/PathExplorer+Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension PathExplorer { 9 | 10 | /// Add the element to the thrown `ValueTypeError` if any 11 | func doAdd(_ element: PathElementRepresentable, _ block: () throws -> T) rethrows -> T { 12 | do { 13 | return try block() 14 | } catch let error as ExplorerError { 15 | throw error.adding(element) 16 | } 17 | } 18 | 19 | /// Add the element to the thrown `ValueTypeError` if any 20 | func doAdd(_ element: PathElementRepresentable, _ block: () throws -> Void) rethrows { 21 | do { 22 | try block() 23 | } catch let error as ExplorerError { 24 | throw error.adding(element) 25 | } 26 | } 27 | 28 | /// Add the element to the thrown `ValueTypeError` if any 29 | func doAdd(_ element: PathElement, _ block: () throws -> T) rethrows -> T { 30 | do { 31 | return try block() 32 | } catch let error as ExplorerError { 33 | throw error.adding(element) 34 | } 35 | } 36 | 37 | /// Add the element to the thrown `ValueTypeError` if any 38 | func doAdd(_ element: PathElement, _ block: () throws -> Void) rethrows { 39 | do { 40 | try block() 41 | } catch let error as ExplorerError { 42 | throw error.adding(element) 43 | } 44 | } 45 | 46 | /// do/catch on the provided block to catch a `ValueTypeError` and set the provided path on it 47 | func doSettingPath(_ path: Slice, _ block: () throws -> Void) rethrows { 48 | do { 49 | try block() 50 | } catch let error as ExplorerError { 51 | throw error.with(path: path) 52 | } 53 | } 54 | 55 | /// do/catch on the provided block to catch a `ValueTypeError` and set the provided path on it 56 | func doSettingPath(_ path: Slice, _ block: () throws -> T) rethrows -> T { 57 | do { 58 | return try block() 59 | } catch let error as ExplorerError { 60 | throw error.with(path: path) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathExplorer/PathExplorers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - PathExplorers 9 | 10 | /// Namespace to find all default PathExplorers in a single place. 11 | /// 12 | /// Use default explorers for a format: `PathExplorers.Json`, `PathExplorers.Xml`... 13 | public enum PathExplorers { 14 | 15 | public typealias Json = CodablePathExplorer 16 | public typealias Plist = CodablePathExplorer 17 | public typealias Yaml = CodablePathExplorer 18 | public typealias Xml = ExplorerXML 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathsFilter/PathsFilter+FunctionPredicate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import BooleanExpressionEvaluation 7 | 8 | // MARK: - FunctionPredicate 9 | 10 | extension PathsFilter { 11 | 12 | /// Specify a function to filter the value 13 | public final class FunctionPredicate: ValuePredicate { 14 | 15 | // MARK: Type alias 16 | 17 | public typealias Evaluation = (ExplorerValue) throws -> Bool 18 | 19 | // MARK: Properties 20 | 21 | public var evaluation: Evaluation 22 | 23 | // MARK: Init 24 | 25 | public init(evaluation: @escaping Evaluation) { 26 | self.evaluation = evaluation 27 | } 28 | } 29 | } 30 | 31 | // MARK: - Evaluate 32 | 33 | extension PathsFilter.FunctionPredicate { 34 | 35 | public func evaluate(with value: ExplorerValue) throws -> Bool { 36 | try evaluation(value) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathsFilter/ValuePredicate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import BooleanExpressionEvaluation 8 | 9 | // MARK: - ValuePredicate 10 | 11 | /// Expression or function to evaluate a value 12 | public protocol ValuePredicate { 13 | 14 | /// Evaluate the predicate with the value. 15 | /// 16 | /// - note: Ignore the error of mismatching types between the value and an operand and return `false` 17 | func evaluate(with value: ExplorerValue) throws -> Bool 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Scout/Models/PathsFilter/ValueTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | // MARK: - ValueTarget 9 | 10 | extension PathsFilter { 11 | 12 | /// Specifies if group (array, dictionary) values, single (string, bool...) values or both should be targeted. 13 | public enum ValueTarget: String, CaseIterable { 14 | 15 | /// Allows the key with a single or a group value. 16 | case singleAndGroup 17 | 18 | /// Allows the key with a single value. 19 | case group 20 | 21 | /// Allows the key with a group (array, dictionary) value. 22 | case single 23 | } 24 | } 25 | 26 | // MARK: - Computed 27 | 28 | extension PathsFilter.ValueTarget { 29 | 30 | /// Allows group values (array, dictionaries)? 31 | var groupAllowed: Bool { [.singleAndGroup, .group].contains(self) } 32 | 33 | /// Allow single values (string, bool...)? 34 | var singleAllowed: Bool { [.singleAndGroup, .single].contains(self) } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Extensions/explorer-value.md: -------------------------------------------------------------------------------- 1 | # ``Scout/ExplorerValue`` 2 | 3 | @Metadata { 4 | @DocumentationExtension(mergeBehavior: append) 5 | } 6 | 7 | ## Overview 8 | 9 | `ExplorerValue` is the back bone of serializable ``PathExplorer`` (JSON, Plist, YAML). It's the type that implements all the logic to conform to `PathExplorer`. Then ``CodablePathExplorer`` simply interfaces it with the proper data format to conform to ``SerializablePathExplorer``. Also, it's the type that is used to encode and decode to those formats. 10 | 11 | But it also allows to use your own types to inject them in a `PathExplorer`. Read more with 12 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Extensions/path-element.md: -------------------------------------------------------------------------------- 1 | # ``Scout/PathElement`` 2 | 3 | @Metadata { 4 | @DocumentationExtension(mergeBehavior: append) 5 | } 6 | 7 | ## Topics 8 | 9 | ### Basics 10 | 11 | - ``key(_:)`` 12 | - ``index(_:)`` 13 | 14 | ### Getting a group information 15 | 16 | - ``count`` 17 | - ``keysList`` 18 | 19 | ### Scope groups 20 | 21 | - ``filter(_:)`` 22 | - ``slice(_:)`` 23 | - ``slice(_:_:)`` 24 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Extensions/path.md: -------------------------------------------------------------------------------- 1 | # ``Scout/Path`` 2 | 3 | @Metadata { 4 | @DocumentationExtension(mergeBehavior: append) 5 | } 6 | 7 | ## Overview 8 | 9 | Paths are the way to feed a ``PathExplorer`` to navigate through data. `PathExplorer`'s operations will often take a `Path` (or a collection of ``PathElement``s) to target precisely where to run. 10 | 11 | Basically, a `Path` is a collection of ``PathElement``s in a specific order. The sequence of `PathElement`s lets the explorer know what value to target next. When navigating to a value is not possible, the explorer will throw an error. 12 | 13 | ## Topics 14 | 15 | ### Instantiate an empty Path 16 | 17 | - ``init()`` 18 | - ``empty`` 19 | 20 | ### Instantiate from PathElement values 21 | 22 | - ``init(elements:)-8dch4`` 23 | - ``init(elements:)-9i64v`` 24 | 25 | ### Instantiate from PathElementRepresentable values 26 | 27 | ``PathElementRepresentable`` is a protocol to erase the `PathElement` type when instantiating a `Path` with non-literal values. 28 | 29 | - ``init(_:)-1b2iy`` 30 | - ``init(_:)-cgb7`` 31 | - ``init(arrayLiteral:)`` 32 | 33 | ### Instantiate from a String 34 | 35 | A `Path` is easily represented as a `String`, which is especially useful when working in the command-line. 36 | 37 | - ``init(string:separator:)`` 38 | - ``defaultSeparator`` 39 | - ``parser(separator:keyForbiddenCharacters:)`` 40 | 41 | ### Appending elements 42 | 43 | `Path` conforms to several collection protocols. Additionally, those convenience functions are offered. 44 | 45 | - ``append(_:)-9l194`` 46 | - ``appending(_:)-2ptn6`` 47 | - ``appending(_:)-3mvwq`` 48 | 49 | ### Flatten a Path 50 | 51 | When a `Path` contains special group scoping elements like ``PathElement/slice(_:)`` or ``PathElement/filter(_:)``, specifying a `PathElement.index` or `PathElement.key` will not refer to an immediate dictionary or array. The "flatten" operation will replace the slices and the filters in the `Path` with the proper values when the path is complete. Mainly used in paths listing ``PathExplorer/listPaths(startingAt:)``. 52 | 53 | - ``flattened()`` 54 | 55 | ### Map elements (Collection) 56 | 57 | - ``Path/compactMapIndexes`` 58 | - ``Path/compactMapKeys`` 59 | - ``Path/compactMapSlices`` 60 | - ``Path/compactMapFilter`` 61 | 62 | ### Compare path (Collection) 63 | 64 | - ``Path/commonPrefix(with:)`` 65 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Extensions/paths-filter.md: -------------------------------------------------------------------------------- 1 | # ``Scout/PathsFilter`` 2 | 3 | @Metadata { 4 | @DocumentationExtension(mergeBehavior: append) 5 | } 6 | 7 | ## Overview 8 | 9 | Allows to target single or group values, specific keys with regular expressions and values with predicates. 10 | 11 | When filtering keys or values, it's always possible to specify single, group values or both. 12 | 13 | ## Topics 14 | 15 | ### No filter 16 | 17 | - ``noFilter`` 18 | - ``targetOnly(_:)`` 19 | - ``ValueTarget`` 20 | 21 | ### Filter keys 22 | 23 | - ``key(regex:)`` 24 | - ``key(regex:target:)`` 25 | - ``key(pattern:target:)`` 26 | 27 | ### Filter values 28 | 29 | - ``value(_:)`` 30 | - ``value(_:_:)-8tfx1`` 31 | - ``value(_:_:)-2wxh0`` 32 | 33 | ### Filter keys and values 34 | 35 | - ``keyAndValue(pattern:valuePredicate:)`` 36 | - ``keyAndValue(keyRegex:valuePredicate:)`` 37 | - ``keyAndValue(keyRegex:valuePredicates:)`` 38 | - ``keyAndValue(keyRegex:valuePredicates:_:)`` 39 | - ``keyAndValue(pattern:valuePredicatesFormat:_:)`` 40 | 41 | ### Predicates 42 | 43 | - ``ValuePredicate`` 44 | - ``ExpressionPredicate`` 45 | - ``FunctionPredicate`` 46 | 47 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Extensions/serializable-path-explorer-export-folder.md: -------------------------------------------------------------------------------- 1 | # ``Scout/SerializablePathExplorer/exportFoldedString(upTo:)`` 2 | 3 | @Metadata { 4 | @DocumentationExtension(mergeBehavior: append) 5 | } 6 | ### Examples 7 | 8 | With the following JSON stored in a `SerializablePathExplorer` named `json`. 9 | 10 | ```json 11 | { 12 | "Tom" : { 13 | "age" : 68, 14 | "hobbies" : [ 15 | "cooking", 16 | "guitar" 17 | ], 18 | "height" : 175 19 | }, 20 | "Robert" : { 21 | "age" : 23, 22 | "hobbies" : [ 23 | "video games", 24 | "party", 25 | "tennis" 26 | ], 27 | "running_records" : [ 28 | [ 29 | 10, 30 | 12, 31 | 9, 32 | 10 33 | ], 34 | [ 35 | 9, 36 | 12, 37 | 11 38 | ] 39 | ], 40 | "height" : 181 41 | }, 42 | "Suzanne" : { 43 | "job" : "actress", 44 | "movies" : [ 45 | { 46 | "title" : "Tomorrow is so far", 47 | "awards" : "Best speech for a silent movie" 48 | }, 49 | { 50 | "title" : "Yesterday will never go", 51 | "awards" : "Best title" 52 | }, 53 | { 54 | "title" : "What about today?" 55 | } 56 | ] 57 | } 58 | } 59 | ``` 60 | 61 | The following 62 | 63 | ```swift 64 | json.exportFoldedString(upTo: 2) 65 | ``` 66 | 67 | will return the string: 68 | 69 | ```json 70 | { 71 | "Suzanne" : { 72 | "job" : "actress", 73 | "movies" : [...] 74 | }, 75 | "Tom" : { 76 | "hobbies" : [...], 77 | "age" : 68, 78 | "height" : 175 79 | }, 80 | "Robert" : { 81 | "running_records" : [...], 82 | "age" : 23, 83 | "hobbies" : [...], 84 | "height" : 181 85 | } 86 | } 87 | ``` 88 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Extensions/serializable-path-explorer.md: -------------------------------------------------------------------------------- 1 | # ``Scout/SerializablePathExplorer`` 2 | 3 | @Metadata { 4 | @DocumentationExtension(mergeBehavior: append) 5 | } 6 | 7 | ## Overview 8 | 9 | Protocol refining ``PathExplorer`` to offer features like conversion to another format or serialization. Explorers in ``PathExplorers`` implement this protocol. 10 | 11 | ## Topics 12 | 13 | ### Initializers 14 | 15 | - ``init(data:)`` 16 | - ``fromCSV(string:separator:hasHeaders:)`` 17 | 18 | ### Get format info 19 | 20 | - ``format`` 21 | 22 | ### Export as Data 23 | 24 | - ``exportData()`` 25 | - ``exportData(to:)`` 26 | - ``exportData(to:rootName:)`` 27 | 28 | ### Export as String 29 | 30 | - ``exportString()`` 31 | - ``exportString(to:)`` 32 | - ``exportString(to:rootName:)`` 33 | 34 | ### Export as CSV 35 | 36 | - ``exportCSV()`` 37 | - ``exportCSV(separator:)`` 38 | 39 | ### Export folded String 40 | 41 | - ``exportFoldedString(upTo:)`` 42 | - ``folded(upTo:)`` 43 | -------------------------------------------------------------------------------- /Sources/Scout/Scout.docc/Scout.md: -------------------------------------------------------------------------------- 1 | # ``Scout`` 2 | 3 | This library aims to make specific formats data values reading and writing simple when the data format is not known at build time. 4 | 5 | ## Overview 6 | 7 | Supported formats: 8 | - JSON 9 | - Plist 10 | - YAML 11 | - XML 12 | 13 | ## Topics 14 | 15 | ### Updates 16 | - 17 | 18 | ### Essential 19 | - 20 | - ``PathExplorer`` 21 | - ``Path`` 22 | 23 | ### Explore data 24 | 25 | - ``PathExplorer`` 26 | - ``PathExplorers`` 27 | - ``ExplorerValue`` 28 | - ``ExplorerError`` 29 | 30 | ### Manipulate paths 31 | 32 | - 33 | - 34 | - ``Path`` 35 | - ``PathElement`` 36 | - ``PathElementRepresentable`` 37 | - ``PathsFilter`` 38 | - ``ValuePredicate`` 39 | - ``Bounds`` 40 | 41 | ### Convert and export explorers 42 | 43 | - ``SerializablePathExplorer`` 44 | - ``DataFormat`` 45 | - ``CodablePathExplorer`` 46 | - ``CodableFormat`` 47 | - ``CodableFormats`` 48 | - ``ExplorerXML`` 49 | - ``SerializationError`` 50 | 51 | ### Set and add custom types 52 | 53 | - 54 | - ``ExplorerValueCreatable`` 55 | - ``ExplorerValueRepresentable`` 56 | - ``ExplorerValueConvertible`` 57 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/AdvancedTopicsDoc/AdvancedTopic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import ArgumentParser 8 | 9 | extension DocCommand { 10 | } 11 | 12 | enum AdvancedDocumentation { 13 | 14 | enum Topic: String, ExpressibleByArgument { 15 | case predicates 16 | 17 | var doc: String { 18 | switch self { 19 | case .predicates: return Predicates.text 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/CRUD/Add/AddCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | import Scout 8 | import ScoutCLTCore 9 | 10 | struct AddCommand: SADCommand { 11 | 12 | // MARK: - Constants 13 | 14 | static let configuration = CommandConfiguration( 15 | commandName: "add", 16 | abstract: "Add value at a given path", 17 | discussion: "To find examples and advanced explanations, please type `scout doc -c add`") 18 | 19 | // MARK: - Properties 20 | 21 | @Option(name: .dataFormat, help: .dataFormat) 22 | var dataFormat: Scout.DataFormat 23 | 24 | @Argument(help: PathAndValue.help) 25 | var pathsCollection = [PathAndValue]() 26 | 27 | @Option(name: .inputFilePath, help: .inputFilePath, completion: .file()) 28 | var inputFilePath: String? 29 | 30 | @Option(name: .outputFilePath, help: .outputFilePath, completion: .file()) 31 | var outputFilePath: String? 32 | 33 | @Option(name: .modifyFilePath, help: .modifyFilePath, completion: .file()) 34 | var modifyFilePath: String? 35 | 36 | @Flag(help: .colorise) 37 | var color = ColorFlag.color 38 | 39 | @Option(name: .fold, help: .fold) 40 | var level: Int? 41 | 42 | @Option(name: .csvSeparator, help: .csvSeparator) 43 | var csvSeparator: String? 44 | 45 | @Option(name: .export, help: .export) 46 | var exportFormat: ExportFormat? 47 | 48 | // MARK: - Functions 49 | 50 | func perform(pathExplorer: inout P, pathAndValue: PathAndValue) throws { 51 | let (path, value) = (pathAndValue.readingPath, pathAndValue.value) 52 | try pathExplorer.add(value, at: path) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/CRUD/Add/AddDocumentation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | import Lux 8 | 9 | enum AddDocumentation: Documentation { 10 | 11 | private static let examples = 12 | [(#"`scout add "Tom.hobbies[#]=Playing music"`"#, #"will add the hobby "Playing music" to Tom hobbies at the end of the array"#), 13 | (#"`scout add "Arnaud.hobbies[-1]=Playing music"`"#, #"will insert the hobby "Playing music" to Arnaud hobbies before the last hobby 'tennis'."#), 14 | (#"`scout add "Arnaud.hobbies[1]=reading"`"#, #"will insert the hobby "reading" to Arnaud hobbies between the hobby "video games" and "party""#), 15 | (#"`scout add "Franklin={}"`"#, #"will create a new empty dictionary at the key #Franklin#"#), 16 | (#"`scout add "Tom.colors=[]"`"#, #"will add a new empty #colors# array to Tom"#), 17 | (#"`scout add "Tom.score=/165/"`"#, #"will add a new #score# key to Tom with the String value "165""#)] 18 | 19 | static let text = 20 | """ 21 | 22 | ----------- 23 | Add command 24 | ----------- 25 | 26 | \(AddCommand.configuration.abstract) 27 | 28 | \(notesHeader) 29 | 30 | \(commonDoc) 31 | 32 | \(header: "Several paths") 33 | It's possible to add multiple values in one command by specifying several path/value pairs. 34 | 35 | \(header: "Keys creation") 36 | Only when a key is the last one in the path will it be created. When an index is specified as the last element of the path, 37 | the value to add will be inserted at the index location. 38 | 39 | \(header: "Append a value") 40 | To add a value at the end of an array, specify the '[#]' symbol rather than an index 41 | 42 | \(valueSpecificationDoc) 43 | 44 | \(examplesHeader) 45 | 46 | JSON file 47 | 48 | \(injectedJSONExample) 49 | 50 | \(examplesText(from: examples)) 51 | """ 52 | } 53 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/CRUD/Delete/DeleteCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | import Scout 8 | import ScoutCLTCore 9 | 10 | struct DeleteCommand: SADCommand { 11 | 12 | // MARK: - Constants 13 | 14 | static let configuration = CommandConfiguration( 15 | commandName: "delete", 16 | abstract: "Delete a value at a given path", 17 | discussion: "To find examples and advanced explanations, please type `scout doc -c delete-key`") 18 | 19 | // MARK: - Properties 20 | 21 | @Option(name: .dataFormat, help: .dataFormat) 22 | var dataFormat: Scout.DataFormat 23 | 24 | @Argument(help: "Paths to indicate the keys to be deleted") 25 | var pathsCollection = [Path]() 26 | 27 | @Option(name: .inputFilePath, help: .inputFilePath, completion: .file()) 28 | var inputFilePath: String? 29 | 30 | @Option(name: .outputFilePath, help: .outputFilePath, completion: .file()) 31 | var outputFilePath: String? 32 | 33 | @Option(name: .modifyFilePath, help: .modifyFilePath, completion: .file()) 34 | var modifyFilePath: String? 35 | 36 | @Flag(help: .colorise) 37 | var color = ColorFlag.color 38 | 39 | @Option(name: .fold, help: .fold) 40 | var level: Int? 41 | 42 | @Flag(name: [.short, .long], help: "When the deleted value leaves the array or dictionary holding it empty, delete it too") 43 | var recursive = false 44 | 45 | @Option(name: .csvSeparator, help: .csvSeparator) 46 | var csvSeparator: String? 47 | 48 | @Option(name: .export, help: .export) 49 | var exportFormat: ExportFormat? 50 | 51 | // MARK: - Functions 52 | 53 | func perform(pathExplorer: inout P, pathAndValue: Path) throws { 54 | try pathExplorer.delete(pathAndValue, deleteIfEmpty: recursive) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/CRUD/Delete/DeleteDocumentation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | import Lux 8 | 9 | enum DeleteDocumentation: Documentation { 10 | 11 | static let recursive = zshInjector.delegate.inject(.optionNameOrFlag, in: .terminal, "-r") 12 | 13 | private static let examples = 14 | [(#"`scout delete "Tom.height"`"#, #"will delete Tom height"#), 15 | (#"`scout delete "Tom.hobbies[0]"`"#, #"will delete Tom first hobby"#), 16 | (#"`scout delete "Tom.hobbies[-1]"`"#, #"will delete Tom last hobby"#), 17 | (#"`scout delete "Arnaud.#h.*#"`"#, #"will delete Arnaud's height and hobbies"#), 18 | (#"`scout delete "Arnaud.hobbies[-2:]"`"#, #"will delete Arnaud's last two hobbies"#), 19 | (##"`scout delete "#.*#.hobbies[:1]`""##, #"will delete Tom's and Arnaud's first two hobbies"#), 20 | (##"`scout delete -r "#.*#.hobbies[:1]"`"##, #"will delete Arnaud's first two hobbies and Tom hobbies"#), 21 | (#"`scout delete "Tom.height -e plist"`"#, #"will delete Tom height and convert the modified data to a Plist format"#)] 22 | 23 | static let text = 24 | """ 25 | 26 | -------------- 27 | Delete command 28 | -------------- 29 | 30 | \(DeleteCommand.configuration.abstract) 31 | 32 | \(notesHeader) 33 | 34 | \(commonDoc) 35 | 36 | \(header: "Several paths") 37 | It's possible to set multiple values in one command by specifying several path/value pairs. 38 | 39 | \(header: "Delete if empty") 40 | Use the flag \(recursive) to delete an array or a dictionary key when left empty 41 | 42 | \(slicingAndFilteringDoc) 43 | 44 | \(miscDoc) 45 | 46 | \(examplesHeader) 47 | 48 | JSON file 49 | 50 | \(injectedJSONExample) 51 | 52 | \(examplesText(from: examples)) 53 | """ 54 | } 55 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/CRUD/Read/ReadDocumentation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | 8 | enum ReadDocumentation: Documentation { 9 | 10 | private static let examples = 11 | [(#"`scout read "Tom.hobbies[0]"`"#, #"will output Tom first hobby "cooking""#), 12 | (#"`scout read "Arnaud.height"`"#, #"will output Arnaud's height "180""#), 13 | (#"`scout read "Tom.hobbies[-1]"`"#, #"will output Tom last hobby: "guitar""#), 14 | (#"`scout read "Tom"`"#, #"will output Tom dictionary"#), 15 | (#"`scout read "[#]"`"#, #"will output the people count: 2"#), 16 | (#"`scout read "Arnaud.hobbies[#]"`"#, #"will output Arnaud's hobbies count: 3"#), 17 | (#"`scout read "Arnaud.#h.*#"`"#, #"will output Arnaud's height and hobbies"#), 18 | (#"`scout read "Arnaud.hobbies[1:]"`"#, #"will output Arnaud's last two hobbies"#), 19 | (#"`scout read "Arnaud.hobbies[-2:]"`"#, #"will output Arnaud's last two hobbies"#), 20 | (##"`scout read "#.*#.hobbies[:1]"`"##, #"will output Tom's and Arnaud's first two hobbies"#), 21 | (##"`scout read "#.*#.hobbies[#]"`"##, #"will output Tom's and Arnaud's hobbies count"#), 22 | (#"`scout read "Tom.hobbies[:]" --csv-exp ";"`"#, #"will ouput Tom hobbies as CSV"#), 23 | (#"`scout read -i People.json -f json -e yaml`"#, #"will convert the JSON file to YAML"#)] 24 | 25 | static let text = 26 | """ 27 | 28 | ------------ 29 | Read command 30 | ------------ 31 | 32 | \(ReadCommand.configuration.abstract) 33 | 34 | Notes 35 | ===== 36 | 37 | \(commonDoc) 38 | 39 | \(header: "Count/Keys symbols") 40 | - Get a dictionary or an array count with the '[#]' symbol. 41 | - List the keys of a dictionary with the '{#}' symbol. 42 | 43 | \(slicingAndFilteringDoc) 44 | 45 | \(miscDoc) 46 | 47 | \(examplesHeader) 48 | 49 | JSON file 50 | 51 | \(injectedJSONExample) 52 | 53 | \(examplesText(from: examples)) 54 | """ 55 | } 56 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/CRUD/Set/SetCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | import Scout 8 | import ScoutCLTCore 9 | 10 | struct SetCommand: SADCommand { 11 | 12 | // MARK: - Constants 13 | 14 | static let configuration = CommandConfiguration( 15 | commandName: "set", 16 | abstract: "Change a value at a given path.", 17 | discussion: "To find examples and advanced explanations, please type `scout doc -c set`") 18 | 19 | // MARK: - Properties 20 | 21 | @Option(name: .dataFormat, help: .dataFormat) 22 | var dataFormat: Scout.DataFormat 23 | 24 | @Argument(help: PathAndValue.help) 25 | var pathsCollection = [PathAndValue]() 26 | 27 | @Option(name: .inputFilePath, help: .inputFilePath, completion: .file()) 28 | var inputFilePath: String? 29 | 30 | @Option(name: .outputFilePath, help: .outputFilePath, completion: .file()) 31 | var outputFilePath: String? 32 | 33 | @Option(name: .modifyFilePath, help: .modifyFilePath, completion: .file()) 34 | var modifyFilePath: String? 35 | 36 | @Flag(help: .colorise) 37 | var color = ColorFlag.color 38 | 39 | @Option(name: .fold, help: .fold) 40 | var level: Int? 41 | 42 | @Option(name: .csvSeparator, help: .csvSeparator) 43 | var csvSeparator: String? 44 | 45 | @Option(name: .export, help: .export) 46 | var exportFormat: ExportFormat? 47 | 48 | // MARK: - Functions 49 | 50 | func perform(pathExplorer: inout P, pathAndValue: PathAndValue) throws { 51 | let (path, value) = (pathAndValue.readingPath, pathAndValue.value) 52 | 53 | if case let .keyName(keyName) = value { 54 | try pathExplorer.set(path, keyNameTo: keyName) 55 | } else { 56 | try pathExplorer.set(path, to: value) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/ColorDelegates/ColorFile.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | struct JsonColors: Codable { 7 | var punctuation: Int? 8 | var keyName: Int? 9 | var keyValue: Int? 10 | } 11 | 12 | struct YamlColors: Codable { 13 | var punctuation: Int? 14 | var keyName: Int? 15 | var keyValue: Int? 16 | } 17 | 18 | struct PlistColors: Codable { 19 | var tag: Int? 20 | var keyName: Int? 21 | var keyValue: Int? 22 | var header: Int? 23 | var comment: Int? 24 | } 25 | 26 | struct XmlColors: Codable { 27 | var punctuation: Int? 28 | var openingTag: Int? 29 | var closingTag: Int? 30 | var key: Int? 31 | var header: Int? 32 | var comment: Int? 33 | } 34 | 35 | /// Plist file to specify custom colors 36 | struct ColorFile: Codable { 37 | var json: JsonColors? 38 | var yaml: YamlColors? 39 | var plist: PlistColors? 40 | var xml: XmlColors? 41 | } 42 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/ColorDelegates/JSONInjectorDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Lux 7 | 8 | final class JSONInjectorColorDelegate: JSONDelegate { 9 | 10 | // MARK: - Properties 11 | 12 | let colors: JsonColors 13 | 14 | // MARK: - Initialisation 15 | 16 | init(colors: JsonColors) { 17 | self.colors = colors 18 | } 19 | 20 | required init() { 21 | colors = JsonColors() 22 | super.init() 23 | } 24 | 25 | // MARK: - Functions 26 | 27 | override func terminalModifier(for category: JSONCategory) -> TerminalModifier { 28 | var colorCode: Int? 29 | 30 | // retrieve the color code in the colors plist if any 31 | switch category { 32 | case .punctuation: colorCode = colors.punctuation 33 | case .keyName: colorCode = colors.keyName 34 | case .keyValue: colorCode = colors.keyValue 35 | } 36 | 37 | if let code = colorCode { 38 | return TerminalModifier(colorCode: code) 39 | } else { 40 | return super.terminalModifier(for: category) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/ColorDelegates/PlistInjectorColorDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Lux 7 | 8 | final class PlistInjectorColorDelegate: PlistDelegate { 9 | 10 | // MARK: - Properties 11 | 12 | let colors: PlistColors 13 | 14 | // MARK: - Initialisation 15 | 16 | init(colors: PlistColors) { 17 | self.colors = colors 18 | } 19 | 20 | required init() { 21 | colors = PlistColors() 22 | super.init() 23 | } 24 | 25 | // MARK: - Functions 26 | 27 | override func terminalModifier(for category: PlistCategory) -> TerminalModifier { 28 | var colorCode: Int? 29 | 30 | switch category { 31 | case .tag: colorCode = colors.tag 32 | case .keyName: colorCode = colors.keyName 33 | case .keyValue: colorCode = colors.keyValue 34 | case .comment: colorCode = colors.comment 35 | case .header: colorCode = colors.header 36 | } 37 | 38 | if let code = colorCode { 39 | return TerminalModifier(colorCode: code) 40 | } else { 41 | return super.terminalModifier(for: category) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/ColorDelegates/XMLInjectorColorDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Lux 7 | 8 | final class XMLInjectorColorDelegate: XMLEnhancedDelegate { 9 | 10 | // MARK: - Properties 11 | 12 | let colors: XmlColors 13 | 14 | // MARK: - Initialisation 15 | 16 | init(colors: XmlColors) { 17 | self.colors = colors 18 | } 19 | 20 | required init() { 21 | colors = XmlColors() 22 | super.init() 23 | } 24 | 25 | // MARK: - Functions 26 | 27 | override func terminalModifier(for category: XMLEnhancedCategory) -> TerminalModifier { 28 | var colorCode: Int? 29 | 30 | switch category { 31 | case .openingTag: colorCode = colors.openingTag 32 | case .closingTag: colorCode = colors.closingTag 33 | case .punctuation: colorCode = colors.punctuation 34 | case .key: colorCode = colors.key 35 | case .comment: colorCode = colors.comment 36 | case .header: colorCode = colors.header 37 | } 38 | 39 | if let code = colorCode { 40 | return TerminalModifier(colorCode: code) 41 | } else { 42 | return super.terminalModifier(for: category) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/ColorDelegates/YAMLInjectorColorDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Lux 7 | 8 | final class YAMLInjectorColorDelegate: YAMLDelegate { 9 | 10 | // MARK: - Properties 11 | 12 | let colors: YamlColors 13 | 14 | // MARK: - Initialisation 15 | 16 | init(colors: YamlColors) { 17 | self.colors = colors 18 | } 19 | 20 | required init() { 21 | colors = YamlColors() 22 | super.init() 23 | } 24 | 25 | // MARK: - Functions 26 | 27 | override func terminalModifier(for category: YAMLCategory) -> TerminalModifier { 28 | var colorCode: Int? 29 | 30 | // retrieve the color code in the colors plist if any 31 | switch category { 32 | case .punctuation: colorCode = colors.punctuation 33 | case .keyName: colorCode = colors.keyName 34 | case .keyValue: colorCode = colors.keyValue 35 | } 36 | 37 | if let code = colorCode { 38 | return TerminalModifier(colorCode: code) 39 | } else { 40 | return super.terminalModifier(for: category) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/ArgumentHelp+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | 8 | extension ArgumentHelp { 9 | 10 | static var readingPath: ArgumentHelp { 11 | ArgumentHelp( 12 | "Path in the data where to read the key value", 13 | discussion: """ 14 | A path is a sequence of keys separated with dots to navigate through the data. 15 | A dot '.' is used to subscript a dictionary. For example 'dictionary.key'. 16 | An integer enclosed by square brakets '[1]' is used to subscript an array. For example 'array[5]'. 17 | """) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/ArgumentParserConformance/DataFormat+ArgumentParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Scout 7 | import ArgumentParser 8 | 9 | extension DataFormat: ExpressibleByArgument { 10 | 11 | public var defaultValueDescription: String { "The data format to read the input" } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/ArgumentParserConformance/ExportFormat+ArgumentParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ScoutCLTCore 7 | import ArgumentParser 8 | 9 | extension ExportFormat: ExpressibleByArgument {} 10 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/ArgumentParserConformance/ParsableCommand+PathCompletion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import Scout 8 | 9 | /// A PathExplorer without the Self requirement to try to get a path. 10 | protocol PathExplorerGet { 11 | func tryToGet(_ path: Path) throws 12 | } 13 | 14 | extension CodablePathExplorer: PathExplorerGet { 15 | func tryToGet(_ path: Path) throws { 16 | _ = try get(path) 17 | } 18 | } 19 | 20 | extension ExplorerXML: PathExplorerGet { 21 | func tryToGet(_ path: Path) throws { 22 | _ = try get(path) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/ArgumentParserConformance/PathAndValue+ArgumentParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ScoutCLTCore 7 | import ArgumentParser 8 | 9 | private let _abstract = 10 | """ 11 | 12 | 13 | \(header: "Value specification") 14 | 15 | Specify a path with an associated value. 16 | Like "firstKey.secondKey[index].thirdKey=value". 17 | 18 | The following notes indicates how to specify the value. 19 | 20 | \(subheader: "Automatic") 21 | Let Scout automatically infer the type. 22 | Ex: 123 will be treated as an integer, and Endo as a string. 23 | 24 | \(subheader: "String") 25 | Force the specified value to be a string. 26 | Usage: enclose the value with single quotes 'value' or slash /value/. 27 | 28 | \(subheader: "Real") 29 | Force the specified value to be a real (Plist only). 30 | Usage: enclose the value with tildes: ~value~. 31 | 32 | \(subheader: "Array") 33 | Usage: enclose with square brackets a list of values and separate them with commas ','. 34 | Use single quote to specify strings with commas. 35 | It's possible to nest arrays or dictionaries. 36 | 37 | Examples 38 | ```````` 39 | [Endo, 'String, with a comma', 123, ~40~] 40 | [Endo, [values, in, nested, array]] 41 | 42 | \(subheader: "Dictionary") 43 | Usage: enclose with curl brackets a list of (key, value) pairs separated with a double point ':' and separate them with commas ','. 44 | Use single quote to specify strings with commas or a key with a commas. 45 | It's possible to nest dictionaries or arrays. 46 | 47 | Examples 48 | ```````` 49 | {Riri: 20, Fifi: duck, Loulou: '60'} 50 | ducks: {Riri, Fifi, Loulou}, mouses: {Mickey: 20, Minnie: 30}} 51 | 52 | """ 53 | 54 | extension PathAndValue: ExpressibleByArgument { 55 | 56 | static var abstract: String { _abstract } 57 | 58 | static var help: ArgumentHelp { ArgumentHelp(abstract, valueName: "path=value") } 59 | 60 | public init?(argument: String) { 61 | self.init(string: argument) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/FileHandle+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension FileHandle { 9 | 10 | /// `true` is the file handle is piped 11 | /// 12 | /// For example on the standard output, this allows to know whether the output is piped or printed in the terminal 13 | /// - note: I think it's O(1) but I cant find any documentation on `isatty()` 14 | var isPiped: Bool { isatty(fileDescriptor) == 0 } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/Optional+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Optional { 9 | 10 | func unwrapOrThrow(error: Error) throws -> Wrapped { 11 | guard let wrapped = self else { 12 | throw error 13 | } 14 | return wrapped 15 | } 16 | 17 | func unwrapOrThrow(_ error: RuntimeError) throws -> Wrapped { 18 | try unwrapOrThrow(error: error) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Extensions/Path+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Scout 7 | import ArgumentParser 8 | import Foundation 9 | 10 | extension Path: ExpressibleByArgument { 11 | 12 | public init?(argument: String) { 13 | try? self.init(string: argument) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Main/CommandsRecords.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | 8 | extension NameSpecification { 9 | 10 | static let dataFormat: NameSpecification = [.customShort("f", allowingJoined: true), .customLong("format")] 11 | static let inputFilePath: NameSpecification = [.short, .customLong("input")] 12 | static let outputFilePath: NameSpecification = [.short, .customLong("output")] 13 | static let modifyFilePath: NameSpecification = [.short, .customLong("modify")] 14 | static let fold: NameSpecification = [.short, .long] 15 | static let csvSeparator: NameSpecification = [.customLong("csv-export")] 16 | static let export: NameSpecification = [.short, .customLong("export")] 17 | } 18 | 19 | extension ArgumentHelp { 20 | 21 | static let dataFormat = ArgumentHelp("The data format of the input") 22 | static let inputFilePath = ArgumentHelp("A file path from which to read the data") 23 | static let outputFilePath = ArgumentHelp("Write the modified data into the file at the given path") 24 | static let modifyFilePath = ArgumentHelp("Read and write the data into the same file at the given path") 25 | static let colorise = ArgumentHelp("Highlight the output. --no-color or --nc to prevent it") 26 | static let fold = ArgumentHelp("Fold the data at the given depth level") 27 | static let csvSeparator = ArgumentHelp("Convert the array data into CSV with the given separator") 28 | static let export = ArgumentHelp("Convert the data to the specified format") 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Main/ScoutMainCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | import Scout 8 | 9 | private let abstract = 10 | """ 11 | Read and modify values in specific format file or data. Currently supported: Json, Plist, YAML and Xml. 12 | """ 13 | 14 | private let discussion = 15 | """ 16 | To find advanced help and rich examples, please type `scout doc`. 17 | 18 | 19 | Written by Alexis Bridoux. Copyright (c) 2020-present. 20 | \u{001B}[38;5;88mhttps://www.woodys-findings.com/scout\u{001B}[0;0m 21 | MIT license, see LICENSE file for details 22 | """ 23 | 24 | @main 25 | struct ScoutMainCommand: ParsableCommand { 26 | 27 | // MARK: - Constants 28 | 29 | static let configuration = CommandConfiguration( 30 | commandName: "scout", 31 | abstract: abstract, 32 | discussion: discussion, 33 | version: ScoutVersion.current, 34 | subcommands: [ 35 | ReadCommand.self, 36 | SetCommand.self, 37 | DeleteCommand.self, 38 | AddCommand.self, 39 | DocCommand.self, 40 | PathsCommand.self, 41 | CSVCommand.self, 42 | InstallCompletionScriptCommand.self], 43 | defaultSubcommand: ReadCommand.self) 44 | } 45 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Models/ColorFlag.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import ArgumentParser 8 | 9 | enum ColorFlag: String, EnumerableFlag { 10 | 11 | /// Specify to colorise the output. Prevented if the program is piped. 12 | case color 13 | 14 | /// Force the colorisation whether the program is piped or not 15 | case forceColor 16 | 17 | /// Specify to not colorise the output 18 | case noColor 19 | 20 | /// Specify to not colorise the output 21 | case nc 22 | 23 | var colorise: Bool { 24 | switch self { 25 | case .color, .forceColor: return true 26 | case .noColor, .nc: return false 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Models/Command.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import ArgumentParser 7 | 8 | enum Command: String, ExpressibleByArgument, CaseIterable { 9 | case read, set, delete, add, paths 10 | 11 | static var documentationDescription: String { 12 | "\(Self.read.rawValue.mainColor), \(Self.set.rawValue.mainColor), \(Self.delete.rawValue.mainColor) and \(Self.add.rawValue.mainColor)" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Models/PathExplorer+Alias.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Scout 7 | 8 | typealias Xml = PathExplorers.Xml 9 | typealias Json = CodablePathExplorer 10 | typealias Plist = PathExplorers.Plist 11 | typealias Yaml = PathExplorers.Yaml 12 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Models/RuntimeError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | enum RuntimeError: LocalizedError { 9 | case invalidData(String) 10 | case dataToString 11 | case noValueAt(path: String) 12 | case unknownFormat(String) 13 | case completionScriptInstallation(description: String) 14 | case invalidRegex(String) 15 | case invalidArgumentsCombination(description: String) 16 | case valueConversion(value: String, type: String) 17 | case custom(String) 18 | 19 | var errorDescription: String? { 20 | switch self { 21 | case .invalidData(let description): return description 22 | case .dataToString: return "The input data cannot be converted to UTF-8 String" 23 | case .noValueAt(let path): return "No value at '\(path)'" 24 | case .unknownFormat(let description): return description 25 | case .completionScriptInstallation(let description): return "Error while installing the completion script. \(description)" 26 | case .invalidRegex(let pattern): return "The regular expression '\(pattern)' is invalid" 27 | case .invalidArgumentsCombination(let description): return description 28 | case .valueConversion(let value, let type): return "The value \(value) is not convertible to \(type)" 29 | case .custom(let description): return description 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/ScoutCLT/Models/ValidationError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | struct ValidationError: LocalizedError { 9 | 10 | var message: String 11 | 12 | var errorDescription: String? { message } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Extensions/Collection+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension Collection where Element: Hashable { 9 | 10 | /// Find a duplicate in the collection. 11 | /// 12 | /// ### Complexity 13 | /// `O(n)` 14 | func duplicate() -> Element? { 15 | var foundElements: Set = [] 16 | 17 | for element in self { 18 | if foundElements.contains(element) { 19 | return element 20 | } else { 21 | foundElements.insert(element) 22 | } 23 | } 24 | return nil 25 | } 26 | } 27 | 28 | extension Dictionary where Key: Hashable { 29 | 30 | /// Find a duplicate in the collection. 31 | /// 32 | /// ### Complexity 33 | /// `O(n)` 34 | func duplicateKey() -> Key? { 35 | var foundElements: Set = [] 36 | 37 | for element in self { 38 | if foundElements.contains(element.key) { 39 | return element.key 40 | } else { 41 | foundElements.insert(element.key) 42 | } 43 | } 44 | return nil 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Extensions/ExplorerValue+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import Scout 8 | 9 | extension ExplorerValue { 10 | 11 | init(fromSingle string: String) { 12 | if let int = Int(string) { 13 | self = .int(int) 14 | } else if let double = Double(string) { 15 | self = .double(double) 16 | } else if let bool = Bool(string) { 17 | self = .bool(bool) 18 | } else { 19 | self = .string(string) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Extensions/URL+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension URL { 9 | 10 | var lastPathComponentWithoutExtension: String { 11 | let splitted = lastPathComponent.split(separator: ".") 12 | 13 | guard splitted.count > 1 else { 14 | return lastPathComponent 15 | } 16 | 17 | return String(splitted[splitted .count - 2]) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Models/CLTCoreError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | public enum CLTCoreError: LocalizedError { 9 | 10 | case exportConflict 11 | case valueConversion(value: String, type: String) 12 | case wrongUsage(String) 13 | 14 | public var errorDescription: String? { 15 | switch self { 16 | case .exportConflict: return "Ambiguous export specification. '--csv-exp' and --export-format' cannot be used simultaneously" 17 | case .valueConversion(let value, let type): return "The value '\(value)' is not convertible to \(type)" 18 | case .wrongUsage(let description): return description 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Models/ExportCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import Scout 8 | 9 | public enum Export: Equatable { 10 | case noExport 11 | case csv(separator: String) 12 | case dataFormat(format: DataFormat) 13 | case array 14 | case dictionary 15 | } 16 | 17 | public protocol ExportCommand { 18 | var csvSeparator: String? { get } 19 | var exportFormat: ExportFormat? { get } 20 | } 21 | 22 | public extension ExportCommand { 23 | 24 | /// Returns the export option specified depending on several inputs: csv, data format, Zsh group values 25 | func exportOption() throws -> Export { 26 | switch (csvSeparator, exportFormat) { 27 | case (let separator?, nil): return .csv(separator: separator) 28 | case (nil, let format?): 29 | switch format { 30 | case .array: return .array 31 | case .dictionary: return .dictionary 32 | case .json: return .dataFormat(format: .json) 33 | case .plist: return .dataFormat(format: .plist) 34 | case .yaml: return .dataFormat(format: .yaml) 35 | case .xml: return .dataFormat(format: .xml) 36 | } 37 | case (nil, nil): return .noExport 38 | case (.some, .some): throw CLTCoreError.exportConflict 39 | } 40 | } 41 | 42 | /// Get the file name of the file path 43 | func fileName(of filePath: String?) -> String? { 44 | guard let filePath = filePath else { return nil } 45 | return URL(fileURLWithPath: filePath).lastPathComponentWithoutExtension 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Models/ExportFormat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Scout 7 | 8 | /// Models the value the export process can take 9 | public enum ExportFormat: String, CaseIterable, Equatable { 10 | case json, plist, yaml, xml, array, dictionary 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Models/GroupExportValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import Scout 8 | 9 | /// Type serving only the purpose to map dictionaries or arrays 10 | /// returned by a `PathExplorer` to a `String` value. 11 | public struct GroupExportValue: ExplorerValueCreatable { 12 | 13 | public let value: String 14 | 15 | /// - throws: if the value is not single. 16 | public init(from explorerValue: ExplorerValue) throws { 17 | switch explorerValue { 18 | case .string(let string): value = string 19 | case .int(let int): value = int.description 20 | case .double(let double): value = double.description 21 | case .bool(let bool): value = bool.description 22 | case .data(let data): value = data.base64EncodedString() 23 | case .date(let date): value = date.description 24 | case .dictionary: throw CLTCoreError.wrongUsage("Trying to export a dictionary of values that are not single") 25 | case .array: throw CLTCoreError.wrongUsage("Trying to export an array of values that are not single") 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ScoutCLTCore/Models/PathAndValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | import Scout 7 | 8 | /// Represents a reading path and an associated value, like `path.component[0]=value`. 9 | /// 10 | /// ### Forcing a type 11 | /// The `value` property can be forced to be a string or a double when the automatic type inferring will return another type. 12 | /// For instance with "123", the value will be treated as an `Int`, so specifying `string` rather than `automatic` prevents that. 13 | /// 14 | public struct PathAndValue { 15 | 16 | // MARK: - Properties 17 | 18 | public let readingPath: Path 19 | public let value: ValueType 20 | 21 | public init?(string: String) { 22 | guard 23 | let result = Self.parser.run(string) 24 | else { return nil } 25 | 26 | if let error = result.result.value.firstError { 27 | print("An error occurred while parsing the argument '\(string)'") 28 | print(error) 29 | return nil 30 | } 31 | 32 | guard result.remainder.isEmpty else { 33 | return nil 34 | } 35 | 36 | readingPath = Path(elements: result.result.pathElements) 37 | value = result.result.value 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/ScoutCLTCoreTests/ExportCommandTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | import Scout 8 | import ScoutCLTCore 9 | 10 | final class ExportCommandTests: XCTestCase { 11 | 12 | func testExportCSVSeparator() throws { 13 | var command = StubCommand() 14 | command.csvSeparator = "/" 15 | 16 | XCTAssertEqual(try command.exportOption(), .csv(separator: "/")) 17 | } 18 | 19 | func testExportDataFormat() throws { 20 | var command = StubCommand() 21 | command.exportFormat = .plist 22 | 23 | XCTAssertEqual(try command.exportOption(), .dataFormat(format: .plist)) 24 | } 25 | 26 | func testExportCSVAndDataFormatThrows() throws { 27 | var command = StubCommand() 28 | command.csvSeparator = ";" 29 | command.exportFormat = .plist 30 | 31 | XCTAssertThrowsError(try command.exportOption()) 32 | } 33 | } 34 | 35 | extension ExportCommandTests { 36 | 37 | struct StubCommand: ExportCommand { 38 | var csvSeparator: String? 39 | var exportFormat: ExportFormat? 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tests/ScoutTests/Definitions/Path/PathTests+Miscellaneous.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import Scout 8 | import XCTest 9 | 10 | final class PathMiscellanousTests: XCTestCase { 11 | 12 | func testCommonPrefix_Middle() { 13 | let path = Path(elements: "toto", 1, "Endo", .count) 14 | let otherPath = Path(elements: "toto", 1, "Endo") 15 | 16 | let intersection = path.commonPrefix(with: otherPath) 17 | 18 | XCTAssertEqual(Path(path[0...2]), Path(intersection)) 19 | } 20 | 21 | func testCommonPrefix_Empty() { 22 | let path = Path(elements: "toto", 1, "Endo", .count) 23 | let otherPath = Path(elements: "Riri", "Fifi", "Loulou") 24 | 25 | let intersection = path.commonPrefix(with: otherPath) 26 | 27 | XCTAssertEqual(Path.empty, Path(intersection)) 28 | } 29 | 30 | func testCommonPrefix_All() { 31 | let path = Path(elements: "toto", 1, "Endo", .count) 32 | let otherPath = Path(elements: "toto", 1, "Endo", .count) 33 | 34 | let intersection = path.commonPrefix(with: otherPath) 35 | 36 | XCTAssertEqual(path, Path(intersection)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Tests/ScoutTests/ExplorerXML/PathExplorerXMLTests+COW.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | import AEXML 8 | @testable import Scout 9 | import XCTest 10 | 11 | final class ExplorerXMLCOWTests: XCTestCase { 12 | 13 | func testSet() throws { 14 | let explorer = ExplorerXML(value: ["Endo": true, "Toto": 20]) 15 | var copy = explorer 16 | 17 | try copy.set("Endo", to: false) 18 | 19 | XCTAssertEqual(explorer.explorerValue(), ["Endo": true, "Toto": 20]) 20 | XCTAssertEqual(copy.explorerValue(), ["Endo": false, "Toto": 20]) 21 | } 22 | 23 | func testDelete() throws { 24 | let explorer = ExplorerXML(value: ["Endo": true, "Toto": 20]) 25 | var copy = explorer 26 | 27 | try copy.delete("Toto") 28 | 29 | XCTAssertEqual(explorer.explorerValue(), ["Endo": true, "Toto": 20]) 30 | try XCTAssertEqual(copy.dictionary(of: Bool.self), ["Endo": true]) 31 | } 32 | 33 | func testAdd() throws { 34 | let explorer = ExplorerXML(value: ["Endo": true, "Toto": 20]) 35 | var copy = explorer 36 | 37 | try copy.add("Riri", at: "duck") 38 | 39 | XCTAssertEqual(explorer.explorerValue(), ["Endo": true, "Toto": 20]) 40 | XCTAssertEqual(copy.explorerValue(), ["Endo": true, "Toto": 20, "duck": "Riri"]) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/ScoutTests/Extensions/PathExplorers+Alias.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import Scout 7 | 8 | typealias Xml = PathExplorers.Xml 9 | typealias Json = PathExplorers.Json 10 | typealias Plist = PathExplorers.Plist 11 | typealias Yaml = PathExplorers.Yaml 12 | -------------------------------------------------------------------------------- /Tests/ScoutTests/Extensions/URL+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import Foundation 7 | 8 | extension URL { 9 | 10 | private static let peopleURL: URL = { 11 | /**https://stackoverflow.com/questions/57555856/get-url-to-a-local-file-with-spm-swift-package-manager/57708634#57708634 */ 12 | let currentFileURL = URL(fileURLWithPath: "\(#file)", isDirectory: false) 13 | return currentFileURL 14 | .deletingLastPathComponent() 15 | .deletingLastPathComponent() 16 | .deletingLastPathComponent() 17 | .deletingLastPathComponent() 18 | .appendingPathComponent("Playground", isDirectory: true) 19 | .appendingPathComponent("People") 20 | }() 21 | 22 | static let peopleJson: URL = { Self.peopleURL.appendingPathExtension("json") }() 23 | static let peoplePlist: URL = { Self.peopleURL.appendingPathExtension("plist") }() 24 | static let peopleXml: URL = { Self.peopleURL.appendingPathExtension("xml") }() 25 | } 26 | -------------------------------------------------------------------------------- /Tests/ScoutTests/Extensions/XCTestCase+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | @testable import Scout 8 | 9 | extension XCTestCase { 10 | 11 | func XCTAssertErrorsEqual(_ expression: @autoclosure () throws -> T, 12 | _ expectedError: ExplorerError, 13 | file: StaticString = #file, line: UInt = #line) { 14 | XCTAssertThrowsError( 15 | _ = try expression(), "", file: file, line: line) { error in 16 | guard 17 | let resultPathExplorerError = error as? ExplorerError, 18 | resultPathExplorerError == expectedError 19 | else { 20 | XCTFail("The expression did not throw the error \(expectedError). Error thrown: \(error)", file: file, line: line) 21 | return 22 | } 23 | } 24 | } 25 | 26 | func XCTAssertExplorersEqual( 27 | _ p1: @autoclosure () throws -> P, 28 | _ p2: @autoclosure () throws -> P, 29 | file: StaticString = #file, line: UInt = #line) rethrows { 30 | let p1 = try p1() 31 | let p2 = try p2() 32 | 33 | XCTAssertTrue(p1.isEqual(to: p2), "\(p1) not equal to \(p2)", file: file, line: line) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/ScoutTests/ExtensionsTests/ArrayTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | @testable import Scout 8 | 9 | final class ArrayExtensionsTests: XCTestCase {} 10 | 11 | // MARK: - Delete range 12 | 13 | extension ArrayExtensionsTests { 14 | 15 | // MARK: Stubs 16 | 17 | var stubArray: [String] { ["Riri", "Fifi", "Loulou", "Scrooge", "Donald", "Daisy"] } 18 | 19 | // MARK: Tests 20 | 21 | func testDeleteRange1() throws { 22 | let range = 2...4 23 | 24 | XCTAssertEqual(stubArray.remove(in: range), ["Riri", "Fifi", "Daisy"]) 25 | } 26 | 27 | func testDeleteRange2() throws { 28 | let range = 2...5 29 | 30 | XCTAssertEqual(stubArray.remove(in: range), ["Riri", "Fifi"]) 31 | } 32 | 33 | func testDeleteRange3() throws { 34 | let range = 0...3 35 | 36 | XCTAssertEqual(stubArray.remove(in: range), ["Donald", "Daisy"]) 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Tests/ScoutTests/ExtensionsTests/NSRegularExpressionExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | @testable import Scout 8 | 9 | final class NSRegularExpressionExtensionsTests: XCTestCase { 10 | 11 | func testValidate1() throws { 12 | let pattern = "[0-9]+" 13 | let regex = try NSRegularExpression(pattern: pattern) 14 | 15 | XCTAssertTrue(regex.validate("1234")) 16 | XCTAssertFalse(regex.validate("123A4")) 17 | } 18 | 19 | func testValidate2() throws { 20 | let pattern = #"[a-zA-Z]+\s+[0-9]+"# 21 | let regex = try NSRegularExpression(pattern: pattern) 22 | 23 | XCTAssertTrue(regex.validate("John 117")) 24 | XCTAssertFalse(regex.validate("Arbiter")) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tests/ScoutTests/ExtensionsTests/PathExplorerHelperTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) 2020-present Alexis Bridoux 4 | // MIT license, see LICENSE file for details 5 | 6 | @testable import Scout 7 | import XCTest 8 | 9 | final class PathExplorerHelpersTest: XCTestCase { 10 | 11 | func testComputeIndex_PositiveIndex() throws { 12 | let result = try PathExplorers.Json.computeIndex(from: 5, arrayCount: 10) 13 | 14 | XCTAssertEqual(result, 5) 15 | } 16 | 17 | func testComputeIndex_NegativeIndex() throws { 18 | let result = try PathExplorers.Json.computeIndex(from: -3, arrayCount: 10) 19 | 20 | XCTAssertEqual(result, 7) 21 | } 22 | 23 | func testComputeIndex_EmptyArray_PositiveIndexThrows() throws { 24 | XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 1, arrayCount: 0), 25 | .wrong(index: 1, arrayCount: 0)) 26 | } 27 | 28 | func testComputeIndex_EmptyArray_NegativeIndexThrows() throws { 29 | XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: -1, arrayCount: 0), 30 | .wrong(index: -1, arrayCount: 0)) 31 | } 32 | 33 | func testComputeIndex_EmptyArray_ZeroIndexThrows() throws { 34 | XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 0, arrayCount: 0), 35 | .wrong(index: 0, arrayCount: 0)) 36 | } 37 | 38 | func testComputeIndex_SingleElementArray_PositiveIndexThrows() throws { 39 | XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 1, arrayCount: 1), 40 | .wrong(index: 1, arrayCount: 1)) 41 | } 42 | 43 | func testComputeIndex_SingleElementArray_NegativeIndex() throws { 44 | let result = try PathExplorers.Json.computeIndex(from: -1, arrayCount: 1) 45 | 46 | XCTAssertEqual(result, 0) 47 | } 48 | 49 | func testComputeIndex_OutOfBounds_PositiveIndexThrows() throws { 50 | XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 5, arrayCount: 4), 51 | .wrong(index: 5, arrayCount: 4)) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Tests/ScoutTests/ExtensionsTests/String+Jaro-WinklerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | @testable import Scout 8 | 9 | final class String_JaroWinklerTests: XCTestCase { 10 | 11 | let target = "verson" 12 | let propositions: Set = ["tag", "date", "name", "owner", "release", "version", "forest", "mouse", "versionning"] 13 | 14 | func testMartha() { 15 | let distance = "MARTHA".jaroWinklerDistance(from: "MARHTA") 16 | 17 | XCTAssertEqual(distance, 0.961, accuracy: 0.3) 18 | } 19 | 20 | func testDWAYNE() { 21 | let distance = "DWAYNE".jaroWinklerDistance(from: "DUANE") 22 | 23 | XCTAssertEqual(distance, 0.84, accuracy: 0.3) 24 | } 25 | 26 | func testDIXON() { 27 | let distance = "DIXON".jaroWinklerDistance(from: "DICKSONX") 28 | 29 | XCTAssertEqual(distance, 0.813, accuracy: 0.3) 30 | } 31 | 32 | func testBestMatch() { 33 | let result = target.bestJaroWinklerMatchIn(propositions: propositions) 34 | XCTAssertEqual(result, "version") 35 | } 36 | 37 | func testMatchSingleCharacters_Equals0() { 38 | let result = "b".jaroWinklerDistance(from: "a") 39 | XCTAssertEqual(result, 0) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tests/ScoutTests/ExtensionsTests/StringExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | @testable import Scout 8 | 9 | final class StringExtensionsTests: XCTestCase { 10 | 11 | func testEscape1() { 12 | let string = "Hello, there" 13 | XCTAssertEqual(#""Hello, there""#, string.escapingCSV(",")) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/ScoutTests/Models/PathsFilterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scout 3 | // Copyright (c) Alexis Bridoux 2020 4 | // MIT license, see LICENSE file for details 5 | 6 | import XCTest 7 | @testable import Scout 8 | 9 | final class PathsFilterTests: XCTestCase { 10 | 11 | func testPredicateMismatchedTypes() throws { 12 | let predicate = try PathsFilter.ExpressionPredicate(format: "value > 10") 13 | 14 | _ = try predicate.evaluate(with: "yo") 15 | 16 | XCTAssertEqual(predicate.operatorsValueTypes, Set(arrayLiteral: .double)) 17 | } 18 | 19 | func testPredicateMismatchedTypesReturnsFalse() throws { 20 | let predicate = try PathsFilter.ExpressionPredicate(format: "value > 10") 21 | 22 | XCTAssertFalse(try predicate.evaluate(with: "yo")) 23 | } 24 | 25 | func testPredicateValueTypes() throws { 26 | let predicate = try PathsFilter.ExpressionPredicate(format: "!(value hasPrefix 'yo')") 27 | 28 | XCTAssertFalse(try predicate.evaluate(with: 10)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - "Tests" -------------------------------------------------------------------------------- /docs/css/documentation-topic~topic.b6287bcf.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */.generic-modal[data-v-795f7b59]{position:fixed;top:0;left:0;right:0;bottom:0;margin:0;z-index:11000;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;background:none;overflow:auto}.modal-fullscreen[data-v-795f7b59]{align-items:stretch}.modal-fullscreen .container[data-v-795f7b59]{margin:0;flex:1;width:100%;height:100%;padding-top:env(safe-area-inset-top);padding-right:env(safe-area-inset-right);padding-bottom:env(safe-area-inset-bottom);padding-left:env(safe-area-inset-left)}.modal-standard[data-v-795f7b59]{padding:20px}.modal-standard .container[data-v-795f7b59]{padding:60px;border-radius:var(--border-radius,4px)}@media screen{[data-color-scheme=dark] .modal-standard .container[data-v-795f7b59]{background:#1d1d1f}}@media screen and (prefers-color-scheme:dark){[data-color-scheme=auto] .modal-standard .container[data-v-795f7b59]{background:#1d1d1f}}@media only screen and (max-width:735px){.modal-standard[data-v-795f7b59]{padding:0;align-items:stretch}.modal-standard .container[data-v-795f7b59]{margin:20px 0 0;padding:50px 30px;flex:1;width:100%;border-bottom-left-radius:0;border-bottom-right-radius:0}}.backdrop[data-v-795f7b59]{overflow:auto;background:var(--backdrop-background,rgba(0,0,0,.4));-webkit-overflow-scrolling:touch;width:100%;height:100%;position:fixed}.container[data-v-795f7b59]{margin-left:auto;margin-right:auto;width:980px;background:var(--colors-generic-modal-background,var(--color-generic-modal-background));z-index:1;position:relative;overflow:auto;max-width:100%}@media only screen and (max-width:1250px){.container[data-v-795f7b59]{width:692px}}@media only screen and (max-width:735px){.container[data-v-795f7b59]{width:87.5%}}@media only screen and (max-width:320px){.container[data-v-795f7b59]{width:215px}}.close[data-v-795f7b59]{position:absolute;z-index:9999;top:22px;left:22px;width:17px;height:17px;color:#666;cursor:pointer;background:none;border:0;display:flex;align-items:center}.close .close-icon[data-v-795f7b59]{fill:currentColor;width:100%;height:100%}.theme-dark .container[data-v-795f7b59]{background:#000}.theme-dark .container .close[data-v-795f7b59]{color:#b0b0b0}.theme-code .container[data-v-795f7b59]{background-color:var(--code-background,var(--color-code-background))} -------------------------------------------------------------------------------- /docs/data/documentation/scout/bounds/equatable-implementations.json: -------------------------------------------------------------------------------- 1 | {"sections":[],"metadata":{"modules":[{"name":"Scout"}],"title":"Equatable Implementations","role":"collectionGroup"},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/Bounds\/Equatable-Implementations"},"kind":"article","hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/Bounds"]]},"variants":[{"paths":["\/documentation\/scout\/bounds\/equatable-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"topicSections":[{"generated":true,"title":"Operators","identifiers":["doc:\/\/Scout\/documentation\/Scout\/Bounds\/!=(_:_:)"]}],"schemaVersion":{"patch":0,"major":0,"minor":3},"references":{"doc://Scout/documentation/Scout/Bounds":{"abstract":[{"type":"text","text":"Lower and upper bounds to be used to slice an array"}],"type":"topic","url":"\/documentation\/scout\/bounds","role":"symbol","kind":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/Bounds","title":"Bounds","fragments":[{"text":"struct","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"Bounds"}],"navigatorTitle":[{"kind":"identifier","text":"Bounds"}]},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/Bounds/!=(_:_:)":{"identifier":"doc:\/\/Scout\/documentation\/Scout\/Bounds\/!=(_:_:)","role":"symbol","title":"!=(_:_:)","abstract":[],"fragments":[{"kind":"keyword","text":"static"},{"text":" ","kind":"text"},{"text":"func","kind":"keyword"},{"text":" ","kind":"text"},{"text":"!=","kind":"identifier"},{"text":" ","kind":"text"},{"kind":"text","text":"("},{"kind":"typeIdentifier","text":"Self"},{"text":", ","kind":"text"},{"text":"Self","kind":"typeIdentifier"},{"text":") -> ","kind":"text"},{"text":"Bool","kind":"typeIdentifier","preciseIdentifier":"s:Sb"}],"type":"topic","kind":"symbol","url":"\/documentation\/scout\/bounds\/!=(_:_:)"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/dataformat/equatable-implementations.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"major":0,"minor":3,"patch":0},"metadata":{"role":"collectionGroup","modules":[{"name":"Scout"}],"title":"Equatable Implementations"},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/DataFormat"]]},"topicSections":[{"title":"Operators","identifiers":["doc:\/\/Scout\/documentation\/Scout\/DataFormat\/!=(_:_:)"],"generated":true}],"kind":"article","identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/Equatable-Implementations"},"sections":[],"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/dataformat\/equatable-implementations"]}],"references":{"doc://Scout/documentation/Scout/DataFormat":{"navigatorTitle":[{"kind":"identifier","text":"DataFormat"}],"type":"topic","fragments":[{"text":"enum","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"DataFormat"}],"title":"DataFormat","abstract":[{"type":"text","text":"Unique identifier of a data format"}],"kind":"symbol","url":"\/documentation\/scout\/dataformat","role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/DataFormat/!=(_:_:)":{"abstract":[],"type":"topic","kind":"symbol","fragments":[{"text":"static","kind":"keyword"},{"kind":"text","text":" "},{"text":"func","kind":"keyword"},{"kind":"text","text":" "},{"text":"!=","kind":"identifier"},{"text":" ","kind":"text"},{"kind":"text","text":"("},{"text":"Self","kind":"typeIdentifier"},{"text":", ","kind":"text"},{"text":"Self","kind":"typeIdentifier"},{"text":") -> ","kind":"text"},{"preciseIdentifier":"s:Sb","text":"Bool","kind":"typeIdentifier"}],"identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/!=(_:_:)","url":"\/documentation\/scout\/dataformat\/!=(_:_:)","title":"!=(_:_:)","role":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/dataformat/json.json: -------------------------------------------------------------------------------- 1 | {"metadata":{"roleHeading":"Case","role":"symbol","title":"DataFormat.json","externalID":"s:5Scout10DataFormatO4jsonyA2CmF","fragments":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"json"}],"modules":[{"name":"Scout"}],"symbolKind":"case"},"sections":[],"primaryContentSections":[{"declarations":[{"tokens":[{"text":"case","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"json"}],"languages":["swift"],"platforms":["macOS"]}],"kind":"declarations"}],"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/dataformat\/json"]}],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/json","interfaceLanguage":"swift"},"schemaVersion":{"major":0,"minor":3,"patch":0},"kind":"symbol","hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/DataFormat"]]},"references":{"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/DataFormat/json":{"role":"symbol","title":"DataFormat.json","abstract":[],"fragments":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"json"}],"kind":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/json","type":"topic","url":"\/documentation\/scout\/dataformat\/json"},"doc://Scout/documentation/Scout/DataFormat":{"navigatorTitle":[{"kind":"identifier","text":"DataFormat"}],"type":"topic","fragments":[{"text":"enum","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"DataFormat"}],"title":"DataFormat","abstract":[{"type":"text","text":"Unique identifier of a data format"}],"kind":"symbol","url":"\/documentation\/scout\/dataformat","role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/dataformat/plist.json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"declarations":[{"tokens":[{"kind":"keyword","text":"case"},{"kind":"text","text":" "},{"text":"plist","kind":"identifier"}],"languages":["swift"],"platforms":["macOS"]}],"kind":"declarations"}],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/DataFormat"]]},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/dataformat\/plist"]}],"schemaVersion":{"minor":3,"major":0,"patch":0},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/plist"},"kind":"symbol","sections":[],"metadata":{"externalID":"s:5Scout10DataFormatO5plistyA2CmF","role":"symbol","modules":[{"name":"Scout"}],"roleHeading":"Case","title":"DataFormat.plist","symbolKind":"case","fragments":[{"kind":"keyword","text":"case"},{"kind":"text","text":" "},{"text":"plist","kind":"identifier"}]},"references":{"doc://Scout/documentation/Scout/DataFormat/plist":{"url":"\/documentation\/scout\/dataformat\/plist","fragments":[{"text":"case","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"plist"}],"identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/plist","kind":"symbol","title":"DataFormat.plist","abstract":[],"role":"symbol","type":"topic"},"doc://Scout/documentation/Scout/DataFormat":{"navigatorTitle":[{"kind":"identifier","text":"DataFormat"}],"type":"topic","fragments":[{"text":"enum","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"DataFormat"}],"title":"DataFormat","abstract":[{"type":"text","text":"Unique identifier of a data format"}],"kind":"symbol","url":"\/documentation\/scout\/dataformat","role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/dataformat/xml.json: -------------------------------------------------------------------------------- 1 | {"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/xml","interfaceLanguage":"swift"},"kind":"symbol","sections":[],"primaryContentSections":[{"declarations":[{"languages":["swift"],"tokens":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"text":"xml","kind":"identifier"}],"platforms":["macOS"]}],"kind":"declarations"}],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/DataFormat"]]},"schemaVersion":{"minor":3,"major":0,"patch":0},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/dataformat\/xml"]}],"metadata":{"roleHeading":"Case","title":"DataFormat.xml","modules":[{"name":"Scout"}],"symbolKind":"case","role":"symbol","externalID":"s:5Scout10DataFormatO3xmlyA2CmF","fragments":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"xml"}]},"references":{"doc://Scout/documentation/Scout/DataFormat":{"navigatorTitle":[{"kind":"identifier","text":"DataFormat"}],"type":"topic","fragments":[{"text":"enum","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"DataFormat"}],"title":"DataFormat","abstract":[{"type":"text","text":"Unique identifier of a data format"}],"kind":"symbol","url":"\/documentation\/scout\/dataformat","role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat"},"doc://Scout/documentation/Scout/DataFormat/xml":{"url":"\/documentation\/scout\/dataformat\/xml","type":"topic","title":"DataFormat.xml","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/xml","role":"symbol","kind":"symbol","abstract":[],"fragments":[{"kind":"keyword","text":"case"},{"text":" ","kind":"text"},{"text":"xml","kind":"identifier"}]},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/dataformat/yaml.json: -------------------------------------------------------------------------------- 1 | {"sections":[],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/DataFormat"]]},"schemaVersion":{"patch":0,"major":0,"minor":3},"kind":"symbol","metadata":{"role":"symbol","externalID":"s:5Scout10DataFormatO4yamlyA2CmF","roleHeading":"Case","modules":[{"name":"Scout"}],"fragments":[{"text":"case","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"yaml"}],"symbolKind":"case","title":"DataFormat.yaml"},"primaryContentSections":[{"declarations":[{"languages":["swift"],"tokens":[{"kind":"keyword","text":"case"},{"text":" ","kind":"text"},{"kind":"identifier","text":"yaml"}],"platforms":["macOS"]}],"kind":"declarations"}],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/yaml","interfaceLanguage":"swift"},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/dataformat\/yaml"]}],"references":{"doc://Scout/documentation/Scout/DataFormat/yaml":{"kind":"symbol","role":"symbol","type":"topic","fragments":[{"text":"case","kind":"keyword"},{"kind":"text","text":" "},{"text":"yaml","kind":"identifier"}],"url":"\/documentation\/scout\/dataformat\/yaml","abstract":[],"identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat\/yaml","title":"DataFormat.yaml"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/DataFormat":{"navigatorTitle":[{"kind":"identifier","text":"DataFormat"}],"type":"topic","fragments":[{"text":"enum","kind":"keyword"},{"kind":"text","text":" "},{"kind":"identifier","text":"DataFormat"}],"title":"DataFormat","abstract":[{"type":"text","text":"Unique identifier of a data format"}],"kind":"symbol","url":"\/documentation\/scout\/dataformat","role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/DataFormat"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/bool(_:).json: -------------------------------------------------------------------------------- 1 | {"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/bool(_:)"},"schemaVersion":{"major":0,"patch":0,"minor":3},"sections":[],"kind":"symbol","primaryContentSections":[{"declarations":[{"languages":["swift"],"platforms":["macOS"],"tokens":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"bool"},{"kind":"text","text":"("},{"preciseIdentifier":"s:Sb","text":"Bool","kind":"typeIdentifier"},{"kind":"text","text":")"}]}],"kind":"declarations"}],"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorervalue\/bool(_:)"]}],"metadata":{"modules":[{"name":"Scout"}],"roleHeading":"Case","symbolKind":"case","title":"ExplorerValue.bool(_:)","externalID":"s:5Scout13ExplorerValueO4boolyACSbcACmF","role":"symbol","fragments":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"text":"bool","kind":"identifier"},{"text":"(","kind":"text"},{"preciseIdentifier":"s:Sb","text":"Bool","kind":"typeIdentifier"},{"kind":"text","text":")"}]},"references":{"doc://Scout/documentation/Scout/ExplorerValue/bool(_:)":{"title":"ExplorerValue.bool(_:)","url":"\/documentation\/scout\/explorervalue\/bool(_:)","type":"topic","abstract":[],"kind":"symbol","role":"symbol","fragments":[{"kind":"keyword","text":"case"},{"text":" ","kind":"text"},{"text":"bool","kind":"identifier"},{"text":"(","kind":"text"},{"text":"Bool","kind":"typeIdentifier","preciseIdentifier":"s:Sb"},{"text":")","kind":"text"}],"identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/bool(_:)"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/customdebugstringconvertible-implementations.json: -------------------------------------------------------------------------------- 1 | {"topicSections":[{"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/debugDescription"],"title":"Instance Properties","generated":true}],"metadata":{"modules":[{"name":"Scout"}],"title":"CustomDebugStringConvertible Implementations","role":"collectionGroup"},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/CustomDebugStringConvertible-Implementations"},"schemaVersion":{"minor":3,"patch":0,"major":0},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorervalue\/customdebugstringconvertible-implementations"]}],"kind":"article","hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"sections":[],"references":{"doc://Scout/documentation/Scout/ExplorerValue/debugDescription":{"kind":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/debugDescription","role":"symbol","fragments":[{"text":"var","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"debugDescription"},{"kind":"text","text":": "},{"preciseIdentifier":"s:SS","kind":"typeIdentifier","text":"String"}],"title":"debugDescription","type":"topic","url":"\/documentation\/scout\/explorervalue\/debugdescription","abstract":[]},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/customstringconvertible-implementations.json: -------------------------------------------------------------------------------- 1 | {"topicSections":[{"generated":true,"title":"Instance Properties","identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/description"]}],"metadata":{"modules":[{"name":"Scout"}],"title":"CustomStringConvertible Implementations","role":"collectionGroup"},"sections":[],"schemaVersion":{"patch":0,"major":0,"minor":3},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/CustomStringConvertible-Implementations"},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorervalue\/customstringconvertible-implementations"]}],"kind":"article","references":{"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout/ExplorerValue/description":{"type":"topic","url":"\/documentation\/scout\/explorervalue\/description","role":"symbol","abstract":[],"fragments":[{"text":"var","kind":"keyword"},{"kind":"text","text":" "},{"text":"description","kind":"identifier"},{"kind":"text","text":": "},{"kind":"typeIdentifier","preciseIdentifier":"s:SS","text":"String"}],"identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/description","title":"description","kind":"symbol"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/decodable-implementations.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"minor":3,"patch":0,"major":0},"metadata":{"title":"Decodable Implementations","modules":[{"name":"Scout"}],"role":"collectionGroup"},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"sections":[],"kind":"article","topicSections":[{"generated":true,"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(from:)"],"title":"Initializers"}],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/Decodable-Implementations","interfaceLanguage":"swift"},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/decodable-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"references":{"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue/init(from:)":{"title":"init(from:)","url":"\/documentation\/scout\/explorervalue\/init(from:)","fragments":[{"text":"init","kind":"identifier"},{"text":"(","kind":"text"},{"text":"from","kind":"externalParam"},{"text":": ","kind":"text"},{"text":"Decoder","preciseIdentifier":"s:s7DecoderP","kind":"typeIdentifier"},{"kind":"text","text":") "},{"kind":"keyword","text":"throws"}],"role":"symbol","abstract":[],"type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(from:)","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/encodable-implementations.json: -------------------------------------------------------------------------------- 1 | {"metadata":{"title":"Encodable Implementations","role":"collectionGroup","modules":[{"name":"Scout"}]},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"sections":[],"topicSections":[{"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/encode(to:)"],"generated":true,"title":"Instance Methods"}],"schemaVersion":{"minor":3,"patch":0,"major":0},"kind":"article","identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/Encodable-Implementations","interfaceLanguage":"swift"},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/encodable-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"references":{"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue/encode(to:)":{"identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/encode(to:)","title":"encode(to:)","abstract":[],"fragments":[{"text":"func","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"encode"},{"text":"(","kind":"text"},{"kind":"externalParam","text":"to"},{"text":": ","kind":"text"},{"preciseIdentifier":"s:s7EncoderP","text":"Encoder","kind":"typeIdentifier"},{"text":") ","kind":"text"},{"text":"throws","kind":"keyword"}],"type":"topic","url":"\/documentation\/scout\/explorervalue\/encode(to:)","kind":"symbol","role":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/equatable-implementations.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"patch":0,"major":0,"minor":3},"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/Equatable-Implementations","interfaceLanguage":"swift"},"kind":"article","variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorervalue\/equatable-implementations"]}],"topicSections":[{"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/!=(_:_:)"],"title":"Operators","generated":true}],"metadata":{"role":"collectionGroup","modules":[{"name":"Scout"}],"title":"Equatable Implementations"},"sections":[],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"references":{"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout/ExplorerValue/!=(_:_:)":{"title":"!=(_:_:)","abstract":[],"fragments":[{"text":"static","kind":"keyword"},{"kind":"text","text":" "},{"kind":"keyword","text":"func"},{"text":" ","kind":"text"},{"text":"!=","kind":"identifier"},{"kind":"text","text":" "},{"kind":"text","text":"("},{"text":"Self","kind":"typeIdentifier"},{"text":", ","kind":"text"},{"text":"Self","kind":"typeIdentifier"},{"text":") -> ","kind":"text"},{"text":"Bool","kind":"typeIdentifier","preciseIdentifier":"s:Sb"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/!=(_:_:)","url":"\/documentation\/scout\/explorervalue\/!=(_:_:)","role":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/expressiblebyarrayliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"metadata":{"modules":[{"name":"Scout"}],"title":"ExpressibleByArrayLiteral Implementations","role":"collectionGroup"},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"sections":[],"topicSections":[{"generated":true,"title":"Initializers","identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(arrayLiteral:)"]}],"schemaVersion":{"major":0,"patch":0,"minor":3},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/ExpressibleByArrayLiteral-Implementations"},"kind":"article","variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorervalue\/expressiblebyarrayliteral-implementations"]}],"references":{"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout/ExplorerValue/init(arrayLiteral:)":{"url":"\/documentation\/scout\/explorervalue\/init(arrayliteral:)","abstract":[],"kind":"symbol","fragments":[{"kind":"identifier","text":"init"},{"text":"(","kind":"text"},{"text":"arrayLiteral","kind":"externalParam"},{"kind":"text","text":": "},{"preciseIdentifier":"s:5Scout13ExplorerValueO","text":"ExplorerValue","kind":"typeIdentifier"},{"kind":"text","text":"...)"}],"role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(arrayLiteral:)","type":"topic","title":"init(arrayLiteral:)"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/expressiblebybooleanliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/ExpressibleByBooleanLiteral-Implementations","interfaceLanguage":"swift"},"metadata":{"role":"collectionGroup","title":"ExpressibleByBooleanLiteral Implementations","modules":[{"name":"Scout"}]},"sections":[],"kind":"article","hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/expressiblebybooleanliteral-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"schemaVersion":{"minor":3,"major":0,"patch":0},"topicSections":[{"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(booleanLiteral:)"],"title":"Initializers","generated":true}],"references":{"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout/ExplorerValue/init(booleanLiteral:)":{"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(booleanLiteral:)","abstract":[],"fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"("},{"kind":"externalParam","text":"booleanLiteral"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"Bool","preciseIdentifier":"s:Sb"},{"text":")","kind":"text"}],"role":"symbol","url":"\/documentation\/scout\/explorervalue\/init(booleanliteral:)","title":"init(booleanLiteral:)"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/expressiblebydictionaryliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"sections":[],"metadata":{"role":"collectionGroup","modules":[{"name":"Scout"}],"title":"ExpressibleByDictionaryLiteral Implementations"},"kind":"article","schemaVersion":{"major":0,"minor":3,"patch":0},"topicSections":[{"title":"Initializers","identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(dictionaryLiteral:)"],"generated":true}],"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/ExpressibleByDictionaryLiteral-Implementations"},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/expressiblebydictionaryliteral-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"references":{"doc://Scout/documentation/Scout/ExplorerValue/init(dictionaryLiteral:)":{"url":"\/documentation\/scout\/explorervalue\/init(dictionaryliteral:)","type":"topic","title":"init(dictionaryLiteral:)","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(dictionaryLiteral:)","role":"symbol","kind":"symbol","abstract":[],"fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"("},{"kind":"externalParam","text":"dictionaryLiteral"},{"kind":"text","text":": ("},{"kind":"typeIdentifier","preciseIdentifier":"s:SS","text":"String"},{"text":", ","kind":"text"},{"kind":"typeIdentifier","preciseIdentifier":"s:5Scout13ExplorerValueO","text":"ExplorerValue"},{"text":")...)","kind":"text"}]},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/expressiblebyfloatliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"major":0,"patch":0,"minor":3},"topicSections":[{"title":"Initializers","identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(floatLiteral:)"],"generated":true}],"sections":[],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/expressiblebyfloatliteral-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/ExpressibleByFloatLiteral-Implementations","interfaceLanguage":"swift"},"kind":"article","metadata":{"title":"ExpressibleByFloatLiteral Implementations","modules":[{"name":"Scout"}],"role":"collectionGroup"},"references":{"doc://Scout/documentation/Scout/ExplorerValue/init(floatLiteral:)":{"role":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(floatLiteral:)","fragments":[{"text":"init","kind":"identifier"},{"text":"(","kind":"text"},{"text":"floatLiteral","kind":"externalParam"},{"kind":"text","text":": "},{"kind":"typeIdentifier","preciseIdentifier":"s:Sd","text":"Double"},{"text":")","kind":"text"}],"url":"\/documentation\/scout\/explorervalue\/init(floatliteral:)","kind":"symbol","title":"init(floatLiteral:)","abstract":[]},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/expressiblebyintegerliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"major":0,"patch":0,"minor":3},"topicSections":[{"title":"Initializers","generated":true,"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(integerLiteral:)"]}],"sections":[],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/expressiblebyintegerliteral-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/ExpressibleByIntegerLiteral-Implementations"},"kind":"article","metadata":{"modules":[{"name":"Scout"}],"title":"ExpressibleByIntegerLiteral Implementations","role":"collectionGroup"},"references":{"doc://Scout/documentation/Scout/ExplorerValue/init(integerLiteral:)":{"role":"symbol","title":"init(integerLiteral:)","fragments":[{"kind":"identifier","text":"init"},{"text":"(","kind":"text"},{"kind":"externalParam","text":"integerLiteral"},{"text":": ","kind":"text"},{"preciseIdentifier":"s:Si","kind":"typeIdentifier","text":"Int"},{"text":")","kind":"text"}],"type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(integerLiteral:)","kind":"symbol","url":"\/documentation\/scout\/explorervalue\/init(integerliteral:)","abstract":[]},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/expressiblebystringliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"metadata":{"title":"ExpressibleByStringLiteral Implementations","role":"collectionGroup","modules":[{"name":"Scout"}]},"topicSections":[{"title":"Initializers","generated":true,"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(stringLiteral:)"]}],"sections":[],"kind":"article","schemaVersion":{"major":0,"minor":3,"patch":0},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/ExpressibleByStringLiteral-Implementations"},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"variants":[{"paths":["\/documentation\/scout\/explorervalue\/expressiblebystringliteral-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"references":{"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue/init(stringLiteral:)":{"title":"init(stringLiteral:)","url":"\/documentation\/scout\/explorervalue\/init(stringliteral:)","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/init(stringLiteral:)","fragments":[{"text":"init","kind":"identifier"},{"kind":"text","text":"("},{"kind":"externalParam","text":"stringLiteral"},{"kind":"text","text":": "},{"preciseIdentifier":"s:SS","text":"String","kind":"typeIdentifier"},{"text":")","kind":"text"}],"type":"topic","abstract":[],"kind":"symbol","role":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorervalue/int(_:).json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"patch":0,"major":0,"minor":3},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorervalue\/int(_:)"]}],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/int(_:)","interfaceLanguage":"swift"},"kind":"symbol","hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerValue"]]},"metadata":{"roleHeading":"Case","role":"symbol","externalID":"s:5Scout13ExplorerValueO3intyACSicACmF","title":"ExplorerValue.int(_:)","modules":[{"name":"Scout"}],"symbolKind":"case","fragments":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"int"},{"kind":"text","text":"("},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"},{"text":")","kind":"text"}]},"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"text":"case","kind":"keyword"},{"kind":"text","text":" "},{"text":"int","kind":"identifier"},{"kind":"text","text":"("},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"},{"kind":"text","text":")"}],"languages":["swift"],"platforms":["macOS"]}]}],"sections":[],"references":{"doc://Scout/documentation/Scout/ExplorerValue":{"fragments":[{"kind":"keyword","text":"enum"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerValue"}],"kind":"symbol","type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue","title":"ExplorerValue","abstract":[{"type":"text","text":"The values a "},{"type":"codeVoice","code":"PathExplorer"},{"type":"text","text":" can take"}],"role":"symbol","navigatorTitle":[{"text":"ExplorerValue","kind":"identifier"}],"url":"\/documentation\/scout\/explorervalue"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerValue/int(_:)":{"title":"ExplorerValue.int(_:)","role":"symbol","kind":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerValue\/int(_:)","url":"\/documentation\/scout\/explorervalue\/int(_:)","type":"topic","abstract":[],"fragments":[{"text":"case","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"int"},{"kind":"text","text":"("},{"kind":"typeIdentifier","preciseIdentifier":"s:Si","text":"Int"},{"text":")","kind":"text"}]}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorerxml/element.json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"declarations","declarations":[{"platforms":["macOS"],"tokens":[{"kind":"keyword","text":"typealias"},{"text":" ","kind":"text"},{"text":"Element","kind":"identifier"},{"text":" = ","kind":"text"},{"text":"AEXMLElement","kind":"typeIdentifier","preciseIdentifier":"s:5AEXML12AEXMLElementC"}],"languages":["swift"]}]}],"metadata":{"externalID":"s:5Scout11ExplorerXMLV7Elementa","title":"ExplorerXML.Element","symbolKind":"typealias","modules":[{"name":"Scout"}],"fragments":[{"text":"typealias","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"Element"}],"roleHeading":"Type Alias","navigatorTitle":[{"text":"Element","kind":"identifier"}],"role":"symbol"},"sections":[],"schemaVersion":{"major":0,"minor":3,"patch":0},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"]]},"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/Element","interfaceLanguage":"swift"},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorerxml\/element"]}],"kind":"symbol","references":{"doc://Scout/documentation/Scout/ExplorerXML":{"title":"ExplorerXML","url":"\/documentation\/scout\/explorerxml","abstract":[],"type":"topic","kind":"symbol","fragments":[{"kind":"keyword","text":"struct"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerXML"}],"navigatorTitle":[{"text":"ExplorerXML","kind":"identifier"}],"role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerXML/Element":{"fragments":[{"kind":"keyword","text":"typealias"},{"text":" ","kind":"text"},{"text":"Element","kind":"identifier"}],"abstract":[],"url":"\/documentation\/scout\/explorerxml\/element","kind":"symbol","title":"ExplorerXML.Element","role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/Element","type":"topic","navigatorTitle":[{"kind":"identifier","text":"Element"}]}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorerxml/expressiblebyunicodescalarliteral-implementations.json: -------------------------------------------------------------------------------- 1 | {"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/ExpressibleByUnicodeScalarLiteral-Implementations"},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorerxml\/expressiblebyunicodescalarliteral-implementations"]}],"sections":[],"schemaVersion":{"patch":0,"major":0,"minor":3},"metadata":{"modules":[{"name":"Scout"}],"role":"collectionGroup","title":"ExpressibleByUnicodeScalarLiteral Implementations"},"kind":"article","topicSections":[{"title":"Initializers","generated":true,"identifiers":["doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/init(unicodeScalarLiteral:)"]}],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"]]},"references":{"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerXML":{"title":"ExplorerXML","url":"\/documentation\/scout\/explorerxml","abstract":[],"type":"topic","kind":"symbol","fragments":[{"kind":"keyword","text":"struct"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerXML"}],"navigatorTitle":[{"text":"ExplorerXML","kind":"identifier"}],"role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"},"doc://Scout/documentation/Scout/ExplorerXML/init(unicodeScalarLiteral:)":{"url":"\/documentation\/scout\/explorerxml\/init(unicodescalarliteral:)","fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"("},{"kind":"externalParam","text":"unicodeScalarLiteral"},{"text":": ","kind":"text"},{"text":"Self","kind":"typeIdentifier"},{"kind":"text","text":"."},{"kind":"typeIdentifier","text":"ExtendedGraphemeClusterLiteralType"},{"kind":"text","text":")"}],"identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/init(unicodeScalarLiteral:)","abstract":[],"kind":"symbol","title":"init(unicodeScalarLiteral:)","role":"symbol","conformance":{"constraints":[{"type":"codeVoice","code":"ExtendedGraphemeClusterLiteralType"},{"text":" is ","type":"text"},{"type":"codeVoice","code":"Self.UnicodeScalarLiteralType"},{"type":"text","text":"."}],"availabilityPrefix":[{"text":"Available when","type":"text"}],"conformancePrefix":[{"type":"text","text":"Conforms when"}]},"type":"topic"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorerxml/int.json: -------------------------------------------------------------------------------- 1 | {"metadata":{"roleHeading":"Instance Property","symbolKind":"property","modules":[{"name":"Scout"}],"title":"int","externalID":"s:5Scout11ExplorerXMLV3intSiSgvp","fragments":[{"text":"var","kind":"keyword"},{"kind":"text","text":" "},{"text":"int","kind":"identifier"},{"kind":"text","text":": "},{"kind":"typeIdentifier","preciseIdentifier":"s:Si","text":"Int"},{"text":"?","kind":"text"}],"role":"symbol"},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"]]},"variants":[{"paths":["\/documentation\/scout\/explorerxml\/int"],"traits":[{"interfaceLanguage":"swift"}]}],"sections":[],"kind":"symbol","primaryContentSections":[{"kind":"declarations","declarations":[{"languages":["swift"],"tokens":[{"text":"var","kind":"keyword"},{"text":" ","kind":"text"},{"text":"int","kind":"identifier"},{"text":": ","kind":"text"},{"text":"Int","preciseIdentifier":"s:Si","kind":"typeIdentifier"},{"kind":"text","text":"? { "},{"text":"get","kind":"keyword"},{"kind":"text","text":" }"}],"platforms":["macOS"]}]}],"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/int"},"abstract":[{"text":"Inherited from ","type":"text"},{"type":"codeVoice","code":"PathExplorer.int"},{"type":"text","text":"."}],"schemaVersion":{"major":0,"minor":3,"patch":0},"references":{"doc://Scout/documentation/Scout/ExplorerXML":{"title":"ExplorerXML","url":"\/documentation\/scout\/explorerxml","abstract":[],"type":"topic","kind":"symbol","fragments":[{"kind":"keyword","text":"struct"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerXML"}],"navigatorTitle":[{"text":"ExplorerXML","kind":"identifier"}],"role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"},"doc://Scout/documentation/Scout":{"title":"Scout","url":"\/documentation\/scout","abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"type":"topic","kind":"symbol","role":"collection","identifier":"doc:\/\/Scout\/documentation\/Scout"},"doc://Scout/documentation/Scout/ExplorerXML/int":{"title":"int","url":"\/documentation\/scout\/explorerxml\/int","abstract":[],"type":"topic","kind":"symbol","fragments":[{"text":"var","kind":"keyword"},{"kind":"text","text":" "},{"text":"int","kind":"identifier"},{"kind":"text","text":": "},{"text":"Int","kind":"typeIdentifier","preciseIdentifier":"s:Si"},{"text":"?","kind":"text"}],"role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/int"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/explorerxml/isgroup.json: -------------------------------------------------------------------------------- 1 | {"kind":"symbol","variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/scout\/explorerxml\/isgroup"]}],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/isGroup","interfaceLanguage":"swift"},"sections":[],"metadata":{"title":"isGroup","fragments":[{"text":"var","kind":"keyword"},{"text":" ","kind":"text"},{"text":"isGroup","kind":"identifier"},{"kind":"text","text":": "},{"text":"Bool","kind":"typeIdentifier","preciseIdentifier":"s:Sb"}],"symbolKind":"property","role":"symbol","externalID":"s:5Scout11ExplorerXMLV7isGroupSbvp","roleHeading":"Instance Property","modules":[{"name":"Scout"}]},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"]]},"abstract":[{"type":"text","text":"Inherited from "},{"code":"PathExplorer.isGroup","type":"codeVoice"},{"type":"text","text":"."}],"primaryContentSections":[{"declarations":[{"languages":["swift"],"platforms":["macOS"],"tokens":[{"kind":"keyword","text":"var"},{"text":" ","kind":"text"},{"text":"isGroup","kind":"identifier"},{"kind":"text","text":": "},{"text":"Bool","preciseIdentifier":"s:Sb","kind":"typeIdentifier"},{"text":" { ","kind":"text"},{"text":"get","kind":"keyword"},{"text":" }","kind":"text"}]}],"kind":"declarations"}],"schemaVersion":{"minor":3,"patch":0,"major":0},"references":{"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/ExplorerXML":{"title":"ExplorerXML","url":"\/documentation\/scout\/explorerxml","abstract":[],"type":"topic","kind":"symbol","fragments":[{"kind":"keyword","text":"struct"},{"text":" ","kind":"text"},{"kind":"identifier","text":"ExplorerXML"}],"navigatorTitle":[{"text":"ExplorerXML","kind":"identifier"}],"role":"symbol","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML"},"doc://Scout/documentation/Scout/ExplorerXML/isGroup":{"kind":"symbol","title":"isGroup","identifier":"doc:\/\/Scout\/documentation\/Scout\/ExplorerXML\/isGroup","fragments":[{"text":"var","kind":"keyword"},{"text":" ","kind":"text"},{"text":"isGroup","kind":"identifier"},{"text":": ","kind":"text"},{"preciseIdentifier":"s:Sb","text":"Bool","kind":"typeIdentifier"}],"role":"symbol","abstract":[],"type":"topic","url":"\/documentation\/scout\/explorerxml\/isgroup"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/serializationerror/datatostring.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"patch":0,"minor":3,"major":0},"kind":"symbol","metadata":{"modules":[{"name":"Scout"}],"symbolKind":"case","title":"SerializationError.dataToString","fragments":[{"kind":"keyword","text":"case"},{"kind":"text","text":" "},{"text":"dataToString","kind":"identifier"}],"roleHeading":"Case","externalID":"s:5Scout18SerializationErrorO12dataToStringyA2CmF","role":"symbol"},"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/SerializationError"]]},"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/SerializationError\/dataToString"},"variants":[{"paths":["\/documentation\/scout\/serializationerror\/datatostring"],"traits":[{"interfaceLanguage":"swift"}]}],"sections":[],"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"text":"case","kind":"keyword"},{"kind":"text","text":" "},{"text":"dataToString","kind":"identifier"}],"platforms":["macOS"],"languages":["swift"]}]}],"references":{"doc://Scout/documentation/Scout/SerializationError/dataToString":{"url":"\/documentation\/scout\/serializationerror\/datatostring","fragments":[{"kind":"keyword","text":"case"},{"text":" ","kind":"text"},{"kind":"identifier","text":"dataToString"}],"identifier":"doc:\/\/Scout\/documentation\/Scout\/SerializationError\/dataToString","abstract":[],"title":"SerializationError.dataToString","kind":"symbol","role":"symbol","type":"topic"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/SerializationError":{"type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/SerializationError","navigatorTitle":[{"text":"SerializationError","kind":"identifier"}],"url":"\/documentation\/scout\/serializationerror","abstract":[],"title":"SerializationError","role":"symbol","fragments":[{"kind":"keyword","text":"enum"},{"kind":"text","text":" "},{"text":"SerializationError","kind":"identifier"}],"kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/serializationerror/error-implementations.json: -------------------------------------------------------------------------------- 1 | {"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/Scout\/documentation\/Scout\/SerializationError\/Error-Implementations"},"variants":[{"paths":["\/documentation\/scout\/serializationerror\/error-implementations"],"traits":[{"interfaceLanguage":"swift"}]}],"sections":[],"schemaVersion":{"patch":0,"major":0,"minor":3},"kind":"article","metadata":{"modules":[{"name":"Scout"}],"role":"collectionGroup","title":"Error Implementations"},"topicSections":[{"generated":true,"identifiers":["doc:\/\/Scout\/documentation\/Scout\/SerializationError\/localizedDescription"],"title":"Instance Properties"}],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/SerializationError"]]},"references":{"doc://Scout/documentation/Scout/SerializationError":{"type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/SerializationError","navigatorTitle":[{"text":"SerializationError","kind":"identifier"}],"url":"\/documentation\/scout\/serializationerror","abstract":[],"title":"SerializationError","role":"symbol","fragments":[{"kind":"keyword","text":"enum"},{"kind":"text","text":" "},{"text":"SerializationError","kind":"identifier"}],"kind":"symbol"},"doc://Scout/documentation/Scout/SerializationError/localizedDescription":{"identifier":"doc:\/\/Scout\/documentation\/Scout\/SerializationError\/localizedDescription","title":"localizedDescription","abstract":[],"fragments":[{"kind":"keyword","text":"var"},{"kind":"text","text":" "},{"text":"localizedDescription","kind":"identifier"},{"text":": ","kind":"text"},{"preciseIdentifier":"s:SS","text":"String","kind":"typeIdentifier"}],"type":"topic","url":"\/documentation\/scout\/serializationerror\/localizeddescription","kind":"symbol","role":"symbol"},"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/data/documentation/scout/serializationerror/stringtodata.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"patch":0,"minor":3,"major":0},"variants":[{"paths":["\/documentation\/scout\/serializationerror\/stringtodata"],"traits":[{"interfaceLanguage":"swift"}]}],"kind":"symbol","primaryContentSections":[{"declarations":[{"tokens":[{"kind":"keyword","text":"case"},{"text":" ","kind":"text"},{"text":"stringToData","kind":"identifier"}],"languages":["swift"],"platforms":["macOS"]}],"kind":"declarations"}],"hierarchy":{"paths":[["doc:\/\/Scout\/documentation\/Scout","doc:\/\/Scout\/documentation\/Scout\/SerializationError"]]},"metadata":{"modules":[{"name":"Scout"}],"roleHeading":"Case","symbolKind":"case","title":"SerializationError.stringToData","externalID":"s:5Scout18SerializationErrorO12stringToDatayA2CmF","role":"symbol","fragments":[{"kind":"keyword","text":"case"},{"kind":"text","text":" "},{"text":"stringToData","kind":"identifier"}]},"sections":[],"identifier":{"url":"doc:\/\/Scout\/documentation\/Scout\/SerializationError\/stringToData","interfaceLanguage":"swift"},"references":{"doc://Scout/documentation/Scout":{"abstract":[{"type":"text","text":"This library aims to make specific formats data values reading and writing simple when the data format is not known at build time."}],"identifier":"doc:\/\/Scout\/documentation\/Scout","url":"\/documentation\/scout","type":"topic","role":"collection","title":"Scout","kind":"symbol"},"doc://Scout/documentation/Scout/SerializationError/stringToData":{"title":"SerializationError.stringToData","identifier":"doc:\/\/Scout\/documentation\/Scout\/SerializationError\/stringToData","abstract":[],"fragments":[{"kind":"keyword","text":"case"},{"text":" ","kind":"text"},{"text":"stringToData","kind":"identifier"}],"type":"topic","url":"\/documentation\/scout\/serializationerror\/stringtodata","kind":"symbol","role":"symbol"},"doc://Scout/documentation/Scout/SerializationError":{"type":"topic","identifier":"doc:\/\/Scout\/documentation\/Scout\/SerializationError","navigatorTitle":[{"text":"SerializationError","kind":"identifier"}],"url":"\/documentation\/scout\/serializationerror","abstract":[],"title":"SerializationError","role":"symbol","fragments":[{"kind":"keyword","text":"enum"},{"kind":"text","text":" "},{"text":"SerializationError","kind":"identifier"}],"kind":"symbol"}}} -------------------------------------------------------------------------------- /docs/developer-og-twitter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/docs/developer-og-twitter.jpg -------------------------------------------------------------------------------- /docs/developer-og.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/docs/developer-og.jpg -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/docs/favicon.ico -------------------------------------------------------------------------------- /docs/favicon.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/added-icon.d6f7e47d.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/deprecated-icon.015b4f17.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/modified-icon.f496e73d.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/no-image@2x.df2a0a50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ABridoux/scout/37453749ef2d3e81a542cc9dacf0d8f636f848c1/docs/img/no-image@2x.df2a0a50.png -------------------------------------------------------------------------------- /docs/js/highlight-js-diff.62d66733.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-diff"],{"48b8":function(e,n){function a(e){const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-http.163e45b6.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-http"],{c01d:function(e,n){function a(e){const n=e.regex,a="HTTP/(2|1\\.[01])",s=/[A-Za-z][A-Za-z0-9-]*/,t={className:"attribute",begin:n.concat("^",s,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},i=[t,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+a+" \\d{3})",end:/$/,contains:[{className:"meta",begin:a},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},{begin:"(?=^[A-Z]+ (.*?) "+a+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:a},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},e.inherit(t,{relevance:0})]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-json.471128d2.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-json"],{"5ad2":function(n,e){function a(n){const e={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},a={match:/[{}[\],:]/,className:"punctuation",relevance:0},s={beginKeywords:["true","false","null"].join(" ")};return{name:"JSON",contains:[e,a,n.QUOTE_STRING_MODE,s,n.C_NUMBER_MODE,n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],illegal:"\\S"}}n.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-markdown.90077643.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-markdown"],{"04b0":function(n,e){function a(n){const e=n.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},s={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},c={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},t={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},g=/[A-Za-z][A-Za-z0-9+.-]*/,d={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.concat(/\[.+?\]\(/,g,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},l={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},o={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};l.contains.push(o),o.contains.push(l);let b=[a,d];l.contains=l.contains.concat(b),o.contains=o.contains.concat(b),b=b.concat(l,o);const r={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:b},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:b}]}]},m={className:"quote",begin:"^>\\s+",contains:b,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[r,a,c,l,o,m,s,i,d,t]}}n.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-shell.dd7f411f.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-shell"],{b65b:function(s,n){function e(s){return{name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}}s.exports=e}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-xml.9c3688c7.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-xml"],{"8dcb":function(e,n){function a(e){const n=e.regex,a=n.concat(/[A-Z_]/,n.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),s=/[A-Za-z0-9._:-]+/,t={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},c=e.inherit(i,{begin:/\(/,end:/\)/}),l=e.inherit(e.APOS_STRING_MODE,{className:"string"}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),g={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,r,l,c,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[i,c,r,l]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},t,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[g],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[g],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:n.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:a,relevance:0,starts:g}]},{className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(a,/>/))),contains:[{className:"name",begin:a,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/metadata.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":{"major":0,"minor":1,"patch":0},"bundleIdentifier":"Scout","bundleDisplayName":"Scout"} --------------------------------------------------------------------------------