├── .github └── workflows │ ├── Build.yml │ └── WinBuild.yml ├── .gitignore ├── .gitmodules ├── .idea ├── encodings.xml ├── misc.xml └── vcs.xml ├── .scalafmt.conf ├── LICENSE ├── README.md ├── apexlink.iml ├── apexlink ├── .gitignore ├── .idea │ ├── .gitignore │ ├── .idea │ │ ├── .idea.iml │ │ ├── encodings.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── workspace.xml │ ├── ApexLink.iml │ ├── codeStyles │ │ ├── Project.xml │ │ └── codeStyleConfig.xml │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── dictionaries │ │ └── kevin.xml │ ├── encodings.xml │ ├── jarRepositories.xml │ ├── libraries │ │ ├── Maven__com_github_nawforce_scala_json_rpc_2_13_1_0_1.xml │ │ ├── Maven__com_github_nawforce_scala_json_rpc_upickle_json_serializer_2_13_1_0_1.xml │ │ ├── Maven__com_google_guava_guava_18_0.xml │ │ ├── Maven__com_google_jimfs_jimfs_1_1.xml │ │ ├── Maven__com_lihaoyi_geny_2_13_0_6_2.xml │ │ ├── Maven__com_lihaoyi_ujson_2_13_1_2_0.xml │ │ ├── Maven__com_lihaoyi_upack_2_13_1_2_0.xml │ │ ├── Maven__com_lihaoyi_upickle_2_13_1_2_0.xml │ │ ├── Maven__com_lihaoyi_upickle_core_2_13_1_2_0.xml │ │ ├── Maven__com_lihaoyi_upickle_implicits_2_13_1_2_0.xml │ │ ├── Maven__org_antlr_antlr4_runtime_4_8_1.xml │ │ ├── Maven__org_scala_js_scalajs_stubs_2_13_1_0_0.xml │ │ ├── Maven__org_scala_lang_modules_scala_collection_compat_2_13_2_1_4.xml │ │ ├── Maven__org_scala_lang_modules_scala_parallel_collections_2_13_1_0_0.xml │ │ ├── Maven__org_scala_lang_modules_scala_xml_2_13_1_3_0.xml │ │ ├── Maven__org_scala_lang_scala_library_2_13_3.xml │ │ ├── Maven__org_scala_lang_scala_reflect_2_13_3.xml │ │ ├── Maven__org_scalactic_scalactic_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_compatible_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_core_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_diagrams_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_featurespec_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_flatspec_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_freespec_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_funspec_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_funsuite_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_matchers_core_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_mustmatchers_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_propspec_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_refspec_2_13_3_2_2.xml │ │ ├── Maven__org_scalatest_scalatest_shouldmatchers_2_13_3_2_2.xml │ │ └── Maven__org_scalatest_scalatest_wordspec_2_13_3_2_2.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ ├── scala_compiler.xml │ ├── uiDesigner.xml │ └── vcs.xml ├── .scalafmt.conf ├── doc │ └── Types.md ├── images │ ├── FindZombies.png │ └── UnusedField.png ├── pom.xml └── src │ ├── META-INF │ └── MANIFEST.MF │ ├── main │ ├── java │ │ └── com │ │ │ ├── nawforce │ │ │ └── apexlink │ │ │ │ └── api │ │ │ │ └── IssuesCollection.java │ │ │ └── vmware │ │ │ └── antlr4c3 │ │ │ └── CodeCompletionCore.java │ └── scala │ │ └── com │ │ └── nawforce │ │ └── apexlink │ │ ├── ApexLink.scala │ │ ├── api │ │ ├── Org.scala │ │ ├── Package.scala │ │ ├── ServerOps.scala │ │ └── Summary.scala │ │ ├── cmds │ │ ├── Check.scala │ │ └── Server.scala │ │ ├── cst │ │ ├── AssignableSupport.scala │ │ ├── BodyDeclarations.scala │ │ ├── CST.scala │ │ ├── Creator.scala │ │ ├── Expressions.scala │ │ ├── Literals.scala │ │ ├── MethodMap.scala │ │ ├── Operations.scala │ │ ├── Primaries.scala │ │ ├── Properties.scala │ │ ├── Statements.scala │ │ ├── TypeDeclarations.scala │ │ ├── TypeReference.scala │ │ ├── Variables.scala │ │ ├── VerifyContext.scala │ │ └── stmts │ │ │ └── Switch.scala │ │ ├── deps │ │ ├── DownWalker.scala │ │ └── TransitiveCollector.scala │ │ ├── diagnostics │ │ └── IssueOps.scala │ │ ├── finding │ │ ├── RelativeTypeName.scala │ │ ├── TypeError.scala │ │ ├── TypeFinder.scala │ │ └── TypeResolver.scala │ │ ├── memory │ │ ├── Monitor.scala │ │ ├── SkinnySet.scala │ │ └── SkinnyWeakSet.scala │ │ ├── names │ │ ├── TypeIdentifiers.scala │ │ ├── TypeNames.scala │ │ └── XNames.scala │ │ ├── org │ │ ├── CompletionProvider.scala │ │ ├── DefinitionProvider.scala │ │ ├── Flusher.scala │ │ ├── IssuesManager.scala │ │ ├── Module.scala │ │ ├── ModuleCompletions.scala │ │ ├── OrgImpl.scala │ │ ├── PackageAPI.scala │ │ ├── PackageImpl.scala │ │ ├── SObjectDeployer.scala │ │ ├── StreamDeployer.scala │ │ ├── TextOps.scala │ │ └── package.scala │ │ ├── plugins │ │ ├── Plugin.scala │ │ ├── PluginDispatcher.scala │ │ ├── PluginsManager.scala │ │ └── UnusedPlugin.scala │ │ ├── rpc │ │ ├── CompletionItemLink.scala │ │ ├── DependencyGraph.scala │ │ ├── LocationLink.scala │ │ ├── OrgAPI.scala │ │ ├── OrgAPIImpl.scala │ │ └── RPCServer.scala │ │ └── types │ │ ├── apex │ │ ├── ApexDeclaration.scala │ │ ├── FullDeclaration.scala │ │ ├── SummaryDeclaration.scala │ │ ├── TriggerDeclaration.scala │ │ └── package.scala │ │ ├── core │ │ ├── BasicTypeDeclaration.scala │ │ ├── Dependent.scala │ │ ├── DependentType.scala │ │ ├── TypeDeclaration.scala │ │ └── TypeId.scala │ │ ├── other │ │ ├── AnyDeclaration.scala │ │ ├── ComponentDeclaration.scala │ │ ├── InterviewDeclaration.scala │ │ ├── LabelDeclaration.scala │ │ ├── PageDeclaration.scala │ │ └── VFContainer.scala │ │ ├── platform │ │ ├── GenericPlatformTypeDeclaration.scala │ │ ├── PlatformModifiers.scala │ │ ├── PlatformTypeDeclaration.scala │ │ └── PlatformTypes.scala │ │ ├── schema │ │ ├── GhostSObjectDeclaration.scala │ │ ├── SObjectDeclaration.scala │ │ ├── SObjectFieldFinder.scala │ │ ├── SObjectMethods.scala │ │ └── SchemaSObjectType.scala │ │ └── synthetic │ │ ├── CustomFieldDeclaration.scala │ │ └── CustomMethodDeclaration.scala │ └── test │ └── scala │ └── com │ └── nawforce │ └── apexlink │ ├── FileSystemHelper.scala │ ├── TestHelper.scala │ ├── cst │ ├── ArrayTest.scala │ ├── AssignTest.scala │ ├── ClassModifierTest.scala │ ├── ConstructorTest.scala │ ├── CreationTest.scala │ ├── DependencyTest.scala │ ├── EnumModifierTest.scala │ ├── ExtendsTest.scala │ ├── FieldTest.scala │ ├── IdDependencyTest.scala │ ├── IfTest.scala │ ├── ImplementsTest.scala │ ├── InnerInnerTypeTest.scala │ ├── InterfaceModifierTest.scala │ ├── MethodShadowTest.scala │ ├── MethodTest.scala │ ├── OperationsTest.scala │ ├── PropertyTest.scala │ ├── SafeNavigationTest.scala │ ├── SummaryTest.scala │ ├── SuppressWarningsTest.scala │ ├── SwitchTest.scala │ ├── VarTest.scala │ └── VariablesTest.scala │ ├── finding │ └── TypeFindingTest.scala │ ├── org │ └── IssueManagerTest.scala │ ├── parsers │ ├── CodeParserTest.scala │ └── LiteralTokenTest.scala │ ├── pkg │ ├── BugTest.scala │ ├── CachedTest.scala │ ├── CompletionProviderTest.scala │ ├── DefinitionProviderTest.scala │ ├── DeleteTest.scala │ ├── DependencyGraphTest.scala │ ├── DependentProjectTest.scala │ ├── GhostPackageTest.scala │ ├── PackageAPITest.scala │ ├── RefreshSObjectTest.scala │ ├── RefreshTest.scala │ └── UnusedTest.scala │ ├── rpc │ └── OrgAPITest.scala │ ├── stress │ ├── PartialStressTest.scala │ └── RefreshStressTest.scala │ └── types │ ├── AmbiguousObjectTest.scala │ ├── ComponentTest.scala │ ├── CustomObjectTest.scala │ ├── InterviewTest.scala │ ├── LabelTest.scala │ ├── LiteralTypeTest.scala │ ├── PageTest.scala │ ├── PlatformEventTest.scala │ ├── PlatformTypeDeclarationTest.scala │ ├── PlatformTypesValidationTest.scala │ ├── SchemaManagerTest.scala │ ├── StandardObjectTest.scala │ ├── TriggerTest.scala │ └── TypeStoreTest.scala ├── pkgforce ├── .gitignore ├── .scalafmt.conf ├── README.md ├── build.sbt ├── js │ ├── npm │ │ ├── .gitignore │ │ ├── .npmignore │ │ ├── .vscode │ │ │ └── launch.json │ │ ├── jestconfig.json │ │ ├── package.json │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ └── WorkspaceTest.ts │ │ │ └── pkgforce.d.ts │ │ └── tsconfig.json │ └── src │ │ ├── main │ │ └── scala │ │ │ └── com │ │ │ └── nawforce │ │ │ ├── apexparser │ │ │ ├── ApexLexer.scala │ │ │ ├── ApexParser.scala │ │ │ └── CaseInsensitiveInputStream.scala │ │ │ ├── pkgforce │ │ │ └── api │ │ │ │ ├── Issue.scala │ │ │ │ ├── IssueLocation.scala │ │ │ │ └── Workspaces.scala │ │ │ └── runtime │ │ │ ├── package.scala │ │ │ ├── parsers │ │ │ ├── CodeParser.scala │ │ │ ├── CollectingErrorListener.scala │ │ │ ├── PageParser.scala │ │ │ ├── Source.scala │ │ │ ├── SourceData.scala │ │ │ ├── TreeVisitor.scala │ │ │ ├── VFLexer.scala │ │ │ ├── VFParser.scala │ │ │ └── antlr │ │ │ │ ├── ANTLRInputStream.scala │ │ │ │ ├── AbstractParseTreeVisitor.scala │ │ │ │ ├── ApexParserVisitor.scala │ │ │ │ ├── BufferedTokenStream.scala │ │ │ │ ├── CharStream.scala │ │ │ │ ├── CommonTokenStream.scala │ │ │ │ ├── ErrorNode.scala │ │ │ │ ├── Interval.scala │ │ │ │ ├── ParseTree.scala │ │ │ │ ├── ParserRuleContext.scala │ │ │ │ ├── RuleContext.scala │ │ │ │ ├── RuleNode.scala │ │ │ │ ├── TerminalNode.scala │ │ │ │ └── Token.scala │ │ │ ├── platform │ │ │ ├── Environment.scala │ │ │ └── Path.scala │ │ │ └── xml │ │ │ ├── XMLDocument.scala │ │ │ └── XMLDom.scala │ │ └── test │ │ └── scala │ │ └── com │ │ └── nawforce │ │ └── runtime │ │ ├── FileSystemHelper.scala │ │ └── imports │ │ ├── FSMonkey.scala │ │ └── Memfs.scala ├── jvm │ └── src │ │ ├── META-INF │ │ └── MANIFEST.MF │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── nawforce │ │ │ │ ├── pkgforce │ │ │ │ └── api │ │ │ │ │ ├── Issue.java │ │ │ │ │ └── IssueLocation.java │ │ │ │ └── runtime │ │ │ │ └── parsers │ │ │ │ ├── VFLexer.java │ │ │ │ ├── VFParser.java │ │ │ │ ├── VFParserBaseListener.java │ │ │ │ ├── VFParserBaseVisitor.java │ │ │ │ ├── VFParserListener.java │ │ │ │ └── VFParserVisitor.java │ │ └── scala │ │ │ └── com │ │ │ └── nawforce │ │ │ └── runtime │ │ │ ├── cmds │ │ │ └── Scan.scala │ │ │ ├── package.scala │ │ │ ├── parsers │ │ │ ├── CodeParser.scala │ │ │ ├── CollectingErrorListener.scala │ │ │ ├── PageParser.scala │ │ │ ├── Source.scala │ │ │ ├── SourceData.scala │ │ │ └── TreeVisitor.scala │ │ │ ├── platform │ │ │ ├── Environment.scala │ │ │ └── Path.scala │ │ │ └── xml │ │ │ └── XMLDocument.scala │ │ └── test │ │ └── scala │ │ └── com │ │ └── nawforce │ │ └── runtime │ │ └── FileSystemHelper.scala ├── pkgforce.iml ├── pom.xml ├── project │ ├── build.properties │ └── plugins.sbt └── shared │ └── src │ ├── main │ └── scala │ │ └── com │ │ └── nawforce │ │ └── pkgforce │ │ ├── diagnostics │ │ ├── Diagnostic.scala │ │ ├── Duplicates.scala │ │ ├── Issue.scala │ │ ├── IssueLogger.scala │ │ └── Logger.scala │ │ ├── documents │ │ ├── DocumentIndex.scala │ │ ├── MetadataDocument.scala │ │ ├── ParsedCache.scala │ │ └── SourceInfo.scala │ │ ├── memory │ │ ├── Cleanable.scala │ │ ├── IdentityBox.scala │ │ ├── IdentityEquality.scala │ │ └── InternCache.scala │ │ ├── modifiers │ │ ├── FieldModifiers.scala │ │ ├── MethodModifiers.scala │ │ ├── Modifier.scala │ │ └── ModifierResults.scala │ │ ├── names │ │ ├── DotName.scala │ │ ├── EncodedName.scala │ │ ├── Identifier.scala │ │ ├── Name.scala │ │ ├── Names.scala │ │ ├── TypeIdentifier.scala │ │ └── TypeName.scala │ │ ├── parsers │ │ ├── ApexClassSummary.scala │ │ ├── ApexClassVisitor.scala │ │ └── UTF8Decode.scala │ │ ├── path │ │ ├── Location.scala │ │ ├── PathFactory.scala │ │ └── PathLike.scala │ │ ├── sfdx │ │ ├── ForceIgnore.scala │ │ ├── ModuleDependent.scala │ │ ├── PackageDependent.scala │ │ ├── PackageDirectory.scala │ │ ├── PositionParser.scala │ │ ├── SFDXProject.scala │ │ ├── VersionNumber.scala │ │ ├── WorkspaceConfig.scala │ │ └── package.scala │ │ ├── stream │ │ ├── ApexGenerator.scala │ │ ├── ComponentGenerator.scala │ │ ├── FlowGenerator.scala │ │ ├── LabelGenerator.scala │ │ ├── PackageStream.scala │ │ ├── PageGenerator.scala │ │ ├── SObjectGenerator.scala │ │ ├── TriggerGenerator.scala │ │ └── VFEvent.scala │ │ ├── workspace │ │ ├── Layer.scala │ │ └── Workspace.scala │ │ └── xml │ │ ├── XMLDocumentLike.scala │ │ └── XMLFactory.scala │ └── test │ └── scala │ └── com │ └── nawforce │ └── pkgforce │ ├── diagnostics │ └── LoggerTest.scala │ ├── documents │ ├── DocumentIndexTest.scala │ ├── DocumentTest.scala │ ├── ForceIgnoreTests.scala │ ├── IgnoreRuleTest.scala │ ├── ParsedCacheTest.scala │ ├── PathTest.scala │ └── XMLDocumentTest.scala │ ├── modifiers │ ├── ClassModifierTest.scala │ ├── FieldModifierTest.scala │ └── MethodModifierTest.scala │ ├── names │ ├── EncodedNameTest.scala │ ├── IdentifierTest.scala │ ├── TypeIdentifierTest.scala │ └── TypeNameTest.scala │ ├── parsers │ ├── CodeParserTest.scala │ ├── SOQLParserTest.scala │ ├── SOSLParserTest.scala │ ├── SourceDataTest.scala │ ├── SummaryTest.scala │ └── VFParserTest.scala │ ├── sfdx │ ├── ProjectLayerTest.scala │ └── ProjectTest.scala │ └── workspace │ └── WorkspaceTest.scala ├── pom.xml └── samples ├── Cumulus └── sfdx-project.json ├── FindNearby └── sfdx-project.json ├── HyperBatch └── sfdx-project.json ├── Interactions-for-Student-Recruitment ├── extra │ ├── DmlWrapper.cls │ └── README.md └── sfdx-project.json ├── NPSP └── sfdx-project.json ├── README.md ├── at4dx └── sfdx-project.json ├── fflib-apex-common-samplecode └── sfdx-project.json ├── purealoe-lwc ├── .forceignore └── sfdx-project.json └── synthetic ├── dependency-counts ├── .forceignore ├── .gitignore ├── force-app │ └── main │ │ └── default │ │ └── classes │ │ ├── NoDeps.cls │ │ ├── NoDeps.cls-meta.xml │ │ ├── SingleDep.cls │ │ ├── SingleDep.cls-meta.xml │ │ ├── TestDep.cls │ │ ├── TestDep.cls-meta.xml │ │ ├── TransDep.cls │ │ └── TransDep.cls-meta.xml └── sfdx-project.json ├── mdapi-test ├── Hello.cls ├── Hello.cls-meta.xml ├── World.cls └── World.cls-meta.xml ├── sfdx-ns-test ├── .forceignore ├── .gitignore ├── force-app │ └── main │ │ └── default │ │ └── classes │ │ ├── DoubleError.cls │ │ ├── DoubleError.cls-meta.xml │ │ ├── Hello.cls │ │ ├── Hello.cls-meta.xml │ │ ├── SingleError.cls │ │ └── SingleError.cls-meta.xml └── sfdx-project.json ├── sfdx-test ├── .forceignore ├── .gitignore ├── force-app │ └── main │ │ └── default │ │ └── classes │ │ ├── Hello.cls │ │ └── Hello.cls-meta.xml └── sfdx-project.json └── test-classes ├── .forceignore ├── .gitignore ├── force-app └── main │ └── default │ └── classes │ ├── API.cls │ ├── APIFactory.cls │ ├── APIImpl.cls │ ├── APITest.cls │ ├── Base.cls │ ├── BaseTest.cls │ ├── Derived.cls │ ├── DerivedTest.cls │ ├── Hello.cls │ ├── Hello.cls-meta.xml │ ├── HelloTest.cls │ ├── HelloTest.cls-meta.xml │ ├── InnerServiceImpl.cls │ ├── NoTest.cls │ ├── NoTest.cls-meta.xml │ ├── Service.cls │ ├── ServiceAPITest.cls │ ├── ServiceImpl.cls │ └── ServiceTest.cls └── sfdx-project.json /.github/workflows/WinBuild.yml: -------------------------------------------------------------------------------- 1 | name: WinBuild 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | 9 | runs-on: windows-latest 10 | 11 | steps: 12 | - run: git config --global core.autocrlf false 13 | - uses: actions/checkout@v2 14 | - uses: olafurpg/setup-scala@v10 15 | 16 | - name: Set up JDK 1.8 17 | uses: actions/setup-java@v2 18 | with: 19 | distribution: adopt 20 | java-version: 8 21 | cache: "maven" 22 | 23 | - name: Set up Maven 24 | uses: stCarolas/setup-maven@v4.2 25 | with: 26 | maven-version: 3.8.1 27 | 28 | - name: Build with Maven 29 | run: | 30 | mvn --version 31 | mvn -B install -D gpg.skip 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 2.6.3 2 | continuationIndent.defnSite = 2 3 | optIn.configStyleArguments = false 4 | align.preset = more 5 | maxColumn = 100 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | [The "BSD licence"] 2 | Copyright (c) 2013 Terence Parr, Sam Harwell (ApexLexer.g4 & ApexParser.g4) 3 | Copyright (c) 2017-2020 Kevin Jones (All other contributions) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /apexlink.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /apexlink/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # ANTLR 3 | *.tokens 4 | *.interp 5 | 6 | # Linked common directory 7 | module/common 8 | 9 | # scratch bin directory 10 | bin/ 11 | 12 | # checkstyle junk 13 | .idea/checkstyle-idea.xml 14 | 15 | # Created by https://www.gitignore.io/api/windows,intellij,maven 16 | 17 | ### Windows ### 18 | # Windows image file caches 19 | Thumbs.db 20 | ehthumbs.db 21 | 22 | # Folder config file 23 | Desktop.ini 24 | 25 | # Recycle Bin used on file shares 26 | $RECYCLE.BIN/ 27 | 28 | # Windows Installer files 29 | *.cab 30 | *.msi 31 | *.msm 32 | *.msp 33 | 34 | # Windows shortcuts 35 | *.lnk 36 | 37 | 38 | ### Intellij ### 39 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 40 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 41 | 42 | # User-specific stuff: 43 | #.idea/workspace.xml 44 | #.idea/tasks.xml 45 | #.idea/dictionaries/ 46 | 47 | # Sensitive or high-churn files: 48 | #.idea/dataSources.ids 49 | #.idea/dataSources.xml 50 | #.idea/dataSources.local.xml 51 | #.idea/sqlDataSources.xml 52 | #.idea/dynamic.xml 53 | #.idea/uiDesigner.xml 54 | 55 | # Gradle: 56 | #.idea/gradle.xml 57 | ##.idea/libraries 58 | 59 | # Mongo Explorer plugin: 60 | #.idea/mongoSettings.xml 61 | 62 | ## File-based project format: 63 | *.iws 64 | 65 | ## Plugin-specific files: 66 | 67 | # IntelliJ 68 | /out/ 69 | 70 | # mpeltonen/sbt-idea plugin 71 | .idea_modules/ 72 | 73 | # JIRA plugin 74 | atlassian-ide-plugin.xml 75 | 76 | # Crashlytics plugin (for Android Studio and IntelliJ) 77 | com_crashlytics_export_strings.xml 78 | crashlytics.properties 79 | crashlytics-build.properties 80 | fabric.properties 81 | 82 | ### Intellij Patch ### 83 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 84 | 85 | # *.iml 86 | # modules.xml 87 | # .idea/misc.xml 88 | # *.ipr 89 | 90 | 91 | ### Maven ### 92 | target/ 93 | pom.xml.tag 94 | pom.xml.releaseBackup 95 | pom.xml.versionsBackup 96 | pom.xml.next 97 | release.properties 98 | dependency-reduced-pom.xml 99 | buildNumber.properties 100 | .mvn/timing.properties 101 | 102 | -------------------------------------------------------------------------------- /apexlink/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /apexlink/.idea/.idea/.idea.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apexlink/.idea/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apexlink/.idea/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1.7 9 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /apexlink/.idea/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /apexlink/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /apexlink/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /apexlink/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /apexlink/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /apexlink/.idea/dictionaries/kevin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | declarators 5 | deployer 6 | fieldsets 7 | intelli 8 | jsonrpc 9 | multiselect 10 | nawforce 11 | pkgforce 12 | shogowada 13 | tostring 14 | unmanaged 15 | upickle 16 | 17 | 18 | -------------------------------------------------------------------------------- /apexlink/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apexlink/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_github_nawforce_scala_json_rpc_2_13_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_github_nawforce_scala_json_rpc_upickle_json_serializer_2_13_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_google_guava_guava_18_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_google_jimfs_jimfs_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_lihaoyi_geny_2_13_0_6_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_lihaoyi_ujson_2_13_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_lihaoyi_upack_2_13_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_lihaoyi_upickle_2_13_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_lihaoyi_upickle_core_2_13_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__com_lihaoyi_upickle_implicits_2_13_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_antlr_antlr4_runtime_4_8_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scala_js_scalajs_stubs_2_13_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scala_lang_modules_scala_collection_compat_2_13_2_1_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scala_lang_modules_scala_parallel_collections_2_13_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scala_lang_modules_scala_xml_2_13_1_3_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scala_lang_scala_library_2_13_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Scala_2_13 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scala_lang_scala_reflect_2_13_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalactic_scalactic_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_compatible_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_core_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_diagrams_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_featurespec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_flatspec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_freespec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_funspec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_funsuite_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_matchers_core_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_mustmatchers_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_propspec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_refspec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_shouldmatchers_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/libraries/Maven__org_scalatest_scalatest_wordspec_2_13_3_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apexlink/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | 20 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /apexlink/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /apexlink/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /apexlink/.idea/scala_compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /apexlink/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /apexlink/.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 2.6.3 2 | continuationIndent.defnSite = 2 3 | optIn.configStyleArguments = false 4 | align.preset = more 5 | maxColumn = 100 6 | -------------------------------------------------------------------------------- /apexlink/images/FindZombies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nawforce/apex-link/7688adcb7a2d7f8aa28d0618ffb2a3aa81151858/apexlink/images/FindZombies.png -------------------------------------------------------------------------------- /apexlink/images/UnusedField.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nawforce/apex-link/7688adcb7a2d7f8aa28d0618ffb2a3aa81151858/apexlink/images/UnusedField.png -------------------------------------------------------------------------------- /apexlink/src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.nawforce.apexlink.ApexLink 3 | Class-Path: 4 | antlr4-runtime-4.8-1.jar 5 | apex-parser-3.0.0.jar 6 | geny_2.13-0.6.2.jar 7 | pkgforce_2.13-2.3.7.jar 8 | runforce-55.5.0.jar 9 | scala-collection-compat_2.13-2.1.4.jar 10 | scala-json-rpc-upickle-json-serializer_2.13-1.0.1.jar 11 | scala-json-rpc_2.13-1.0.1.jar 12 | scala-library-2.13.3.jar 13 | scala-parallel-collections_2.13-1.0.0.jar 14 | scala-reflect-2.13.3.jar 15 | scala-xml_2.13-1.3.0.jar 16 | ujson_2.13-1.2.0.jar 17 | upack_2.13-1.2.0.jar 18 | upickle-core_2.13-1.2.0.jar 19 | upickle-implicits_2.13-1.2.0.jar 20 | upickle_2.13-1.2.0.jar 21 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/ApexLink.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink 16 | 17 | import com.nawforce.apexlink.cmds.Check 18 | 19 | object ApexLink { 20 | def main(args: Array[String]): Unit = { 21 | System.exit(Check.run(args)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/api/ServerOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.api 16 | 17 | /** Collection of Ops functions for changing global behaviours */ 18 | object ServerOps { 19 | private var lazyBlocks: Boolean = true 20 | private var duplicateObjectMonitor: Boolean = false 21 | private var autoFlush: Boolean = true 22 | 23 | /** Are we using lazy blocks, this is enabled by default */ 24 | def getLazyBlocks: Boolean = { 25 | lazyBlocks 26 | } 27 | 28 | /** Update lazy block flag */ 29 | def setLazyBlocks(enable: Boolean): Unit = { 30 | lazyBlocks = enable 31 | } 32 | 33 | /** Is duplicate object monitor enabled, this is disabled by default */ 34 | def getDuplicateObjectMonitoring: Boolean = { 35 | duplicateObjectMonitor 36 | } 37 | 38 | /** Update duplicate object monitor flag */ 39 | def setDuplicateObjectMonitoring(enable: Boolean): Unit = { 40 | duplicateObjectMonitor = enable 41 | } 42 | 43 | /** Is auto flushing, this is enabled by default */ 44 | def getAutoFlush: Boolean = { 45 | autoFlush 46 | } 47 | 48 | /** Update auto flushing flag */ 49 | def setAutoFlush(enable: Boolean): Boolean = { 50 | val current = autoFlush 51 | autoFlush = enable 52 | current 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/cmds/Server.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.cmds 16 | 17 | import com.nawforce.apexlink.rpc.RPCServer 18 | 19 | object Server { 20 | 21 | def main(args: Array[String]): Unit = { 22 | try { 23 | new RPCServer().run() 24 | } catch { 25 | case ex: Throwable => 26 | ex.printStackTrace() 27 | System.exit(-1) 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/deps/TransitiveCollector.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.deps 16 | 17 | import com.nawforce.apexlink.api.Org 18 | import com.nawforce.pkgforce.names.{Name, Names, TypeIdentifier} 19 | 20 | import scala.collection.mutable 21 | 22 | /** Transitive dependency helper */ 23 | class TransitiveCollector(org: Org, apexOnly: Boolean) { 24 | private val packagesByNamespace = 25 | org.getPackages().map(pkg => (Name(pkg.getNamespaces(false).head), pkg)).toMap 26 | 27 | def count(id: TypeIdentifier, ignoring: Array[TypeIdentifier]): Int = { 28 | transitives(id, ignoring).length 29 | } 30 | 31 | def transitives( 32 | id: TypeIdentifier, 33 | ignoring: Array[TypeIdentifier] = Array() 34 | ): Array[TypeIdentifier] = { 35 | val pkg = packagesByNamespace.get(id.namespace.getOrElse(Names.Empty)) 36 | 37 | val depsSeen = mutable.Set[TypeIdentifier]() 38 | depsSeen.add(id) 39 | ignoring.foreach(i => depsSeen.add(i)) 40 | val deps = mutable.ArrayBuffer[TypeIdentifier]() 41 | deps.append(id) 42 | var current = 0 43 | while (current < deps.size) { 44 | pkg 45 | .flatMap(pkg => { 46 | Option(pkg.getDependencies(deps(current), outerInheritanceOnly = false, apexOnly)) 47 | }) 48 | .getOrElse(Array[TypeIdentifier]()) 49 | .filterNot(depsSeen.contains) 50 | .foreach(t => { 51 | deps.append(t) 52 | depsSeen.add(t) 53 | }) 54 | current += 1 55 | } 56 | deps.remove(0) 57 | deps.toArray 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/finding/TypeError.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.finding 16 | 17 | import com.nawforce.pkgforce.diagnostics.{Diagnostic, Issue, MISSING_CATEGORY} 18 | import com.nawforce.pkgforce.names.TypeName 19 | import com.nawforce.pkgforce.path.PathLocation 20 | 21 | /** Collection of error types returned from type requests */ 22 | sealed abstract class TypeError(val typeName: TypeName) { 23 | def asIssue(location: PathLocation): Issue 24 | 25 | // Protect against old way of using this 26 | override def toString: String = throw new IllegalArgumentException 27 | } 28 | 29 | final case class MissingType(_typeName: TypeName) extends TypeError(_typeName) { 30 | def asIssue(location: PathLocation): Issue = { 31 | new Issue( 32 | location.path, 33 | Diagnostic(MISSING_CATEGORY, location.location, s"No type declaration found for '$typeName'") 34 | ) 35 | } 36 | 37 | // Protect against old way of using this 38 | override def toString: String = throw new IllegalArgumentException 39 | } 40 | 41 | final case class WrongTypeArguments(_typeName: TypeName, expected: Integer) 42 | extends TypeError(_typeName) { 43 | def asIssue(location: PathLocation): Issue = { 44 | new Issue( 45 | location.path, 46 | Diagnostic( 47 | MISSING_CATEGORY, 48 | location.location, 49 | s"Wrong number of type arguments for '$typeName', expected $expected" 50 | ) 51 | ) 52 | } 53 | 54 | // Protect against old way of using this 55 | override def toString: String = throw new IllegalArgumentException 56 | } 57 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/memory/Monitor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink.memory 15 | 16 | import com.nawforce.apexlink.api.ServerOps 17 | import com.nawforce.apexlink.types.core.TypeDeclaration 18 | import com.nawforce.pkgforce.diagnostics.LoggerOps 19 | 20 | object Monitor { 21 | val map = new SkinnyWeakSet[AnyRef]() 22 | var duplicateTypes: SkinnyWeakSet[TypeDeclaration] = _ 23 | 24 | def push[T <: AnyRef](t: T): Unit = { 25 | if (ServerOps.getDuplicateObjectMonitoring) 26 | map.add(t) 27 | } 28 | 29 | def size: Int = map.size 30 | 31 | def reportDuplicateTypes(): Unit = { 32 | if (ServerOps.getDuplicateObjectMonitoring) { 33 | val tdsByName = map.toSet.toArray.collect { case td: TypeDeclaration => (td.typeName, td) } 34 | val typeNames = tdsByName.map(_._1) 35 | val duplicates = typeNames.toSeq.groupBy(identity).collect { case (t, Seq(_, _, _*)) => t } 36 | if (duplicates.nonEmpty) { 37 | duplicates.foreach(typeName => { 38 | LoggerOps.debug(s"Duplicate types found for $typeName") 39 | }) 40 | duplicateTypes = new SkinnyWeakSet[TypeDeclaration]() 41 | duplicates.foreach( 42 | dup => tdsByName.filter(_._1 == dup).foreach(x => duplicateTypes.add(x._2)) 43 | ) 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/memory/SkinnySet.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.memory 16 | 17 | import scala.collection.mutable 18 | 19 | /** Low memory set. Uses an array for small sizes before swapping to a set. */ 20 | final class SkinnySet[T <: AnyRef] { 21 | private var arrayOf: mutable.ArrayBuffer[T] = _ 22 | private var setOf: mutable.Set[T] = _ 23 | 24 | def isEmpty: Boolean = { 25 | if (setOf != null) 26 | setOf.isEmpty 27 | else if (arrayOf != null) 28 | arrayOf.isEmpty 29 | else 30 | true 31 | } 32 | 33 | def nonEmpty: Boolean = !isEmpty 34 | 35 | def size: Int = { 36 | if (setOf != null) 37 | setOf.size 38 | else if (arrayOf != null) 39 | arrayOf.size 40 | else 41 | 0 42 | } 43 | 44 | def add(t: T): Unit = { 45 | if (setOf != null) 46 | setOf.add(t) 47 | else { 48 | if (arrayOf == null) 49 | arrayOf = new mutable.ArrayBuffer[T](4) 50 | arrayOf.append(t) 51 | if (arrayOf.size > 64) 52 | arrayOf = arrayOf.distinct 53 | } 54 | 55 | if (arrayOf != null && arrayOf.length > 64) { 56 | setOf = new mutable.HashSet[T]() 57 | arrayOf.foreach(setOf.add) 58 | arrayOf = null 59 | } 60 | } 61 | 62 | def toSet: Set[T] = { 63 | if (setOf != null) 64 | setOf.toSet 65 | else if (arrayOf != null) 66 | arrayOf.toSet 67 | else 68 | Set.empty 69 | } 70 | 71 | def toIterable: mutable.Iterable[T] = { 72 | if (setOf != null) { 73 | setOf 74 | } else if (arrayOf != null) { 75 | arrayOf = arrayOf.distinct 76 | arrayOf 77 | } else { 78 | mutable.Iterable() 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/names/TypeIdentifiers.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink.names 15 | 16 | import com.nawforce.apexlink.names.TypeNames.TypeNameUtils 17 | import com.nawforce.pkgforce.names.{Names, TypeIdentifier} 18 | 19 | object TypeIdentifiers { 20 | implicit class TypeIdentifierUtils(typeIdentifier: TypeIdentifier) { 21 | 22 | def intern: TypeIdentifier = 23 | TypeIdentifier(typeIdentifier.namespace.map(Names(_)), typeIdentifier.typeName.intern) 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/plugins/Plugin.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink.plugins 15 | 16 | import com.nawforce.apexlink.cst._ 17 | import com.nawforce.apexlink.plugins.Plugin.emptyTypes 18 | import com.nawforce.apexlink.types.apex.{SummaryDeclaration, TriggerDeclaration} 19 | import com.nawforce.apexlink.types.core.DependentType 20 | 21 | class Plugin(td: DependentType) { 22 | 23 | def onTypeValidated(): Seq[DependentType] = { 24 | td match { 25 | case td: ClassDeclaration => onClassValidated(td) 26 | case td: InterfaceDeclaration => onInterfaceValidated(td) 27 | case td: EnumDeclaration => onEnumValidated(td) 28 | case td: TriggerDeclaration => onTriggerValidated(td) 29 | case td: SummaryDeclaration => onSummaryValidated(td) 30 | case _ => emptyTypes 31 | } 32 | } 33 | 34 | def onClassValidated(td: ClassDeclaration): Seq[DependentType] = emptyTypes 35 | 36 | def onInterfaceValidated(td: InterfaceDeclaration): Seq[DependentType] = emptyTypes 37 | 38 | def onEnumValidated(td: EnumDeclaration): Seq[DependentType] = emptyTypes 39 | 40 | def onTriggerValidated(td: TriggerDeclaration): Seq[DependentType] = emptyTypes 41 | 42 | def onSummaryValidated(td: SummaryDeclaration): Seq[DependentType] = emptyTypes 43 | 44 | def onBlockValidated(block: Block, isStatic: Boolean, context: BlockVerifyContext): Unit = {} 45 | } 46 | 47 | object Plugin { 48 | val emptyTypes: Seq[DependentType] = Seq.empty 49 | } 50 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/plugins/PluginDispatcher.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.plugins 16 | 17 | import com.nawforce.apexlink.cst.{Block, BlockVerifyContext} 18 | import com.nawforce.apexlink.types.core.DependentType 19 | 20 | import java.lang.reflect.Constructor 21 | 22 | class PluginDispatcher(td: DependentType, plugins: Seq[Plugin]) extends Plugin(td) { 23 | 24 | override def onTypeValidated(): Seq[DependentType] = { 25 | plugins.flatMap(_.onTypeValidated()) 26 | } 27 | 28 | override def onBlockValidated( 29 | block: Block, 30 | isStatic: Boolean, 31 | context: BlockVerifyContext 32 | ): Unit = { 33 | plugins.foreach(_.onBlockValidated(block, isStatic, context)) 34 | } 35 | } 36 | 37 | object PluginDispatcher { 38 | def apply(td: DependentType, plugins: Seq[Constructor[_ <: Plugin]]): PluginDispatcher = { 39 | new PluginDispatcher( 40 | td, 41 | plugins.map(plugin => { 42 | plugin.newInstance(td) 43 | }) 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/rpc/CompletionItemLink.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.apexlink.rpc 2 | 3 | import com.nawforce.apexlink.types.core.{FieldDeclaration, MethodDeclaration, TypeDeclaration} 4 | import com.nawforce.pkgforce.parsers.{CLASS_NATURE, ENUM_NATURE, INTERFACE_NATURE} 5 | import com.nawforce.pkgforce.path.Location 6 | import io.github.shogowada.scala.jsonrpc.serializers.JSONRPCPickler.{macroRW, ReadWriter => RW} 7 | 8 | case class CompletionItemLink(label: String, kind: String, detail: String = null) 9 | 10 | object CompletionItemLink { 11 | implicit val rw: RW[CompletionItemLink] = macroRW 12 | implicit val rwLocation: RW[Location] = macroRW 13 | 14 | def apply(td: TypeDeclaration): Option[CompletionItemLink] = { 15 | val detail = td.modifiers.map(_.name).mkString(" ") 16 | td.nature match { 17 | case CLASS_NATURE => Some(CompletionItemLink(td.typeName.name.value, "Class", detail)) 18 | case INTERFACE_NATURE => Some(CompletionItemLink(td.typeName.name.value, "Interface", detail)) 19 | case ENUM_NATURE => Some(CompletionItemLink(td.typeName.name.value, "Enum", detail)) 20 | case _ => None 21 | } 22 | } 23 | 24 | def apply(field: FieldDeclaration): CompletionItemLink = { 25 | CompletionItemLink(field.name.toString, "Field", field.toString) 26 | } 27 | 28 | def apply(method: MethodDeclaration): CompletionItemLink = { 29 | CompletionItemLink( 30 | method.name.toString + "(" + method.parameters.map(_.name.toString()).mkString(", ") + ")", 31 | "Method", 32 | method.toString 33 | ) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/rpc/LocationLink.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink.rpc 15 | 16 | import com.nawforce.pkgforce.path.Location 17 | import io.github.shogowada.scala.jsonrpc.serializers.JSONRPCPickler.{macroRW, ReadWriter => RW} 18 | 19 | /** A link for a given position, can be used for definition or reference links. origin is the calculated extent of 20 | * the link that was selected. targetPath is where the definition or reference refers to. Within target path, target 21 | * is the full extend of the definition whereas targetSelection is just the extent of the link itself. 22 | */ 23 | case class LocationLink( 24 | origin: Location, 25 | targetPath: String, 26 | target: Location, 27 | targetSelection: Location 28 | ) 29 | 30 | object LocationLink { 31 | implicit val rw: RW[LocationLink] = macroRW 32 | implicit val rwLocation: RW[Location] = macroRW 33 | } 34 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/types/core/BasicTypeDeclaration.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.types.core 16 | 17 | import com.nawforce.apexlink.org.Module 18 | import com.nawforce.pkgforce.modifiers.{Modifier, ModifierOps} 19 | import com.nawforce.pkgforce.names.{Name, TypeName} 20 | import com.nawforce.pkgforce.parsers.{CLASS_NATURE, Nature} 21 | import com.nawforce.pkgforce.path.PathLike 22 | 23 | import scala.collection.immutable.ArraySeq 24 | 25 | class BasicTypeDeclaration(val paths: ArraySeq[PathLike], module: Module, val typeName: TypeName) 26 | extends TypeDeclaration { 27 | 28 | override val moduleDeclaration: Option[Module] = Some(module) 29 | override val name: Name = typeName.name 30 | override val outerTypeName: Option[TypeName] = None 31 | override val nature: Nature = CLASS_NATURE 32 | override val modifiers: ArraySeq[Modifier] = ModifierOps.emptyModifiers 33 | override lazy val isComplete: Boolean = true 34 | 35 | override val superClass: Option[TypeName] = None 36 | override val interfaces: ArraySeq[TypeName] = ArraySeq() 37 | override def nestedTypes: ArraySeq[TypeDeclaration] = TypeDeclaration.emptyTypeDeclarations 38 | 39 | override val blocks: ArraySeq[BlockDeclaration] = BlockDeclaration.emptyBlockDeclarations 40 | override val fields: ArraySeq[FieldDeclaration] = FieldDeclaration.emptyFieldDeclarations 41 | override val constructors: ArraySeq[ConstructorDeclaration] = 42 | ConstructorDeclaration.emptyConstructorDeclarations 43 | override val methods: ArraySeq[MethodDeclaration] = MethodDeclaration.emptyMethodDeclarations 44 | 45 | override def validate(): Unit = {} 46 | } 47 | 48 | class InnerBasicTypeDeclaration(_paths: ArraySeq[PathLike], _module: Module, _typeName: TypeName) 49 | extends BasicTypeDeclaration(_paths, _module, _typeName) { 50 | override val outerTypeName: Option[TypeName] = typeName.outer 51 | } 52 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/types/core/TypeId.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.types.core 16 | 17 | import com.nawforce.apexlink.org.Module 18 | import com.nawforce.pkgforce.names.{TypeIdentifier, TypeName} 19 | 20 | case class TypeId(module: Module, typeName: TypeName) { 21 | def asTypeIdentifier: TypeIdentifier = { 22 | TypeIdentifier(module.pkg.namespace, typeName) 23 | } 24 | 25 | override def toString: String = asTypeIdentifier.toString 26 | } 27 | -------------------------------------------------------------------------------- /apexlink/src/main/scala/com/nawforce/apexlink/types/other/AnyDeclaration.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.types.other 16 | 17 | import com.nawforce.apexlink.names.TypeNames 18 | import com.nawforce.apexlink.org.Module 19 | import com.nawforce.apexlink.types.core.BasicTypeDeclaration 20 | import com.nawforce.pkgforce.path.PathLike 21 | 22 | /** An any type declaration, there are deliberately very few uses of this, hopefully at some point it 23 | * can be removed. 24 | */ 25 | final case class AnyDeclaration(module: Module) 26 | extends BasicTypeDeclaration(PathLike.emptyPaths, module, TypeNames.Any) 27 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/FileSystemHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink 15 | 16 | import java.nio.file.Files 17 | 18 | import com.google.common.jimfs.{Configuration, Jimfs} 19 | import com.nawforce.pkgforce.documents.ParsedCache 20 | import com.nawforce.pkgforce.path.PathLike 21 | import com.nawforce.runtime.platform.Path 22 | 23 | object FileSystemHelper { 24 | 25 | // Abstract virtual filesystem for testing 26 | def run[T](files: Map[String, String])(verify: PathLike => T): T = { 27 | val config = Configuration 28 | .unix() 29 | .toBuilder 30 | .setWorkingDirectory("/") 31 | .build() 32 | val fs = Jimfs.newFileSystem(config) 33 | val rootDir = fs.getRootDirectories.iterator().next() 34 | files.foreach(kv => { 35 | val path = rootDir.resolve(kv._1) 36 | Files.createDirectories(path.getParent) 37 | Files.write(path, kv._2.getBytes()) 38 | }) 39 | 40 | ParsedCache.clear() 41 | verify(new Path(rootDir)) 42 | } 43 | 44 | // Temp directory based model 45 | def runTempDir[T](files: Map[String, String], setupCache: Boolean = false)( 46 | verify: PathLike => T 47 | ): T = { 48 | val tempDir = Files.createTempDirectory("apexlinktest") 49 | files.foreach(kv => { 50 | val path = tempDir.resolve(kv._1) 51 | Files.createDirectories(path.getParent) 52 | Files.write(path, kv._2.getBytes()) 53 | }) 54 | 55 | // Make sure cache is empty if we are going to use it 56 | if (setupCache) 57 | ParsedCache.clear() 58 | 59 | try { 60 | verify(new Path(tempDir)) 61 | } finally { 62 | files.foreach(kv => { 63 | val path = tempDir.resolve(kv._1) 64 | path.toFile.delete() 65 | }) 66 | tempDir.toFile.delete() 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/cst/ArrayTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.cst 16 | 17 | import com.nawforce.apexlink.TestHelper 18 | import org.scalatest.funsuite.AnyFunSuite 19 | 20 | class ArrayTest extends AnyFunSuite with TestHelper { 21 | 22 | test("Non-Integer index") { 23 | typeDeclaration("public class Dummy {Integer b; {List a; b = a[null].b;}}") 24 | assert(dummyIssues == "Error: line 1 at 54-58: Array indexes must be Integers, found 'null'\n") 25 | } 26 | 27 | test("Integer index") { 28 | typeDeclaration("public class Dummy {Integer b; {List a; b = a[0].b;}}") 29 | assert(dummyIssues.isEmpty) 30 | } 31 | 32 | test("Assignment") { 33 | typeDeclaration("public class Dummy {{String[] a; a=new String[]{'a'}; }}") 34 | assert(dummyIssues.isEmpty) 35 | } 36 | 37 | // TODO: Complete testing 38 | } 39 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/cst/AssignTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.cst 16 | 17 | import com.nawforce.apexlink.{FileSystemHelper, TestHelper} 18 | import com.nawforce.pkgforce.path.PathLike 19 | import org.scalatest.funsuite.AnyFunSuite 20 | 21 | class AssignTest extends AnyFunSuite with TestHelper { 22 | 23 | test("Assign list of ghosted SObject to SObject list") { 24 | FileSystemHelper.run( 25 | Map( 26 | "sfdx-project.json" -> 27 | """{ 28 | |"packageDirectories": [{"path": "force-app"}], 29 | |"plugins": {"dependencies": [{"namespace": "ext"}]} 30 | |}""".stripMargin, 31 | "force-app/Dummy.cls" -> "public class Dummy { {List b; List a = b;} }" 32 | ) 33 | ) { root: PathLike => 34 | createHappyOrg(root) 35 | } 36 | } 37 | 38 | test("Assign list of ghosted types to Object list") { 39 | FileSystemHelper.run( 40 | Map( 41 | "sfdx-project.json" -> 42 | """{ 43 | |"packageDirectories": [{"path": "force-app"}], 44 | |"plugins": {"dependencies": [{"namespace": "ext"}]} 45 | |}""".stripMargin, 46 | "force-app/Dummy.cls" -> "public class Dummy { {List b; List a = b;} }" 47 | ) 48 | ) { root: PathLike => 49 | createHappyOrg(root) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/cst/ConstructorTest.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.apexlink.cst 2 | 3 | import com.nawforce.apexlink.TestHelper 4 | import org.scalatest.funsuite.AnyFunSuite 5 | 6 | class ConstructorTest extends AnyFunSuite with TestHelper { 7 | 8 | test("Basic constructor") { 9 | typeDeclaration("public class Dummy {public dummY() {}}") 10 | assert(dummyIssues.isEmpty) 11 | } 12 | 13 | test("Bad name constructor") { 14 | typeDeclaration("public class Dummy {public Foo() {}}") 15 | assert( 16 | dummyIssues == 17 | "Error: line 1 at 27-30: Constructors should have same name as the class, maybe method return type is missing?\n" 18 | ) 19 | } 20 | 21 | test("Duplicate no args constructor") { 22 | typeDeclaration("public class Dummy {public Dummy() {} private Dummy() {}}") 23 | assert( 24 | dummyIssues == 25 | "Error: line 1 at 46-51: Constructor is a duplicate of an earlier constructor at line 1 at 27-32\n" 26 | ) 27 | } 28 | 29 | test("Duplicate same single args constructor") { 30 | typeDeclaration("public class Dummy {public Dummy(String a) {} private Dummy(String b) {}}") 31 | assert( 32 | dummyIssues == 33 | "Error: line 1 at 54-59: Constructor is a duplicate of an earlier constructor at line 1 at 27-32\n" 34 | ) 35 | } 36 | 37 | test("Duplicate same multi args constructor") { 38 | typeDeclaration( 39 | "public class Dummy {public Dummy(String a, Integer b) {} private Dummy(String c, Integer d) {}}" 40 | ) 41 | assert( 42 | dummyIssues == 43 | "Error: line 1 at 65-70: Constructor is a duplicate of an earlier constructor at line 1 at 27-32\n" 44 | ) 45 | } 46 | 47 | test("Duplicate same args (different typeRef) constructor") { 48 | typeDeclaration( 49 | "public class Dummy {public Dummy(String a) {} private Dummy(System.String b) {}}" 50 | ) 51 | assert( 52 | dummyIssues == 53 | "Error: line 1 at 54-59: Constructor is a duplicate of an earlier constructor at line 1 at 27-32\n" 54 | ) 55 | } 56 | 57 | test("Multiple Duplicate no args constructor") { 58 | typeDeclaration("public class Dummy {public Dummy() {} private Dummy() {} private Dummy() {}}") 59 | assert( 60 | dummyIssues == 61 | "Error: line 1 at 46-51: Constructor is a duplicate of an earlier constructor at line 1 at 27-32\n" + 62 | "Error: line 1 at 65-70: Constructor is a duplicate of an earlier constructor at line 1 at 27-32\n" 63 | ) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/cst/IfTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.apexlink.cst 16 | 17 | import com.nawforce.apexlink.TestHelper 18 | import org.scalatest.funsuite.AnyFunSuite 19 | 20 | class IfTest extends AnyFunSuite with TestHelper { 21 | 22 | test("Block bug") { 23 | typeDeclaration("public class Dummy {{ if (false) String a = ''; else a =''; }}") 24 | assert(!hasIssues) 25 | } 26 | 27 | // TODO: Write some tests! 28 | } 29 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/cst/SafeNavigationTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink.cst 15 | 16 | import com.nawforce.apexlink.TestHelper 17 | import org.scalatest.funsuite.AnyFunSuite 18 | 19 | class SafeNavigationTest extends AnyFunSuite with TestHelper { 20 | 21 | test("Field Reference") { 22 | typeDeclaration("public class Dummy {String a; { String b = this?.a; }}") 23 | assert(!hasIssues) 24 | } 25 | 26 | test("Method Reference") { 27 | typeDeclaration("public class Dummy {String func(){} { String b = this?.func(); }}") 28 | assert(!hasIssues) 29 | } 30 | 31 | test("Field nested reference") { 32 | typeDeclaration("public class Dummy {Dummy a; { Dummy b = this?.a?.a; }}") 33 | assert(!hasIssues) 34 | } 35 | 36 | test("Method nexted reference") { 37 | typeDeclaration("public class Dummy {Dummy func(){} { Dummy b = this?.func()?.func(); }}") 38 | assert(!hasIssues) 39 | } 40 | 41 | test("Static field reference") { 42 | typeDeclaration("public class Dummy {static String a; { String b = Dummy?.a; }}") 43 | assert( 44 | dummyIssues == "Error: line 1 at 50-58: Safe navigation operator (?.) can not be used on static references\n" 45 | ) 46 | } 47 | 48 | test("Static method reference") { 49 | typeDeclaration("public class Dummy {static String func(){} { String b = Dummy?.func(); }}") 50 | assert( 51 | dummyIssues == "Error: line 1 at 56-69: Safe navigation operator (?.) can not be used on static references\n" 52 | ) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/cst/VariablesTest.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.apexlink.cst 2 | 3 | import com.nawforce.apexlink.TestHelper 4 | import org.scalatest.funsuite.AnyFunSuite 5 | 6 | class VariablesTest extends AnyFunSuite with TestHelper { 7 | 8 | test("Boolean variable declaration") { 9 | typeDeclaration("public class Dummy { {Boolean b = 1;} }") 10 | assert( 11 | dummyIssues == "Error: line 1 at 30-35: Incompatible types in assignment, from 'System.Integer' to 'System.Boolean'\n" 12 | ) 13 | } 14 | 15 | test("Database.QueryLocator variable declaration") { 16 | typeDeclaration("""public class Dummy {{ 17 | Database.QueryLocator result; 18 | System.Iterator < SObject > iteratorResult = result.iterator(); 19 | }}""") 20 | assert(!hasIssues) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /apexlink/src/test/scala/com/nawforce/apexlink/parsers/CodeParserTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexlink.parsers 15 | 16 | import com.nawforce.apexlink.api.ServerOps 17 | import com.nawforce.apexlink.{FileSystemHelper, TestHelper} 18 | import com.nawforce.pkgforce.path.PathLike 19 | import com.nawforce.runtime.parsers.{CodeParser, SourceData} 20 | import com.nawforce.runtime.platform.Path 21 | import org.scalatest.BeforeAndAfter 22 | import org.scalatest.funsuite.AnyFunSuite 23 | 24 | class CodeParserTest extends AnyFunSuite with BeforeAndAfter with TestHelper { 25 | 26 | before { 27 | ServerOps.setAutoFlush(false) 28 | } 29 | 30 | after { 31 | ServerOps.setAutoFlush(true) 32 | } 33 | 34 | test("Good class") { 35 | val parser = CodeParser(Path("Hello.cls"), SourceData("public class Hello {}")) 36 | val result = parser.parseClass() 37 | assert(result.issues.isEmpty) 38 | } 39 | 40 | test("Broken class") { 41 | val parser = CodeParser(Path("Hello.cls"), SourceData("public class Hello {")) 42 | val result = parser.parseClass() 43 | assert(result.issues.nonEmpty) 44 | } 45 | 46 | test("UTF-8 class") { 47 | FileSystemHelper.run( 48 | Map("Dummy.cls" -> "public class Dummy {{String a = 'Kimi Räikkönen';}}") 49 | ) { root: PathLike => 50 | val org = createOrg(root) 51 | assert(org.issues.isEmpty) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pkgforce/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .bsp/ 3 | .metals/ 4 | .vscode 5 | **/target/ 6 | **/node_modules/ 7 | js/npm/package-lock.json 8 | js/npm/pkgforce-fastopt.js 9 | js/npm/pkgforce-fastopt.js.map 10 | js/npm/pkgforce-opt.js 11 | js/npm/pkgforce-opt.js.map 12 | js/npm/lib/ 13 | 14 | -------------------------------------------------------------------------------- /pkgforce/.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 2.6.3 2 | continuationIndent.defnSite = 2 3 | optIn.configStyleArguments = false 4 | align.preset = more 5 | maxColumn = 100 6 | -------------------------------------------------------------------------------- /pkgforce/README.md: -------------------------------------------------------------------------------- 1 | ## pkgforce 2 | 3 | Provides utility functions for handling collections of Salesforce metadata. The library is implemented in Scala in a 4 | style that allows it to be compiled for either use on both JVM or node. 5 | 6 | ### NPM API 7 | 8 | The library is mostly written in Scala to support dual building for Java & Node. This model works well when you are 9 | also using Scala and is usable from Java but is more awkward for Node clients. To overcome this a small part of the 10 | library for resolving type names to paths is exposed in a Node friendly NPM module. 11 | 12 | To use this, first create a workspace: 13 | 14 | const workspace = Workspaces.get("mydirectory") // Will throw on errors 15 | 16 | Call findType on the workspace: 17 | 18 | const fooPath = workspace.findType("ns001.Foo") // Returns null if type is unknown 19 | 20 | A workspace here is simply the directory containing Salesforce metadata, typically it's the directory in which 21 | sfdx-project.json resides. 22 | 23 | ### Java Distribution via Maven 24 | 25 | To use in a JVM project 26 | 27 | 28 | com.github.nawforce 29 | pkgforce 30 | 2.3.7/version> 31 | 32 | 33 | ### Scala/Scala.js 34 | 35 | For scala.js: 36 | 37 | libraryDependencies += "com.github.nawforce" %%% "pkgforce" % "2.3.7" 38 | 39 | For scala: 40 | 41 | libraryDependencies += "com.github.nawforce" % "pkgforce" % "2.3.7" 42 | 43 | ### Building 44 | 45 | The dual build (Java & JS) is handled by [sbt](https://www.scala-sbt.org/): 46 | 47 | sbt build 48 | 49 | To run tests: 50 | 51 | sbt test 52 | 53 | A maven pom.xml is also provided to aid compatibility with IntelliJ. See top level README.md for details on use. 54 | -------------------------------------------------------------------------------- /pkgforce/js/npm/.gitignore: -------------------------------------------------------------------------------- 1 | src/pkgforce.js 2 | README.md 3 | -------------------------------------------------------------------------------- /pkgforce/js/npm/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nawforce/apex-link/7688adcb7a2d7f8aa28d0618ffb2a3aa81151858/pkgforce/js/npm/.npmignore -------------------------------------------------------------------------------- /pkgforce/js/npm/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug Jest Tests", 9 | "type": "node", 10 | "request": "launch", 11 | "runtimeArgs": [ 12 | "--inspect-brk", 13 | "${workspaceRoot}/node_modules/.bin/jest", 14 | "--runInBand" 15 | ], 16 | "console": "integratedTerminal", 17 | "internalConsoleOptions": "neverOpen" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /pkgforce/js/npm/jestconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "transform": { 3 | "^.+\\.tsx?$": "ts-jest" 4 | }, 5 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | "moduleFileExtensions": [ 7 | "ts", 8 | "tsx", 9 | "js", 10 | "jsx", 11 | "json", 12 | "node" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /pkgforce/js/npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pkgforce", 3 | "version": "2.3.7", 4 | "description": "Salesforce Metadata Management Utility Library", 5 | "publisher": "KevinJones", 6 | "repository": "nawforce/pkgforce", 7 | "author": "Kevin Jones (https://github.com/nawforce)", 8 | "license": "BSD-3-Clause", 9 | "bugs": "https://github.com/nawforce/pkgforce/issues", 10 | "icon": "logo.png", 11 | "scripts": { 12 | "build": "tsc", 13 | "test": "jest --config jestconfig.json lib" 14 | }, 15 | "main": "lib/pkgforce.js", 16 | "typings": "src/pkgforce.d.ts", 17 | "files": [ 18 | "src/pkgforce.d.ts" 19 | ], 20 | "dependencies": { 21 | "antlr4ts": "0.5.0-alpha.4", 22 | "@apexdevtools/apex-parser": "3.0.0", 23 | "vf-parser": "1.0.0", 24 | "@xmldom/xmldom": "0.7.5" 25 | }, 26 | "devDependencies": { 27 | "@types/jest": "^27.0.2", 28 | "fs-monkey": "0.3.3", 29 | "jest": "^27.2.5", 30 | "memfs": "3.2.0", 31 | "ts-jest": "^27.0.5", 32 | "typescript": "^4.4.4" 33 | }, 34 | "engines": { 35 | "node": ">=8.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkgforce/js/npm/src/__tests__/WorkspaceTest.ts: -------------------------------------------------------------------------------- 1 | import {Workspaces} from "../pkgforce"; 2 | import {vol} from "memfs"; 3 | import {patchFs} from "fs-monkey"; 4 | 5 | test("Bad directory", () => { 6 | try { 7 | Workspaces.get("foo"); 8 | expect(true).toBe(false); 9 | } catch (err) { 10 | expect(err.message).toMatch(/.*No directory at .*/); 11 | } 12 | }); 13 | 14 | test("Empty directory", () => { 15 | vol.fromJSON({"/pkg1/README.md": ""}); 16 | const unpatch = patchFs(vol); 17 | try { 18 | const workspace = Workspaces.get("/pkg1"); 19 | expect(workspace).toBeDefined(); 20 | expect(workspace.findType("Foo")).toBeNull; 21 | } finally { 22 | unpatch(); 23 | } 24 | }); 25 | 26 | test("MDAPI Class", () => { 27 | vol.fromJSON({"/pkg2/classes/Foo.cls": ""}); 28 | const unpatch = patchFs(vol); 29 | try { 30 | const workspace = Workspaces.get("/pkg2"); 31 | expect(workspace).toBeDefined(); 32 | expect(workspace.findType("Foo")).toEqual(["/pkg2/classes/Foo.cls"]); 33 | } finally { 34 | unpatch(); 35 | } 36 | }); 37 | 38 | test("SFDX Bad Project file", () => { 39 | vol.fromJSON({"/pkg3/sfdx-project.json": ""}); 40 | const unpatch = patchFs(vol); 41 | try { 42 | const workspace = Workspaces.get("/pkg3"); 43 | expect(true).toBe(false); 44 | } catch (err) { 45 | expect(err.message).toMatch( 46 | "/pkg3/sfdx-project.json line 1 Error Failed to parse - ujson.IncompleteParseException: exhausted input" 47 | ); 48 | } finally { 49 | unpatch(); 50 | } 51 | }); 52 | 53 | test("SFDX without namespace", () => { 54 | vol.fromJSON({ 55 | "/pkg4/sfdx-project.json": '{ "packageDirectories": [{"path": "classes"}]}', 56 | "/pkg4/classes/Foo.cls": "", 57 | }); 58 | const unpatch = patchFs(vol); 59 | try { 60 | const workspace = Workspaces.get("/pkg4"); 61 | expect(workspace).toBeDefined(); 62 | expect(workspace.findType("Foo")).toEqual(["/pkg4/classes/Foo.cls"]); 63 | } finally { 64 | unpatch(); 65 | } 66 | }); 67 | 68 | test("SFDX with namespace", () => { 69 | vol.fromJSON({ 70 | "/pkg5/sfdx-project.json": '{ "packageDirectories": [{"path": "classes"}], "namespace": "ns001"}', 71 | "/pkg5/classes/Foo.cls": "", 72 | }); 73 | const unpatch = patchFs(vol); 74 | try { 75 | const workspace = Workspaces.get("/pkg5"); 76 | expect(workspace).toBeDefined(); 77 | expect(workspace.findType("ns001.Foo")).toEqual(["/pkg5/classes/Foo.cls"]); 78 | } finally { 79 | unpatch(); 80 | } 81 | }); 82 | -------------------------------------------------------------------------------- /pkgforce/js/npm/src/pkgforce.d.ts: -------------------------------------------------------------------------------- 1 | export declare class WorkspaceException { 2 | message: string; 3 | } 4 | 5 | export declare class Workspace { 6 | findType(name: string): string | null; 7 | } 8 | 9 | export declare class Workspaces { 10 | static get(path: string): Workspace; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /pkgforce/js/npm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "rootDir": "src", 8 | "outDir": "lib", 9 | "allowJs": true, 10 | "esModuleInterop": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/apexparser/ApexLexer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexparser 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("@apexdevtools/apex-parser", "ApexLexer") 21 | class ApexLexer(stream: CaseInsensitiveInputStream) extends js.Object {} 22 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/apexparser/CaseInsensitiveInputStream.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.apexparser 15 | 16 | import com.nawforce.runtime.parsers.antlr.CharStream 17 | 18 | import scala.scalajs.js 19 | import scala.scalajs.js.annotation.JSImport 20 | 21 | @js.native 22 | @JSImport("@apexdevtools/apex-parser", "CaseInsensitiveInputStream") 23 | class CaseInsensitiveInputStream(src: CharStream) extends CharStream {} 24 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/pkgforce/api/Issue.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.api 15 | 16 | trait Issue { 17 | /* The file path where the issue was found */ 18 | def filePath(): String 19 | 20 | /* The location within the file */ 21 | def fileLocation(): IssueLocation 22 | 23 | /* The category of the issue, one of "Syntax", "Error", "Missing", "Warning" or "Unused" */ 24 | def category(): String 25 | 26 | /* The issue message */ 27 | def message(): String 28 | 29 | /* Is this considered an error issue, rather than a warning */ 30 | def isError(): java.lang.Boolean 31 | 32 | /* Format as String, filePath is omitted to avoid duplicating over multiple Issues */ 33 | def asString: String = category() + ": " + fileLocation().displayPosition + ": " + message() 34 | 35 | override def toString: String = filePath() + ": " + asString 36 | } 37 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/pkgforce/api/IssueLocation.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.api 15 | 16 | trait IssueLocation { 17 | def startLineNumber(): Int 18 | def startCharOffset(): Int 19 | def endLineNumber(): Int 20 | def endCharOffset(): Int 21 | 22 | def displayPosition: String = { 23 | if ( 24 | startLineNumber() == 1 && endLineNumber() == Int.MaxValue && startCharOffset() == 0 && endCharOffset() == 0 25 | ) { 26 | s"line 1" 27 | } else if (startLineNumber() == endLineNumber()) { 28 | if (startCharOffset() == 0 && endCharOffset() == 0) 29 | s"line ${startLineNumber()}" 30 | else if (startCharOffset() == endCharOffset()) 31 | s"line ${startLineNumber()} at ${startCharOffset()}" 32 | else 33 | s"line ${startLineNumber()} at ${startCharOffset()}-${endCharOffset()}" 34 | } else { 35 | if (startCharOffset() == 0 && endCharOffset() == 0) 36 | s"line ${startLineNumber()} to ${endLineNumber()}" 37 | else 38 | s"line ${startLineNumber()}:${startCharOffset()} to ${endLineNumber()}:${endCharOffset()}" 39 | } 40 | } 41 | 42 | def contains(line: Int, offset: Int): Boolean = { 43 | !(line < startLineNumber() || line > endLineNumber() || 44 | (line == startLineNumber() && offset < startCharOffset()) || 45 | (line == endLineNumber() && offset > endCharOffset())) 46 | } 47 | 48 | def contains(other: IssueLocation): Boolean = { 49 | contains(other.startLineNumber(), other.startCharOffset()) && 50 | contains(other.endLineNumber(), other.endCharOffset()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/pkgforce/api/Workspaces.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.api 15 | 16 | import com.nawforce.pkgforce.names.DotName 17 | import com.nawforce.pkgforce.path.PathFactory 18 | import com.nawforce.pkgforce.workspace.{Workspace => SWorkspace} 19 | 20 | import scala.collection.mutable 21 | import scala.scalajs.js 22 | import scala.scalajs.js.JSConverters._ 23 | import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel} 24 | 25 | @JSExportTopLevel("WorkspaceException") 26 | class WorkspaceException(val message: String) extends Exception(message) 27 | 28 | @JSExportTopLevel("Workspace") 29 | class Workspace(val workspace: SWorkspace) { 30 | 31 | @JSExport 32 | def findType(name: String): js.Array[String] = { 33 | workspace.get(DotName(name).asTypeName()).map(_.path.toString).toJSArray 34 | } 35 | } 36 | 37 | @JSExportTopLevel("Workspaces") 38 | object Workspaces { 39 | private val workspaces = new mutable.HashMap[String, Workspace]() 40 | 41 | @JSExport 42 | def get(wsPath: String): Workspace = { 43 | 44 | val ws = workspaces.get(wsPath) 45 | if (ws.nonEmpty) 46 | return ws.get 47 | 48 | val issuesAndWorkspace = SWorkspace(PathFactory(wsPath)) 49 | if (issuesAndWorkspace.issues.nonEmpty) { 50 | throw new WorkspaceException(issuesAndWorkspace.issues.head.asString) 51 | } 52 | 53 | issuesAndWorkspace.value 54 | .map(workspace => { 55 | val jsWorkspace = new Workspace(workspace) 56 | workspaces.put(wsPath, new Workspace(workspace)) 57 | jsWorkspace 58 | }) 59 | .orNull 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce 15 | 16 | import java.nio.charset.StandardCharsets 17 | 18 | /** Platform specific handling for Node execution. 19 | * 20 | * Contains a number of abstractions for handling the differences between JVM & Node execution. This is just the JVM 21 | * implementation, the node version of the same abstraction is not in this project. See [[com.nawforce.pkgforce]] for 22 | * the analysis code. 23 | */ 24 | package object runtime { 25 | type SourceBlob = Array[Byte] 26 | 27 | object SourceBlob { 28 | def apply(value: String): SourceBlob = { 29 | value.getBytes(StandardCharsets.UTF_8) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/CollectingErrorListener.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers 15 | 16 | import com.nawforce.pkgforce.diagnostics.{Diagnostic, Issue, SYNTAX_CATEGORY} 17 | import com.nawforce.pkgforce.path.{Location, PathLike} 18 | 19 | import scala.collection.compat.immutable.ArraySeq 20 | import scala.collection.mutable 21 | import scala.scalajs.js 22 | 23 | class CollectingErrorListener(path: PathLike) extends js.Object { 24 | var _issues: mutable.ArrayBuffer[Issue] = _ 25 | 26 | def syntaxError( 27 | recognizer: Any, 28 | offendingSymbol: Any, 29 | line: Int, 30 | charPositionInLine: Int, 31 | msg: String, 32 | e: Any 33 | ): Unit = { 34 | if (_issues == null) 35 | _issues = new mutable.ArrayBuffer[Issue]() 36 | 37 | _issues.addOne( 38 | new Issue(path, Diagnostic(SYNTAX_CATEGORY, Location(line, charPositionInLine), msg)) 39 | ) 40 | } 41 | 42 | def issues: ArraySeq[Issue] = { 43 | if (_issues != null) 44 | ArraySeq.unsafeWrapArray(_issues.toArray) 45 | else 46 | Issue.emptyArray 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/VFLexer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers 15 | 16 | import com.nawforce.runtime.parsers.antlr.CharStream 17 | 18 | import scala.scalajs.js 19 | import scala.scalajs.js.annotation.JSImport 20 | 21 | @js.native 22 | @JSImport("vf-parser", "VFLexer") 23 | class VFLexer(stream: CharStream) extends js.Object { 24 | def removeErrorListeners(): Unit = js.native 25 | def addErrorListener(listener: CollectingErrorListener): Unit = js.native 26 | } 27 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/ANTLRInputStream.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts", "ANTLRInputStream") 21 | class ANTLRInputStream extends js.Object { 22 | def getText(interval: Interval): String = js.native 23 | } 24 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/AbstractParseTreeVisitor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts/tree/AbstractParseTreeVisitor", "AbstractParseTreeVisitor") 21 | class AbstractParseTreeVisitor[Result] extends js.Object { 22 | def visit(tree: ParseTree): Result = js.native 23 | 24 | def visitChildren(node: RuleNode): Result = js.native 25 | def visitTerminal(node: TerminalNode): Result = js.native 26 | def visitErrorNode(node: ErrorNode): Result = js.native 27 | protected def defaultResult(): Result = js.native 28 | protected def aggregateResult(aggregate: Result, nextResult: Result): Result = js.native 29 | protected def shouldVisitNextChild(node: RuleNode, currentResult: Result): Boolean = js.native 30 | } 31 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/ApexParserVisitor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import com.nawforce.apexparser.ApexParser._ 17 | 18 | import scala.scalajs.js 19 | 20 | trait ApexParserVisitor[Result] extends js.Object { 21 | val visitCompilationUnit: js.UndefOr[js.Function1[CompilationUnitContext, Result]] = js.undefined 22 | 23 | val visitTriggerUnit: js.UndefOr[js.Function1[TriggerUnitContext, Result]] = js.undefined 24 | 25 | val visitTypeDeclaration: js.UndefOr[js.Function1[TypeDeclarationContext, Result]] = js.undefined 26 | 27 | val visitClassDeclaration: js.UndefOr[js.Function1[ClassDeclarationContext, Result]] = 28 | js.undefined 29 | val visitInterfaceDeclaration: js.UndefOr[js.Function1[InterfaceDeclarationContext, Result]] = 30 | js.undefined 31 | val visitEnumDeclaration: js.UndefOr[js.Function1[EnumDeclarationContext, Result]] = js.undefined 32 | 33 | val visitFieldDeclaration: js.UndefOr[js.Function1[FieldDeclarationContext, Result]] = 34 | js.undefined 35 | val visitPropertyDeclaration: js.UndefOr[js.Function1[PropertyDeclarationContext, Result]] = 36 | js.undefined 37 | val visitConstructorDeclaration: js.UndefOr[js.Function1[ConstructorDeclarationContext, Result]] = 38 | js.undefined 39 | val visitMethodDeclaration: js.UndefOr[js.Function1[MethodDeclarationContext, Result]] = 40 | js.undefined 41 | val visitInterfaceMethodDeclaration 42 | : js.UndefOr[js.Function1[InterfaceMethodDeclarationContext, Result]] = js.undefined 43 | val visitEnumConstants: js.UndefOr[js.Function1[EnumConstantsContext, Result]] = js.undefined 44 | } 45 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/BufferedTokenStream.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.runtime.parsers.antlr 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.JSImport 5 | 6 | @js.native 7 | @JSImport("antlr4ts", "BufferedTokenStream") 8 | class BufferedTokenStream extends js.Object { 9 | def getHiddenTokensToRight(tokenIndex: Int): js.Array[Token] = js.native 10 | def getHiddenTokensToLeft(tokenIndex: Int): js.Array[Token] = js.native 11 | } 12 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/CharStream.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts/CharStream", "CharStream") 21 | class CharStream extends js.Object {} 22 | 23 | @js.native 24 | @JSImport("antlr4ts/CharStreams", "CharStreams") 25 | object CharStreams extends js.Object { 26 | def fromString(s: String): CharStream = js.native 27 | def fromString(s: String, sourceName: String): CharStream = js.native 28 | } 29 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/CommonTokenStream.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts", "CommonTokenStream") 21 | class CommonTokenStream(lexer: js.Any) extends BufferedTokenStream { 22 | def fill(): Unit = js.native 23 | } 24 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/ErrorNode.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | 18 | @js.native 19 | trait ErrorNode extends TerminalNode 20 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/Interval.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts/misc/Interval", "Interval") 21 | class Interval(a: Int, b: Int) extends js.Object 22 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/ParseTree.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | 18 | @js.native 19 | trait ParseTree extends js.Object { 20 | val text: String = js.native 21 | } 22 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/ParserRuleContext.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts", "ParserRuleContext") 21 | class ParserRuleContext extends RuleContext { 22 | val start: Token = js.native 23 | val stop: Token = js.native 24 | 25 | def parent: ParserRuleContext = js.native 26 | val childCount: Int = js.native 27 | def getChild(i: Int): ParseTree = js.native 28 | } 29 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/RuleContext.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | 18 | @js.native 19 | trait RuleContext extends RuleNode 20 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/RuleNode.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | 18 | @js.native 19 | trait RuleNode extends ParseTree 20 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/TerminalNode.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | @JSImport("antlr4ts/tree/TerminalNode", "TerminalNode") 21 | class TerminalNode extends ParseTree {} 22 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/parsers/antlr/Token.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers.antlr 15 | 16 | import com.nawforce.apexparser.CaseInsensitiveInputStream 17 | 18 | import scala.scalajs.js 19 | import scala.scalajs.js.annotation.JSImport 20 | 21 | @js.native 22 | @JSImport("antlr4ts", "Token") 23 | class Token extends js.Object { 24 | val text: String = js.native 25 | val line: Int = js.native 26 | val charPositionInLine: Int = js.native 27 | val inputStream: CaseInsensitiveInputStream = js.native 28 | val startIndex: Int = js.native 29 | val stopIndex: Int = js.native 30 | } 31 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/platform/Environment.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.runtime.platform 16 | 17 | import com.nawforce.pkgforce.path.PathLike 18 | import io.scalajs.nodejs.process.Process 19 | 20 | import scala.scalajs.js 21 | import scala.scalajs.js.annotation.JSImport 22 | 23 | object Environment { 24 | private val CACHE_DIR: String = ".apexlink_cache" 25 | private var cacheDirOverride: Option[Option[PathLike]] = None 26 | 27 | def gc(): Unit = { 28 | // Not implemented 29 | } 30 | 31 | def homedir: Option[Path] = { 32 | Option(OSExtra.homedir()).filter(_.nonEmpty).map(Path(_)) 33 | } 34 | 35 | def cacheDir: Option[PathLike] = { 36 | if (cacheDirOverride.nonEmpty) 37 | return cacheDirOverride.get 38 | 39 | try { 40 | Process 41 | .env("APEXLINK_CACHE_DIR") 42 | .toOption 43 | .filter(_.nonEmpty) 44 | .map(Path(_)) 45 | .orElse(Environment.homedir.map(_.join(CACHE_DIR))) 46 | } catch { 47 | case _: Throwable => None 48 | } 49 | } 50 | 51 | // Only for test usage 52 | def setCacheDirOverride(value: Option[Option[PathLike]]): Unit = { 53 | cacheDirOverride = value 54 | } 55 | 56 | def isWindows: Boolean = { 57 | // It's win32 even on Win64 58 | Process.platform == "win32" 59 | } 60 | 61 | } 62 | 63 | @js.native 64 | trait OSExtra extends js.Object { 65 | def homedir(): String = js.native 66 | } 67 | 68 | @js.native 69 | @JSImport("os", JSImport.Namespace) 70 | object OSExtra extends OSExtra 71 | -------------------------------------------------------------------------------- /pkgforce/js/src/main/scala/com/nawforce/runtime/xml/XMLDom.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.xml 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation._ 18 | 19 | @js.native 20 | trait NodeList extends js.Object { 21 | val length: Int = js.native 22 | def item(at: Int): Node = js.native 23 | } 24 | 25 | @js.native 26 | trait Node extends js.Object { 27 | val lineNumber: Int = js.native 28 | val columnNumber: Int = js.native 29 | 30 | val nodeType: Int = js.native 31 | val nodeName: String = js.native 32 | 33 | val namespaceURI: String = js.native 34 | val localName: String = js.native 35 | 36 | val childNodes: NodeList = js.native 37 | } 38 | 39 | object Node { 40 | val ELEMENT_NODE = 1 41 | val ATTRIBUTE_NODE = 2 42 | val TEXT_NODE = 3 43 | val CDATA_SECTION_NODE = 4 44 | val ENTITY_REFERENCE_NODE = 5 45 | val ENTITY_NODE = 6 46 | val PROCESSING_INSTRUCTION_NODE = 7 47 | val COMMENT_NODE = 8 48 | val DOCUMENT_NODE = 9 49 | val DOCUMENT_TYPE_NODE = 10 50 | val DOCUMENT_FRAGMENT_NODE = 11 51 | val NOTATION_NODE = 12 52 | } 53 | 54 | @js.native 55 | trait Element extends Node {} 56 | 57 | @js.native 58 | trait CharacterData extends Node { 59 | val data: String = js.native 60 | } 61 | 62 | @js.native 63 | trait Text extends CharacterData {} 64 | 65 | @js.native 66 | trait Document extends js.Object { 67 | val documentElement: Element = js.native 68 | } 69 | 70 | @js.native 71 | @JSImport("@xmldom/xmldom", "DOMParser") 72 | class DOMParser(options: js.Dynamic) extends js.Object { 73 | def parseFromString(xmlSource: String, mimeType: String): Document = js.native 74 | } 75 | -------------------------------------------------------------------------------- /pkgforce/js/src/test/scala/com/nawforce/runtime/imports/FSMonkey.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.imports 15 | 16 | import scala.scalajs.js 17 | import scala.scalajs.js.annotation.JSImport 18 | 19 | @js.native 20 | trait FSMonkey extends js.Object { 21 | def patchRequire(vol: js.Object): Unit = js.native 22 | def patchFs(vol: js.Object): js.Function0[Unit] = js.native 23 | } 24 | 25 | @js.native 26 | @JSImport("fs-monkey", JSImport.Namespace) 27 | object FSMonkey extends FSMonkey 28 | -------------------------------------------------------------------------------- /pkgforce/js/src/test/scala/com/nawforce/runtime/imports/Memfs.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.imports 15 | 16 | import io.scalajs.nodejs.fs.Fs 17 | 18 | import scala.scalajs.js 19 | import scala.scalajs.js.annotation.JSImport 20 | 21 | @js.native 22 | trait Volume extends Fs { 23 | def fromJSON(json: js.Dynamic, cwd: String = ""): Unit = js.native 24 | def toJSON(): js.Object = js.native 25 | def reset(): Unit = js.native 26 | } 27 | 28 | @js.native 29 | trait Memfs extends js.Object { 30 | val vol: Volume = js.native 31 | val fs: js.Object = js.native 32 | } 33 | 34 | @js.native 35 | @JSImport("memfs", JSImport.Namespace) 36 | object Memfs extends Memfs 37 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | antlr4-runtime-4.8-1.jar 4 | apex-parser-3.0.0.jar 5 | geny_2.13-0.6.2.jar 6 | scala-collection-compat_2.13-2.1.4.jar 7 | scala-json-rpc-upickle-json-serializer_2.13-1.0.1.jar 8 | scala-json-rpc_2.13-1.0.1.jar 9 | scala-library-2.13.3.jar 10 | scala-reflect-2.13.3.jar 11 | scala-xml_2.13-1.3.0.jar 12 | ujson_2.13-1.2.0.jar 13 | upack_2.13-1.2.0.jar 14 | upickle-core_2.13-1.2.0.jar 15 | upickle-implicits_2.13-1.2.0.jar 16 | upickle_2.13-1.2.0.jar 17 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/java/com/nawforce/pkgforce/api/Issue.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.api; 16 | 17 | public abstract class Issue { 18 | /* The file path where the issue was found */ 19 | public abstract String filePath(); 20 | 21 | /* The location within the file */ 22 | public abstract IssueLocation fileLocation(); 23 | 24 | /* The category of the issue, one of "Syntax", "Error", "Missing", "Warning" or "Unused" */ 25 | public abstract String category(); 26 | 27 | /* Is this considered an error issue, rather than a warning */ 28 | public abstract Boolean isError(); 29 | 30 | /* The issue message */ 31 | public abstract String message(); 32 | 33 | /* Format as String, filePath is omitted to avoid duplicating over multiple Issues */ 34 | public String asString() { 35 | return category() + ": " + fileLocation().displayPosition() + ": " + message(); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return filePath() + ": " + asString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/java/com/nawforce/pkgforce/api/IssueLocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.api; 15 | 16 | public abstract class IssueLocation { 17 | public abstract int startLineNumber(); 18 | public abstract int startCharOffset(); 19 | public abstract int endLineNumber(); 20 | public abstract int endCharOffset(); 21 | 22 | public String displayPosition() { 23 | if (startLineNumber() == 1 && endLineNumber() == Integer.MAX_VALUE && startCharOffset() == 0 && endCharOffset() == 0) { 24 | return "line 1"; 25 | } 26 | if (startLineNumber() == endLineNumber()) { 27 | if (startCharOffset() == 0 && endCharOffset() == 0) 28 | return "line " + startLineNumber(); 29 | else if (startCharOffset() == endCharOffset()) 30 | return "line " + startLineNumber() + " at " + startCharOffset(); 31 | else 32 | return "line " + startLineNumber() + " at " + startCharOffset() + "-" + endCharOffset(); 33 | } else { 34 | if (startCharOffset() == 0 && endCharOffset() == 0) 35 | return "line " + startLineNumber() + " to " + endLineNumber(); 36 | else 37 | return "line " + startLineNumber() + ":" + startCharOffset() + " to " + endLineNumber() + ":" + endCharOffset(); 38 | } 39 | } 40 | 41 | public boolean contains(int line, int offset) { 42 | return !(line < startLineNumber() || line > endLineNumber() || 43 | (line == startLineNumber() && offset < startCharOffset()) || 44 | (line == endLineNumber() && offset > endCharOffset())); 45 | } 46 | 47 | public boolean contains(IssueLocation other) { 48 | return contains(other.startLineNumber(), other.startCharOffset()) && 49 | contains(other.endLineNumber(), other.endCharOffset()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/java/com/nawforce/runtime/parsers/VFParserVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/kevin/Projects/pkgforce/jvm/src/main/antlr/com/nawforce/parsers/VFParser.g4 by ANTLR 4.8 2 | package com.nawforce.runtime.parsers; 3 | import org.antlr.v4.runtime.tree.ParseTreeVisitor; 4 | 5 | /** 6 | * This interface defines a complete generic visitor for a parse tree produced 7 | * by {@link VFParser}. 8 | * 9 | * @param The return type of the visit operation. Use {@link Void} for 10 | * operations with no return type. 11 | */ 12 | public interface VFParserVisitor extends ParseTreeVisitor { 13 | /** 14 | * Visit a parse tree produced by {@link VFParser#vfUnit}. 15 | * @param ctx the parse tree 16 | * @return the visitor result 17 | */ 18 | T visitVfUnit(VFParser.VfUnitContext ctx); 19 | /** 20 | * Visit a parse tree produced by {@link VFParser#element}. 21 | * @param ctx the parse tree 22 | * @return the visitor result 23 | */ 24 | T visitElement(VFParser.ElementContext ctx); 25 | /** 26 | * Visit a parse tree produced by {@link VFParser#attribute}. 27 | * @param ctx the parse tree 28 | * @return the visitor result 29 | */ 30 | T visitAttribute(VFParser.AttributeContext ctx); 31 | /** 32 | * Visit a parse tree produced by {@link VFParser#attributeName}. 33 | * @param ctx the parse tree 34 | * @return the visitor result 35 | */ 36 | T visitAttributeName(VFParser.AttributeNameContext ctx); 37 | /** 38 | * Visit a parse tree produced by {@link VFParser#attributeValues}. 39 | * @param ctx the parse tree 40 | * @return the visitor result 41 | */ 42 | T visitAttributeValues(VFParser.AttributeValuesContext ctx); 43 | /** 44 | * Visit a parse tree produced by {@link VFParser#content}. 45 | * @param ctx the parse tree 46 | * @return the visitor result 47 | */ 48 | T visitContent(VFParser.ContentContext ctx); 49 | /** 50 | * Visit a parse tree produced by {@link VFParser#chardata}. 51 | * @param ctx the parse tree 52 | * @return the visitor result 53 | */ 54 | T visitChardata(VFParser.ChardataContext ctx); 55 | /** 56 | * Visit a parse tree produced by {@link VFParser#processingInstruction}. 57 | * @param ctx the parse tree 58 | * @return the visitor result 59 | */ 60 | T visitProcessingInstruction(VFParser.ProcessingInstructionContext ctx); 61 | /** 62 | * Visit a parse tree produced by {@link VFParser#scriptChardata}. 63 | * @param ctx the parse tree 64 | * @return the visitor result 65 | */ 66 | T visitScriptChardata(VFParser.ScriptChardataContext ctx); 67 | } -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/scala/com/nawforce/runtime/cmds/Scan.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.runtime.cmds 2 | 3 | import com.nawforce.pkgforce.path.PathFactory 4 | import com.nawforce.pkgforce.workspace.Workspace 5 | 6 | object Scan { 7 | 8 | def main(args: Array[String]): Unit = { 9 | if (args.length == 0) { 10 | println("Missing argument, expecting directory to scan") 11 | System.exit(-1) 12 | } 13 | 14 | if (args.length > 1) { 15 | println("Too many arguments, expecting directory to scan") 16 | System.exit(-1) 17 | } 18 | 19 | //Thread.sleep(30*1000) 20 | 21 | val start = System.currentTimeMillis() 22 | val path = PathFactory(args(0)) 23 | val issuesAndWs = Workspace(path) 24 | issuesAndWs.issues.foreach(issue => println(issue.asString)) 25 | val scanned = System.currentTimeMillis() 26 | println( 27 | issuesAndWs.value 28 | .map(ws => { 29 | val eventCount = ws.events.size 30 | val events = System.currentTimeMillis() 31 | s"Scanned $eventCount events, disk scan took ${scanned - start}ms, event loading took ${events - scanned}ms" 32 | }) 33 | .getOrElse({ 34 | "Workspace failed to load" 35 | }) 36 | ) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/scala/com/nawforce/runtime/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce 15 | 16 | import java.nio.charset.StandardCharsets 17 | 18 | /** Platform specific handling for JVM execution. 19 | * 20 | * Contains a number of abstractions for handling the differences between JVM & Node execution. This is just the JVM 21 | * implementation, the node version of the same abstraction is not in this project. See [[com.nawforce.pkgforce]] for 22 | * the analysis code. 23 | */ 24 | package object runtime { 25 | type SourceBlob = Array[Byte] 26 | 27 | object SourceBlob { 28 | def apply(value: String): SourceBlob = { 29 | value.getBytes(StandardCharsets.UTF_8) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/scala/com/nawforce/runtime/parsers/CollectingErrorListener.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.runtime.parsers 15 | 16 | import com.nawforce.pkgforce.diagnostics.{Diagnostic, Issue, SYNTAX_CATEGORY} 17 | import com.nawforce.pkgforce.path.{Location, PathLike} 18 | import org.antlr.v4.runtime.{BaseErrorListener, RecognitionException, Recognizer} 19 | 20 | import scala.collection.compat.immutable.ArraySeq 21 | import scala.collection.mutable 22 | 23 | class CollectingErrorListener(path: PathLike) extends BaseErrorListener { 24 | var _issues: mutable.ArrayBuffer[Issue] = _ 25 | 26 | override def syntaxError( 27 | recognizer: Recognizer[_, _], 28 | offendingSymbol: Any, 29 | line: Int, 30 | charPositionInLine: Int, 31 | msg: String, 32 | e: RecognitionException 33 | ): Unit = { 34 | if (_issues == null) 35 | _issues = new mutable.ArrayBuffer[Issue]() 36 | 37 | _issues.addOne( 38 | new Issue(path, Diagnostic(SYNTAX_CATEGORY, Location(line, charPositionInLine), msg)) 39 | ) 40 | } 41 | 42 | def issues: ArraySeq[Issue] = { 43 | if (_issues != null) 44 | ArraySeq.unsafeWrapArray(_issues.toArray) 45 | else 46 | Issue.emptyArray 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkgforce/jvm/src/main/scala/com/nawforce/runtime/platform/Environment.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.runtime.platform 16 | 17 | import com.nawforce.pkgforce.path.PathLike 18 | 19 | object Environment { 20 | private val CACHE_DIR: String = ".apexlink_cache" 21 | private var cacheDirOverride: Option[Option[PathLike]] = None 22 | 23 | def gc(): Unit = { 24 | System.gc() 25 | } 26 | 27 | def homedir: Option[PathLike] = { 28 | Option(System.getProperty("user.home")).map(Path(_)) 29 | } 30 | 31 | def cacheDir: Option[PathLike] = { 32 | if (cacheDirOverride.nonEmpty) 33 | return cacheDirOverride.get 34 | 35 | try { 36 | Option(System.getenv("APEXLINK_CACHE_DIR")) 37 | .filter(_.nonEmpty) 38 | .map(Path(_)) 39 | .orElse(Environment.homedir.map(_.join(CACHE_DIR))) 40 | } catch { 41 | case _: Throwable => None 42 | } 43 | } 44 | 45 | // Only for test usage 46 | def setCacheDirOverride(value: Option[Option[PathLike]]): Unit = { 47 | cacheDirOverride = value 48 | } 49 | 50 | def isWindows: Boolean = { 51 | System.getProperty("os.name").contains("Windows") 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /pkgforce/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.5.8 2 | -------------------------------------------------------------------------------- /pkgforce/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.1.1") 2 | addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0") 3 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") 4 | addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2") 5 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/diagnostics/Duplicates.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.pkgforce.diagnostics 2 | 3 | object Duplicates { 4 | 5 | implicit class IterableOps[A](iterable: Iterable[A]) { 6 | 7 | /** Return duplicates keyed against the first discovered. */ 8 | def duplicates[K](f: A => K): Map[A, Iterable[A]] = { 9 | iterable 10 | .groupBy(f) 11 | .collect { case (_, group) if group.size > 1 => group } 12 | .map(group => group.head -> group.tail) 13 | .toMap 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/documents/SourceInfo.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.documents 15 | 16 | import com.nawforce.pkgforce.path.PathLocation 17 | import com.nawforce.runtime.parsers.SourceData 18 | 19 | /** Metadata file information for originating source of something */ 20 | final case class SourceInfo(location: PathLocation, hash: Int) 21 | 22 | object SourceInfo { 23 | def apply(location: PathLocation, data: SourceData): SourceInfo = { 24 | new SourceInfo(location, data.hash) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/memory/Cleanable.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.memory 15 | 16 | import com.nawforce.runtime.platform.Environment 17 | 18 | import scala.collection.mutable 19 | 20 | /** For Caches that can be cleaned/reset as needed to recover memory. */ 21 | trait CleanableCache { 22 | Cleanable.register(this) 23 | 24 | def clean(): Unit 25 | } 26 | 27 | /** Manager of cleanable caches. */ 28 | object Cleanable { 29 | private val cleanable = mutable.Set[IdentityBox[CleanableCache]]() 30 | 31 | def register(cache: CleanableCache): Unit = { 32 | cleanable.add(new IdentityBox(cache)) 33 | } 34 | 35 | def clean(): Unit = { 36 | cleanable.foreach(_.value.clean()) 37 | Environment.gc() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/memory/IdentityBox.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.memory 15 | 16 | /* Value wrapper giving identity equality handling. */ 17 | final class IdentityBox[T <: AnyRef](var value: T) { 18 | 19 | override val hashCode: Int = value.hashCode 20 | 21 | override def equals(that: Any): Boolean = { 22 | that match { 23 | case other: IdentityBox[T] => other.value eq this.value 24 | case _ => false 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/memory/IdentityEquality.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.memory 15 | 16 | /** Implementation of identity equality, useful as mixin to case classes. */ 17 | trait IdentityEquality { 18 | // Identity equals 19 | override def equals(that: Any): Boolean = { 20 | that match { 21 | case other: IdentityEquality => other.eq(this) 22 | case _ => false 23 | } 24 | } 25 | 26 | // Identity hash, may not be unique, storing as val does not appear to improve performance 27 | override def hashCode(): Int = System.identityHashCode(this) 28 | } 29 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/memory/InternCache.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.memory 15 | 16 | import scala.collection.mutable 17 | 18 | /** Cache suitable for interning value. */ 19 | class InternCache[T] extends CleanableCache { 20 | private var cache = mutable.HashMap[T, T]() 21 | 22 | def intern(value: T): T = { 23 | cache.getOrElseUpdate(value, value) 24 | } 25 | 26 | def clean(): Unit = { 27 | cache = new mutable.HashMap[T, T]() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/modifiers/FieldModifiers.scala: -------------------------------------------------------------------------------- 1 | package com.nawforce.pkgforce.modifiers 2 | 3 | import com.nawforce.apexparser.ApexParser.{IdContext, ModifierContext} 4 | import com.nawforce.pkgforce.diagnostics.CodeParserLogger 5 | import com.nawforce.pkgforce.modifiers.ApexModifiers.{ 6 | asModifiers, 7 | deduplicateVisibility, 8 | visibilityModifiers 9 | } 10 | import com.nawforce.runtime.parsers.CodeParser 11 | 12 | import scala.collection.compat.immutable.ArraySeq 13 | 14 | object FieldModifiers { 15 | private val FieldModifiers: Set[Modifier] = 16 | visibilityModifiers.toSet ++ Set( 17 | FINAL_MODIFIER, 18 | STATIC_MODIFIER, 19 | TRANSIENT_MODIFIER, 20 | WEBSERVICE_MODIFIER 21 | ) 22 | 23 | private val FieldAnnotations: Set[Modifier] = 24 | Set( 25 | AURA_ENABLED_ANNOTATION, 26 | DEPRECATED_ANNOTATION, 27 | INVOCABLE_VARIABLE_ANNOTATION, 28 | TEST_VISIBLE_ANNOTATION, 29 | SUPPRESS_WARNINGS_ANNOTATION_PMD, 30 | SUPPRESS_WARNINGS_ANNOTATION_UNUSED 31 | ) 32 | 33 | private val FieldModifiersAndAnnotations: Set[Modifier] = FieldAnnotations ++ FieldModifiers 34 | 35 | private val InnerFieldModifiersAndAnnotations: Set[Modifier] = 36 | FieldModifiersAndAnnotations - STATIC_MODIFIER 37 | 38 | def fieldModifiers( 39 | parser: CodeParser, 40 | modifierContexts: ArraySeq[ModifierContext], 41 | outer: Boolean, 42 | idContext: IdContext 43 | ): ModifierResults = { 44 | 45 | val logger = new CodeParserLogger(parser) 46 | val mods = deduplicateVisibility( 47 | asModifiers( 48 | modifierContexts, 49 | if (outer) FieldModifiersAndAnnotations 50 | else InnerFieldModifiersAndAnnotations, 51 | if (outer) "fields" else "inner class fields", 52 | logger, 53 | idContext 54 | ), 55 | "fields", 56 | logger, 57 | idContext 58 | ) 59 | 60 | val results = { 61 | if (mods.intersect(visibilityModifiers).isEmpty && mods.contains(WEBSERVICE_MODIFIER)) { 62 | GLOBAL_MODIFIER +: mods 63 | } else if ( 64 | !mods.intersect(visibilityModifiers).contains(GLOBAL_MODIFIER) && mods.contains( 65 | WEBSERVICE_MODIFIER 66 | ) 67 | ) { 68 | logger.logError(idContext, s"webservice fields must be global") 69 | GLOBAL_MODIFIER +: mods.diff(visibilityModifiers) 70 | } else if (mods.intersect(visibilityModifiers).isEmpty) { 71 | PRIVATE_MODIFIER +: mods 72 | } else { 73 | mods 74 | } 75 | } 76 | ModifierResults(results, logger.issues).intern 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/modifiers/ModifierResults.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.modifiers 16 | 17 | import com.nawforce.pkgforce.diagnostics.Issue 18 | import com.nawforce.pkgforce.memory.InternCache 19 | 20 | import scala.collection.compat.immutable.ArraySeq 21 | 22 | /** Results from modifier analysis. 23 | * 24 | * Modifiers are examined before the CST is constructed to make things a bit simpler. The results of the analysis 25 | * are returned via this type. Interning is supported to reduce memory use. 26 | */ 27 | final case class ModifierResults(modifiers: ArraySeq[Modifier], issues: ArraySeq[Issue]) { 28 | 29 | override val hashCode: Int = modifiers.hashCode() 30 | 31 | def intern: ModifierResults = ModifierResults.intern(this) 32 | 33 | override def equals(that: Any): Boolean = { 34 | that match { 35 | case other: ModifierResults => 36 | other.canEqual(this) && doesEqual(other) 37 | case _ => false 38 | } 39 | } 40 | 41 | override def canEqual(that: Any): Boolean = that.isInstanceOf[ModifierResults] 42 | 43 | private def doesEqual(other: ModifierResults): Boolean = { 44 | this.modifiers == other.modifiers && this.issues == other.issues 45 | } 46 | 47 | def methodOwnerNature: MethodOwnerNature = { 48 | if (modifiers.contains(ABSTRACT_MODIFIER)) ABSTRACT_METHOD_NATURE 49 | else if (modifiers.contains(VIRTUAL_MODIFIER)) VIRTUAL_METHOD_NATURE 50 | else FINAL_METHOD_NATURE 51 | } 52 | 53 | } 54 | 55 | object ModifierResults extends InternCache[ModifierResults] { 56 | val empty: ModifierResults = ModifierResults(ArraySeq.empty, ArraySeq.empty) 57 | } 58 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/names/DotName.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.names 15 | 16 | /** 17 | * A qualified name with notional 'dot' separators 18 | */ 19 | final case class DotName(names: Seq[Name]) { 20 | 21 | val isCompound: Boolean = names.size > 1 22 | 23 | def head: DotName = DotName(Seq(names.head)) 24 | def tail: DotName = DotName(names.tail) 25 | def headNames: DotName = DotName(names.reverse.tail.reverse) 26 | def tailNames: DotName = DotName(names.tail) 27 | def firstName: Name = names.head 28 | def lastName: Name = names.last 29 | 30 | def append(name: Name): DotName = DotName(names :+ name) 31 | def prepend(name: Name): DotName = DotName(name +: names) 32 | def prepend(name: Option[Name]): DotName = { 33 | name match { 34 | case Some(value) => DotName(value +: names) 35 | case _ => this 36 | } 37 | } 38 | 39 | def asTypeName(): TypeName = { 40 | TypeName(names.reverse) 41 | } 42 | 43 | override def toString: String = names.mkString(".") 44 | } 45 | 46 | object DotName { 47 | def apply(name: String): DotName = { 48 | DotName(name.split('.').toSeq.map(p => Name(p))) 49 | } 50 | def apply(name: Name): DotName = { 51 | DotName(Seq(name)) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/names/Name.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.names 15 | 16 | import upickle.default.{macroRW, ReadWriter => RW} 17 | 18 | /** Case insensitive string for symbol names. 19 | * 20 | * The value of the Name is stored as is but equality and hashing are performed against a normalised lower case 21 | * value. 22 | */ 23 | @upickle.implicits.key("Name") 24 | final case class Name(value: String) { 25 | 26 | override val hashCode: Int = value.toLowerCase.hashCode 27 | 28 | def canEqual(that: Any): Boolean = that.isInstanceOf[Name] 29 | 30 | override def equals(that: Any): Boolean = { 31 | that match { 32 | case otherName: Name => 33 | otherName.canEqual(this) && otherName.value.equalsIgnoreCase(value) 34 | case _ => false 35 | } 36 | } 37 | 38 | override def toString: String = value 39 | } 40 | 41 | object Name { 42 | implicit val rw: RW[Name] = macroRW 43 | 44 | val empty: Name = new Name("") 45 | } 46 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/parsers/UTF8Decode.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.parsers 15 | 16 | /* Utilities for helping find character positions in UTF-8 byte arrays. Character positions can be ambiguous as they 17 | * have commonly be used to refer to UTF-16 positions rather than Unicode code points. This code assumes the latter 18 | * model to match ANTLR CharStream handling of positions. 19 | */ 20 | object UTF8Decode { 21 | 22 | def isASCII(buffer: Array[Byte], offset: Int, length: Int): Boolean = { 23 | var at = offset 24 | val limit = offset + length 25 | while (at < limit) { 26 | if ((0xff & buffer(at).asInstanceOf[Int]) >= 0x80) 27 | return false 28 | at += 1 29 | } 30 | true 31 | } 32 | 33 | def getCharOffsetFrom(buffer: Array[Byte], offset: Int, charCount: Int): Int = { 34 | var remaining = charCount 35 | var at = offset 36 | while (remaining > 0) { 37 | at += sequenceLength(buffer(at)) 38 | remaining -= 1 39 | } 40 | at 41 | } 42 | 43 | private def sequenceLength(leadingByte: Byte): Int = { 44 | val unsigned: Int = 0xff & leadingByte.asInstanceOf[Int] 45 | if (unsigned < 0x80) 1 46 | else if ((unsigned >> 5) == 0x6) 2 47 | else if ((unsigned >> 4) == 0xe) 3 48 | else if ((unsigned >> 3) == 0x1e) 4 49 | else 50 | throw new IllegalArgumentException(s"Expecting UTF-8 data, found leading byte: $leadingByte") 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/path/PathFactory.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.path 15 | 16 | import com.nawforce.runtime.platform.Path 17 | 18 | object PathFactory { 19 | def apply(path: String): PathLike = Path(path) 20 | def unapply(path: Path): Option[String] = Some(path.toString) 21 | } 22 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/sfdx/ModuleDependent.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.sfdx 15 | 16 | import com.nawforce.pkgforce.path.Location 17 | import ujson.Value 18 | 19 | case class ModuleDependent(config: ValueWithPositions, value: Value.Value) { 20 | val location: Location = config 21 | .lineAndOffsetOf(value) 22 | .map(lineAndOffset => Location(lineAndOffset._1, lineAndOffset._2)) 23 | .getOrElse(Location.empty) 24 | val name: String = value.stringValue(config, "package") 25 | val version: Option[VersionNumber] = value.optVersionNumber(config, "versionNumber") 26 | } 27 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/sfdx/PackageDependent.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.sfdx 15 | 16 | import com.nawforce.pkgforce.names.Name 17 | import com.nawforce.pkgforce.path.{Location, PathLike} 18 | import ujson.Value 19 | 20 | case class PackageDependent(projectPath: PathLike, config: ValueWithPositions, value: Value.Value) { 21 | 22 | val location: Location = 23 | config 24 | .lineAndOffsetOf(value) 25 | .map(lineAndOffset => Location(lineAndOffset._1, lineAndOffset._2)) 26 | .getOrElse(Location.empty) 27 | 28 | val namespace: Option[Name] = 29 | value.optIdentifier(config, "namespace") match { 30 | case Some(ns) if ns.value.isEmpty => 31 | config 32 | .lineAndOffsetOf(value("namespace")) 33 | .map(lineAndOffset => { 34 | throw SFDXProjectError(lineAndOffset, "'namespace' can not be empty") 35 | }) 36 | case Some(ns) => Some(ns) 37 | case None => None 38 | } 39 | 40 | val relativePath: Option[String] = value.optStringValue(config, "path") 41 | 42 | } 43 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/sfdx/VersionNumber.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.sfdx 15 | 16 | sealed trait BuildNumber 17 | case object NextBuild extends BuildNumber 18 | case object LatestBuild extends BuildNumber 19 | case class Build(build: Int) extends BuildNumber 20 | 21 | case class VersionNumber(major: Int, minor: Int, patch: Int, build: BuildNumber) { 22 | def isCompatible(other: VersionNumber): Boolean = { 23 | if (major != other.major || minor != other.minor || patch != other.patch) 24 | return false 25 | 26 | (build, other.build) match { 27 | case (Build(x), Build(y)) => x == y 28 | case (LatestBuild, _) => true 29 | case _ => false 30 | } 31 | } 32 | 33 | override def toString: String = { 34 | s"$major.$minor.$patch." + (build match { 35 | case Build(n) => s"$n" 36 | case NextBuild => "NEXT" 37 | case LatestBuild => "LATEST" 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/sfdx/WorkspaceConfig.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.sfdx 15 | 16 | import com.nawforce.pkgforce.diagnostics.IssueLogger 17 | import com.nawforce.pkgforce.names.Name 18 | import com.nawforce.pkgforce.path.PathLike 19 | import com.nawforce.pkgforce.workspace.{ModuleLayer, NamespaceLayer} 20 | 21 | trait WorkspaceConfig { 22 | def layers(logger: IssueLogger): Seq[NamespaceLayer] 23 | } 24 | 25 | class MDAPIWorkspaceConfig(namespace: Option[Name], paths: Seq[PathLike]) extends WorkspaceConfig { 26 | 27 | override def layers(logger: IssueLogger): Seq[NamespaceLayer] = 28 | Seq( 29 | NamespaceLayer( 30 | namespace, 31 | isGulped = false, 32 | paths.map(path => ModuleLayer(path, ".", Seq())).toList 33 | ) 34 | ) 35 | 36 | override def toString: String = 37 | s"MDAPIWorkspace(namespace=$namespace, paths=${paths.map(_.toString).mkString(", ")})" 38 | } 39 | 40 | class SFDXWorkspaceConfig(val rootPath: PathLike, project: SFDXProject) extends WorkspaceConfig { 41 | 42 | override def layers(logger: IssueLogger): Seq[NamespaceLayer] = project.layers(logger) 43 | 44 | override def toString: String = s"SFDXWorkspace(${project.projectPath})" 45 | } 46 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/stream/ApexGenerator.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.stream 16 | 17 | import com.nawforce.pkgforce.documents._ 18 | import com.nawforce.pkgforce.path.PathLike 19 | 20 | final case class ApexEvent(path: PathLike) extends PackageEvent 21 | 22 | /** Convert Apex documents into PackageEvents */ 23 | object ApexGenerator { 24 | 25 | def iterator(index: DocumentIndex): Iterator[PackageEvent] = 26 | index.get(ApexNature).flatMap(toEvents) 27 | 28 | private def toEvents(document: MetadataDocument): Iterator[PackageEvent] = { 29 | Iterator(ApexEvent(document.path)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/stream/FlowGenerator.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.stream 16 | 17 | import com.nawforce.pkgforce.documents._ 18 | import com.nawforce.pkgforce.path.{Location, PathLocation} 19 | 20 | final case class FlowEvent(sourceInfo: SourceInfo) extends PackageEvent 21 | 22 | object FlowGenerator { 23 | def iterator(index: DocumentIndex): Iterator[PackageEvent] = 24 | index.get(FlowNature).flatMap(toEvents) 25 | 26 | private def toEvents(document: MetadataDocument): Iterator[PackageEvent] = { 27 | val source = document.source 28 | source.value 29 | .map(source => { 30 | Iterator(FlowEvent(SourceInfo(PathLocation(document.path, Location.all), source))) 31 | }) 32 | .getOrElse(Iterator.empty) ++ IssuesEvent.iterator(source.issues) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/stream/PackageStream.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.stream 15 | 16 | import com.nawforce.pkgforce.diagnostics.Issue 17 | import com.nawforce.pkgforce.documents._ 18 | 19 | import scala.collection.compat.immutable.ArraySeq 20 | 21 | trait PackageEvent 22 | 23 | final case class IssuesEvent(issues: ArraySeq[Issue]) extends PackageEvent 24 | 25 | object IssuesEvent { 26 | def apply(issues: Issue*): IssuesEvent = { 27 | new IssuesEvent(issues.to(ArraySeq)) 28 | } 29 | 30 | def iterator(issues: ArraySeq[Issue]): Iterator[IssuesEvent] = { 31 | if (issues.nonEmpty) 32 | Iterator(new IssuesEvent(issues.to(ArraySeq))) 33 | else 34 | Iterator.empty 35 | } 36 | } 37 | 38 | class PackageStream(val events: ArraySeq[PackageEvent]) { 39 | def issues: ArraySeq[IssuesEvent] = events.collect { case e: IssuesEvent => e } 40 | 41 | def labelsFiles: ArraySeq[LabelFileEvent] = events.collect { case e: LabelFileEvent => e } 42 | 43 | def labels: ArraySeq[LabelEvent] = events.collect { case e: LabelEvent => e } 44 | 45 | def pages: ArraySeq[PageEvent] = events.collect { case e: PageEvent => e } 46 | 47 | def flows: ArraySeq[FlowEvent] = events.collect { case e: FlowEvent => e } 48 | 49 | def components: ArraySeq[ComponentEvent] = events.collect { case e: ComponentEvent => e } 50 | } 51 | 52 | object PackageStream { 53 | def apply(index: DocumentIndex): PackageStream = { 54 | new PackageStream(ArraySeq.unsafeWrapArray(eventStream(index).toArray)) 55 | } 56 | 57 | def eventStream(index: DocumentIndex): Iterator[PackageEvent] = { 58 | LabelGenerator.iterator(index) ++ 59 | ComponentGenerator.iterator(index) ++ 60 | PageGenerator.iterator(index) ++ 61 | FlowGenerator.iterator(index) ++ 62 | SObjectGenerator.iterator(index) ++ 63 | ApexGenerator.iterator(index) ++ 64 | TriggerGenerator.iterator(index) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/stream/PageGenerator.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.stream 16 | 17 | import com.nawforce.pkgforce.diagnostics.CatchingLogger 18 | import com.nawforce.pkgforce.documents._ 19 | import com.nawforce.pkgforce.names.Name 20 | import com.nawforce.pkgforce.path.{LocationAnd, PathLocation} 21 | import com.nawforce.runtime.parsers.PageParser 22 | 23 | import scala.collection.compat.immutable.ArraySeq 24 | 25 | final case class PageEvent( 26 | sourceInfo: SourceInfo, 27 | _controllers: ArraySeq[LocationAnd[Name]], 28 | _expressions: ArraySeq[LocationAnd[String]] 29 | ) extends VFEvent(_controllers, _expressions) 30 | 31 | /** Convert page documents into PackageEvents */ 32 | object PageGenerator { 33 | 34 | def iterator(index: DocumentIndex): Iterator[PackageEvent] = 35 | index.get(PageNature).flatMap(toEvents) 36 | 37 | private def toEvents(document: MetadataDocument): Iterator[PackageEvent] = { 38 | val source = document.source 39 | source.value 40 | .map(source => { 41 | val parser: PageParser = PageParser(document.path, source) 42 | val result = parser.parsePage() 43 | if (result.issues.nonEmpty) { 44 | IssuesEvent.iterator(result.issues) 45 | } else { 46 | val location = parser.getPathLocation(result.value) 47 | val logger = new CatchingLogger 48 | Iterator( 49 | PageEvent( 50 | SourceInfo(PathLocation(location.path, location.location), source), 51 | VFEvent.extractControllers(parser.source, result.value, isPage = true), 52 | VFEvent.extractExpressions(parser.source, result.value) 53 | ) 54 | ) ++ 55 | IssuesEvent.iterator(logger.issues) 56 | } 57 | }) 58 | .getOrElse(Iterator.empty) ++ IssuesEvent.iterator(source.issues) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/stream/TriggerGenerator.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.stream 16 | 17 | import com.nawforce.pkgforce.documents._ 18 | import com.nawforce.pkgforce.path.PathLike 19 | 20 | final case class TriggerEvent(path: PathLike) extends PackageEvent 21 | 22 | /** Convert trigger documents into PackageEvents */ 23 | object TriggerGenerator { 24 | 25 | def iterator(index: DocumentIndex): Iterator[PackageEvent] = 26 | index.get(TriggerNature).flatMap(toEvents) 27 | 28 | private def toEvents(document: MetadataDocument): Iterator[PackageEvent] = { 29 | Iterator(TriggerEvent(document.path)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkgforce/shared/src/main/scala/com/nawforce/pkgforce/xml/XMLFactory.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.xml 15 | 16 | import com.nawforce.pkgforce.diagnostics.{Diagnostic, ERROR_CATEGORY, Issue, IssuesAnd} 17 | import com.nawforce.pkgforce.path.{Location, PathLike} 18 | import com.nawforce.runtime.xml.XMLDocument 19 | 20 | import scala.collection.immutable.ArraySeq 21 | 22 | object XMLFactory { 23 | def parse(path: PathLike): IssuesAnd[Option[XMLDocument]] = { 24 | path.readSourceData() match { 25 | case Left(err) => 26 | IssuesAnd(ArraySeq(Issue(path, Diagnostic(ERROR_CATEGORY, Location(0), err))), None) 27 | case Right(data) => XMLDocument(path, data) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkgforce/shared/src/test/scala/com/nawforce/pkgforce/diagnostics/LoggerTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | 15 | package com.nawforce.pkgforce.diagnostics 16 | 17 | import org.scalatest.BeforeAndAfter 18 | import org.scalatest.funsuite.AnyFunSuite 19 | 20 | class LoggerTest extends AnyFunSuite with BeforeAndAfter { 21 | test("exception logger to string") { 22 | val ex = new Exception("Hello") 23 | assert(LoggerOps.exceptionMessage(ex).startsWith("java.lang.Exception: Hello")) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pkgforce/shared/src/test/scala/com/nawforce/pkgforce/parsers/SourceDataTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kevin Jones, All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | */ 14 | package com.nawforce.pkgforce.parsers 15 | 16 | import com.nawforce.runtime.parsers.SourceData 17 | import org.scalatest.funsuite.AnyFunSuite 18 | 19 | class SourceDataTest extends AnyFunSuite { 20 | 21 | test("Basic string handling") { 22 | val sd = SourceData("A basic test string") 23 | assert(sd.subdata(2, 2).asString.isEmpty) 24 | assert(sd.subdata(2, 3).asString == "b") 25 | assert(sd.subdata(2, 7).asString == "basic") 26 | } 27 | 28 | test("UTF-8 String handling") { 29 | // Single char, two byte UTF-8, 1 Unicode code point 30 | val sd = SourceData("A UTF-8 \u00E9 test string") 31 | assert(sd.subdata(8, 9).asString == "\u00E9") 32 | assert(sd.subdata(10, 11).asString == "t") 33 | assert(sd.subdata(10, 14).asString == "test") 34 | assert(sd.subdata(6, 14).asString == "8 \u00E9 test") 35 | } 36 | 37 | test("UTF-8 String handling (surrogate pair)") { 38 | // Two UTF-16 chars, four byte UTF-8, should be handled as 1 Unicode code point for ANTLR CharSource compat 39 | val sd = SourceData("A UTF-8 \uD83E\uDD26 test string") 40 | assert(sd.subdata(8, 9).asString == "\uD83E\uDD26") 41 | assert(sd.subdata(10, 11).asString == "t") 42 | assert(sd.subdata(10, 14).asString == "test") 43 | assert(sd.subdata(6, 14).asString == "8 \uD83E\uDD26 test") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 5 | 4.0.0 6 | 7 | com.github.nawforce 8 | apexlink-parent 9 | 2.3.7 10 | pom 11 | 12 | apexlink parent 13 | 14 | 15 | pkgforce 16 | apexlink 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /samples/Cumulus/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "Cumulus/force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "npsp", 9 | "sourceApiVersion": "48.0", 10 | "plugins": { 11 | "dependencies": [ 12 | {"namespace": "npe01"}, 13 | {"namespace": "npo02"}, 14 | {"namespace": "npe03"}, 15 | {"namespace": "npe4"}, 16 | {"namespace": "npe5"} 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/FindNearby/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "FindNearBy/src", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "FN", 9 | "sourceApiVersion": "48.0" 10 | } 11 | -------------------------------------------------------------------------------- /samples/HyperBatch/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "HyperBatch/src", 5 | "default": true 6 | } 7 | ], 8 | "sourceApiVersion": "48.0" 9 | } -------------------------------------------------------------------------------- /samples/Interactions-for-Student-Recruitment/extra/README.md: -------------------------------------------------------------------------------- 1 | The code is making direct reference to DmlWrapper, likely its within a the hed namespace but I have borrowed 2 | this copt from Cumulus so the sameple can still be used for testing. -------------------------------------------------------------------------------- /samples/Interactions-for-Student-Recruitment/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "extra", 5 | "default": false 6 | }, 7 | { 8 | "path": "Interactions-for-Student-Recruitment/src", 9 | "default": true 10 | } 11 | ], 12 | "sourceApiVersion": "48.0", 13 | "plugins": { 14 | "dependencies": [ 15 | {"namespace": "hed"} 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /samples/NPSP/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "NPSP/force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "npsp", 9 | "sourceApiVersion": "48.0", 10 | "plugins": { 11 | "dependencies": [ 12 | {"namespace": "npe01"}, 13 | {"namespace": "npo02"}, 14 | {"namespace": "npe03"}, 15 | {"namespace": "npe4"}, 16 | {"namespace": "npe5"} 17 | ] 18 | } 19 | } -------------------------------------------------------------------------------- /samples/at4dx/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "fflib-apex-mocks/sfdx-source/apex-mocks", 5 | "default": false 6 | }, 7 | { 8 | "path": "fflib-apex-common/sfdx-source/apex-common", 9 | "default": false 10 | }, 11 | { 12 | "path": "force-di/force-di", 13 | "default": false 14 | }, 15 | { 16 | "path": "at4dx/sfdx-source/core", 17 | "default": true 18 | } 19 | ], 20 | "namespace": "", 21 | "sfdcLoginUrl": "https://login.salesforce.com", 22 | "sourceApiVersion": "51.0" 23 | } 24 | -------------------------------------------------------------------------------- /samples/fflib-apex-common-samplecode/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "fflib-apex-mocks/sfdx-source/apex-mocks", 5 | "default": false 6 | }, 7 | { 8 | "path": "fflib-apex-common/sfdx-source/apex-common", 9 | "default": false 10 | }, 11 | { 12 | "path": "fflib-apex-common-samplecode/sfdx-source/apex-common-samplecode", 13 | "default": true 14 | } 15 | ], 16 | "namespace": "", 17 | "sfdcLoginUrl": "https://login.salesforce.com", 18 | "sourceApiVersion": "51.0" 19 | } 20 | -------------------------------------------------------------------------------- /samples/purealoe-lwc/.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | # Standard metadata 6 | purealoe-lwc/package.xml 7 | purealoe-lwc/**appMenu 8 | purealoe-lwc/**appSwitcher 9 | purealoe-lwc/**objectTranslations 10 | purealoe-lwc/**profiles 11 | purealoe-lwc/**settings 12 | 13 | # LWC configuration files 14 | purealoe-lwc/**/jsconfig.json 15 | purealoe-lwc/**/.eslintrc.json 16 | 17 | # LWC Jest 18 | purealoe-lwc/**/__tests__/** 19 | 20 | purealoe-lwc/force-app/main/default/objects/Einstein_Settings__c.object 21 | 22 | -------------------------------------------------------------------------------- /samples/purealoe-lwc/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "purealoe-lwc/force-app", 5 | "default": true, 6 | "package": "PureAloeLWC", 7 | "versionNumber": "4.0.0.NEXT", 8 | "versionName": "Spring '20" 9 | } 10 | ], 11 | "namespace": "", 12 | "sfdcLoginUrl": "https://login.salesforce.com", 13 | "sourceApiVersion": "48.0", 14 | "packageAliases": { 15 | "PureAloeLWC": "0HoB0000000Gmi9KAC", 16 | "PureAloeLWC@4.0.0-17": "04tB0000000Azj5IAC" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used for Git repositories to specify intentionally untracked files that Git should ignore. 2 | # If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore 3 | # For useful gitignore templates see: https://github.com/github/gitignore 4 | 5 | # Salesforce cache 6 | .sfdx/ 7 | .localdevserver/ 8 | 9 | # LWC VSCode autocomplete 10 | **/lwc/jsconfig.json 11 | 12 | # LWC Jest coverage reports 13 | coverage/ 14 | 15 | # Logs 16 | logs 17 | *.log 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Dependency directories 23 | node_modules/ 24 | 25 | # Eslint cache 26 | .eslintcache 27 | 28 | # MacOS system files 29 | .DS_Store 30 | 31 | # Windows system files 32 | Thumbs.db 33 | ehthumbs.db 34 | [Dd]esktop.ini 35 | $RECYCLE.BIN/ 36 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/NoDeps.cls: -------------------------------------------------------------------------------- 1 | public class NoDeps { 2 | public void func() {} 3 | } -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/NoDeps.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/SingleDep.cls: -------------------------------------------------------------------------------- 1 | public class SingleDep { 2 | static void func() { 3 | NoDeps n = new NoDeps(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/SingleDep.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/TestDep.cls: -------------------------------------------------------------------------------- 1 | @isTest 2 | public class TestDep { 3 | @isTest 4 | static void test_func() { 5 | SingleDep s = new SingleDep(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/TestDep.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/TransDep.cls: -------------------------------------------------------------------------------- 1 | public class TransDep { 2 | public void func() { 3 | SingleDep s = new SingleDep(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/force-app/main/default/classes/TransDep.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/dependency-counts/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "", 9 | "sfdcLoginUrl": "https://login.salesforce.com", 10 | "sourceApiVersion": "48.0" 11 | } -------------------------------------------------------------------------------- /samples/synthetic/mdapi-test/Hello.cls: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | public final static String Hello = 'Hello' + World.message; 3 | } 4 | -------------------------------------------------------------------------------- /samples/synthetic/mdapi-test/Hello.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/mdapi-test/World.cls: -------------------------------------------------------------------------------- 1 | public class World { 2 | public final static String message = 'World'; 3 | } 4 | -------------------------------------------------------------------------------- /samples/synthetic/mdapi-test/World.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used for Git repositories to specify intentionally untracked files that Git should ignore. 2 | # If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore 3 | # For useful gitignore templates see: https://github.com/github/gitignore 4 | 5 | # Salesforce cache 6 | .sfdx/ 7 | .localdevserver/ 8 | 9 | # LWC VSCode autocomplete 10 | **/lwc/jsconfig.json 11 | 12 | # LWC Jest coverage reports 13 | coverage/ 14 | 15 | # Logs 16 | logs 17 | *.log 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Dependency directories 23 | node_modules/ 24 | 25 | # Eslint cache 26 | .eslintcache 27 | 28 | # MacOS system files 29 | .DS_Store 30 | 31 | # Windows system files 32 | Thumbs.db 33 | ehthumbs.db 34 | [Dd]esktop.ini 35 | $RECYCLE.BIN/ 36 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/force-app/main/default/classes/DoubleError.cls: -------------------------------------------------------------------------------- 1 | public class DoubleError { 2 | 3 | public void func1() {debug} 4 | 5 | public void func2() {debug} 6 | 7 | } 8 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/force-app/main/default/classes/DoubleError.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/force-app/main/default/classes/Hello.cls: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/force-app/main/default/classes/Hello.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/force-app/main/default/classes/SingleError.cls: -------------------------------------------------------------------------------- 1 | public class SingleError { 2 | public void func() { 3 | } 4 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/force-app/main/default/classes/SingleError.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-ns-test/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "sfdx_test", 9 | "sfdcLoginUrl": "https://login.salesforce.com", 10 | "sourceApiVersion": "48.0" 11 | } 12 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-test/.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /samples/synthetic/sfdx-test/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used for Git repositories to specify intentionally untracked files that Git should ignore. 2 | # If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore 3 | # For useful gitignore templates see: https://github.com/github/gitignore 4 | 5 | # Salesforce cache 6 | .sfdx/ 7 | .localdevserver/ 8 | 9 | # LWC VSCode autocomplete 10 | **/lwc/jsconfig.json 11 | 12 | # LWC Jest coverage reports 13 | coverage/ 14 | 15 | # Logs 16 | logs 17 | *.log 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Dependency directories 23 | node_modules/ 24 | 25 | # Eslint cache 26 | .eslintcache 27 | 28 | # MacOS system files 29 | .DS_Store 30 | 31 | # Windows system files 32 | Thumbs.db 33 | ehthumbs.db 34 | [Dd]esktop.ini 35 | $RECYCLE.BIN/ 36 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-test/force-app/main/default/classes/Hello.cls: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | 3 | } -------------------------------------------------------------------------------- /samples/synthetic/sfdx-test/force-app/main/default/classes/Hello.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/sfdx-test/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "", 9 | "sfdcLoginUrl": "https://login.salesforce.com", 10 | "sourceApiVersion": "48.0" 11 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /samples/synthetic/test-classes/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used for Git repositories to specify intentionally untracked files that Git should ignore. 2 | # If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore 3 | # For useful gitignore templates see: https://github.com/github/gitignore 4 | 5 | # Salesforce cache 6 | .sfdx/ 7 | .localdevserver/ 8 | 9 | # LWC VSCode autocomplete 10 | **/lwc/jsconfig.json 11 | 12 | # LWC Jest coverage reports 13 | coverage/ 14 | 15 | # Logs 16 | logs 17 | *.log 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Dependency directories 23 | node_modules/ 24 | 25 | # Eslint cache 26 | .eslintcache 27 | 28 | # MacOS system files 29 | .DS_Store 30 | 31 | # Windows system files 32 | Thumbs.db 33 | ehthumbs.db 34 | [Dd]esktop.ini 35 | $RECYCLE.BIN/ 36 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/API.cls: -------------------------------------------------------------------------------- 1 | public interface API { 2 | void func(); 3 | } 4 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/APIFactory.cls: -------------------------------------------------------------------------------- 1 | public class APIFactory { 2 | static API getInstance() { 3 | (API)type.forName('name'); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/APIImpl.cls: -------------------------------------------------------------------------------- 1 | public class APIImpl implements API { 2 | void func() {} 3 | } 4 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/APITest.cls: -------------------------------------------------------------------------------- 1 | @IsTest 2 | public class APITest { 3 | public testFunc() { 4 | API sut = APIFactory.getInstance(); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/Base.cls: -------------------------------------------------------------------------------- 1 | abstract public class Base implements API { 2 | abstract void func(); 3 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/BaseTest.cls: -------------------------------------------------------------------------------- 1 | @IsTest 2 | public class BaseTest { 3 | 4 | class TestImpl extends Base { 5 | public void func() {} 6 | } 7 | 8 | void testFunc() { 9 | TestImpl sut = new TestImpl(); 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/Derived.cls: -------------------------------------------------------------------------------- 1 | public class Derived extends Base { 2 | void func () {} 3 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/DerivedTest.cls: -------------------------------------------------------------------------------- 1 | @isTest 2 | public class DerivedTest { 3 | public void testFunc() { 4 | Derived sut = new Derived(); 5 | } 6 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/Hello.cls: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | public void func() {} 3 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/Hello.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/HelloTest.cls: -------------------------------------------------------------------------------- 1 | @IsTest 2 | public class HelloTest { 3 | 4 | static void testFunc() { 5 | Hello hello = new Hello(); 6 | hello.func(); 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/HelloTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/InnerServiceImpl.cls: -------------------------------------------------------------------------------- 1 | public class InnerServiceImpl{ 2 | public class InnerImpl implements Service.API { 3 | void func() {} 4 | 5 | void foo() { 6 | Hello h = new Hello(); 7 | } 8 | } 9 | 10 | public void bar() { 11 | NoTest n = new NoTest(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/NoTest.cls: -------------------------------------------------------------------------------- 1 | public class NoTest { 2 | public void func() {} 3 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/NoTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 48.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/Service.cls: -------------------------------------------------------------------------------- 1 | public class Service { 2 | public interface API { 3 | void func(); 4 | } 5 | 6 | static API getInstance() { 7 | (API)type.forName('name'); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/ServiceAPITest.cls: -------------------------------------------------------------------------------- 1 | @IsTest 2 | public class ServiceAPITest { 3 | void testFunc() { 4 | Service.API sut = Service.getInstance(); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/ServiceImpl.cls: -------------------------------------------------------------------------------- 1 | public class ServiceImpl implements Service.API { 2 | void func() {} 3 | 4 | void foo() { 5 | Hello h = new Hello(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /samples/synthetic/test-classes/force-app/main/default/classes/ServiceTest.cls: -------------------------------------------------------------------------------- 1 | @IsTest 2 | public class ServiceTest{ 3 | public void testFunc() { 4 | Service sut = new Service(); 5 | } 6 | } -------------------------------------------------------------------------------- /samples/synthetic/test-classes/sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "", 9 | "sfdcLoginUrl": "https://login.salesforce.com", 10 | "sourceApiVersion": "48.0" 11 | } --------------------------------------------------------------------------------