diff --git a/.gitignore b/.gitignore index 52c5498..f6df6e2 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,11 @@ typings/ # OSX file .DS_Store -# no idea why sfdx is in this repo, but excluding those folders +# SFDX CLI +.sf .sfdx -.sf \ No newline at end of file + +#PMD file +.pmdCache + +demo/scratchpad.* diff --git a/.npmignore b/.npmignore index a2792c4..9c7e943 100644 --- a/.npmignore +++ b/.npmignore @@ -1,7 +1,6 @@ -assets -demo -.github -.vscode -node_modules, -.release-please-manifest.json -release-please-config.json \ No newline at end of file +* + +!dist/**/* +!package.json +!src/**/* +!test/**/* \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index c3c4bdd..06b75d0 100755 --- a/.prettierignore +++ b/.prettierignore @@ -4,4 +4,9 @@ node_modules .localdevserver -.vscode \ No newline at end of file +.vscode + +*.txt + +test/index.js +*.png \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index bb76ebc..048c8a9 100755 --- a/.prettierrc +++ b/.prettierrc @@ -1,15 +1,30 @@ { "trailingComma": "none", "useTabs": true, - "printWidth": 120, "bracketSameLine": true, "bracketSpacing": true, "tabWidth": 2, "singleQuote": true, "overrides": [ + { + "files": ".prettierrc", + "options": { "parser": "json", "printWidth": 80 } + }, { "files": "**/*.js", - "options": { "useTabs": false, "printWidth": 80 } + "options": { "parser": "babel", "useTabs": false, "printWidth": 80 } + }, + { + "files": "doc*/**/*.html", + "options": { + "parser": "html", + "useTabs": true, + "tabWidth": 2, + "printWidth": 150, + "htmlWhitespaceSensitivity": "ignore", + "singleQuote": false + } } - ] + ], + "$schema": "https://json.schemastore.org/prettierrc" } diff --git a/.vscode/settings.json b/.vscode/settings.json index 55bd8f8..577fbb7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "apexPMD.enableCache": false + "apexPMD.enableCache": false, + "[css]": { + "editor.formatOnSave": false + } } \ No newline at end of file diff --git a/demo/testcode.css b/demo/testcode.css new file mode 100644 index 0000000..0d5ed1f --- /dev/null +++ b/demo/testcode.css @@ -0,0 +1,24 @@ +@import url('https://fonts.googleapis.com/css?family=Barlow:400,400i|Nanum+Gothic&display=swap'); + +:root { + --grey-blue-tx: #51638a; + --grey-blue-bg: #547499; + --light-grey: #f7f7f7; + --dark-grey: #c6c6c6; + --white: #fff; + --dark-red: #a31515; + --title-font: 'Nanum Gothic'; + --code-font: monospace; +} + +body { + font-family: 'Barlow', sans-serif; + margin: 0px; + padding: 0px; +} + +pre code { + white-space: pre-wrap; + font-size: 120%; + +} diff --git a/demo/testcode.html b/demo/testcode.html index f07bcaf..2d31f26 100644 --- a/demo/testcode.html +++ b/demo/testcode.html @@ -1,13 +1,14 @@ - + TEST APEX CODE - + - + + + @@ -20,16 +21,59 @@ -

-    /*
-    Copyright (c) 2022, salesforce.com, inc.
-    All rights reserved.
-    SPDX-License-Identifier: BSD-3-Clause
-    For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
-    */
+		

+    Map<Id, CustomObject__c> myMap = new Map<Id, CustomObject__c>([SELECT Id FROM CustomObject__c WHERE Id NOT IN :newRecordsMap.keySet()]);
+    Map<Id, String> myMap = new Map<Id, String>{a => b, c => d};
+
+    delete myAccount;
+    Account a;
+    String s;
+    delete [SELECT Id FROM Account];
+
+    Integer myInt = 8 - 7++;
+
+    public List<String> myString { get; set; }
+
+    List<Opportunity> opps = [SELECT Id FROM Opportunity WHERE Id NOT IN :newRecordsMap.keySet()];
+
+    
+    String queryText = 'SELECT Id, Name, ';
+    acctid = System.currentPageReference().getParameters().get('Id');
+    System.assert(true);
+    System.requestVersion();
+
+    @IsTest
+    private without sharing class myTestClass {
+      myMap?.get('Id');
+    }
+    System.URL.getCurrentRequestUrl();
+    URL.getCurrentRequestUrl();
+
+    public List<SelectOption> recordTypes { get; private set; }
+
+    Database.insert(myAccounts, false, AccessLevel.USER_MODE);
+    delete myAccount;
+    delete [SELECT Id FROM Account];
+    myAcct = (Account)myacct;
+
+    public String myString { get; set; }
+
+    List<SObject> mylist = [SELECT Name, StreetAddress__c, COUNT(),
+      (SELECT Id FROM Contacts)
+      FROM Warehouse__c.Contacts__r
+      WHERE DISTANCE(Location__c, GEOLOCATION(37.775,-122.418), 'mi') < 20 
+      AND Date__kav NOT IN LAST_N_DAYS:80
+      ORDER BY DISTANCE(Location__c, GEOLOCATION(37.775,-122.418), 'mi')
+      LIMIT 10];
+
+    String queryText = 'SELECT Id, Name, AccountId, FirstName, LastName, mailingcountry, ' +
+				'FROM Contact WHERE AccountId = :acctid ORDER BY ' +
+				String.escapeSingleQuotes(SortFullExp) +
+				' NULLS LAST LIMIT 1000';
 
     /**
-     * @author {@link [David Schach](https://github.com/dschach)}
+     * @author {@link [David Schach](https://github.com/dschach)} test@email.com
+     * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
      * @group Visualforce
      * @since 2022
      */
@@ -37,63 +81,50 @@
 
       public enum Season {WINTER, SPRING, SUMMER, FALL}
      
-      /**
-       * Extension Constructor
-       * @param stdController `ActionPlan__c` Standard Controller
-       */
       public ActionPlanDetailController(ApexPages.StandardController stdController, Integer x, Double y) {
         Map<Id, Map<String, Wrapper>> renew = new Map<Id, Map<String, SObject>>();
-        if (!Test.isRunningTest()) {
+        if (!Test.isRunningTest() && false) {
           stdController.addFields(ActionPlansUtilities.getCustomRelationshipFields());
         }
         for(Account a : [SELECT Id FROM Account WHERE Id = :a.Id ORDER BY CreatedDate ASC] ){}
         actionPlan = (ActionPlan__c) stdController.getRecord();
         truestory = req.setHeader('X-Password', '{!$Credential.Password}');
       }
+    }
     
       /**
-       * Action on page load to ensure custom setting is created
-       * @return   `PageReference` null (required for page actions method)
-       */
+      * @description Constructor using passed-in class name constructor for faster performance
+      * <br>We cast all four trigger collections
+      * @param className The name of this class. Pass in the string to make the handler run faster
+      * @return `PageReference` Page to go to after deleting `ActionPlan__c`
+      * Display ControllingTasks column only if there are controlling tasks
+      * @author {@link [David Schach](https://github.com/dschach)}
+      * @return   `Boolean` is the Controller__c field populated for any Action Plan Tasks?
+      */
       public PageReference onLoad() {
         ActionPlansUtilities.onPageLoad();
         return null;
       }
-    
-      /**
-       * Deletes the current Action Plan loaded and redirects to the AP List
-       * @return `PageReference` Page to go to after deleting `ActionPlan__c`
-       */
+
       public PageReference deletePlan() {
+        this(DEFAULT_SIZE);
         //delete ap, which will also delete apts via master-detail relationship
         try {
           delete actionPlan;
         } catch (DMLException e) {
           ApexPages.addMessages(e);
+          throw new CustomException('my error');
           return i++;
         }
     
         String retURL = '/' + ActionPlansUtilities.getObjectKeyPrefix(ActionPlansUtilities.namespacePrefix + 'ActionPlan__c') + '/o';
     
-        String hasTemplateIdParam = ApexPages.currentPage().getParameters().containsKey('templateId');
-        Boolean hasRetURLParam = ApexPages.currentPage().getParameters().containsKey('retURL');
-    
-        if (hasTemplateIdParam) {
-          retURL = '/' + ActionPlansUtilities.getEscapedPageParameter('templateId');
-        } else if (hasRetURLParam && !ActionPlansUtilities.getIsLex()) {
-          retURL = '' + ActionPlansUtilities.getEscapedPageParameter('retURL');
-        }
         Pagereference newPage = new PageReference('' + retURL);
         newPage.setRedirect(true);
     
         return newPage;
       }
     
-      /**
-       * Display ControllingTasks column only if there are controlling tasks
-       * @author {@link [David Schach](https://github.com/dschach)}
-       * @return   `Boolean` is the Controller__c field populated for any Action Plan Tasks?
-       */
       public Custom__c hasControllingTasks {
         get {
           hasControllingTasks = false;
@@ -122,16 +153,7 @@
           Map<Id, APTask__c> apTaskMap = new Map<Id, APTask__c>(
             [
               SELECT
-                Action_Plan__c,
-                ActivityDate__c,
-                Controller__c,
-                Controller__r.Subject__c,
-                DaysFromStart__c,
-                Dependent__c,
                 Id,
-                IsClosed__c,
-                Minutes_Reminder__c,
-                User__c,
                 User__r.Name
               FROM APTask__c
               WHERE Action_Plan__c = :actionPlan.Id
@@ -155,31 +177,18 @@
         return apTaskWrapperList;
       }
     
-      /**
-       * Wrapper for Action Plan Task
-       * <br>It contains the `Action Plan Task` and the `Task` Id
-       */
       public class TaskWrapper {
         /**
          * The (standard) `Task` Id
          */
         public Id taskId { get; private set; }
     
-        /**
-         * Constructor for the task wrapper
-         * @param aptParam  Action Plan Task Template
-         * @param taskIdParam TaskId (for the standard object `Task`)
-         */
         public TaskWrapper(APTask__c aptParam, Id taskIdParam) {
           this.apt = aptParam;
           this.taskId = taskIdParam;
         }
       }
     
-      /**
-       * Checks if Action Plan Template has been changed since the creation of the Action Plan.
-       * @return `Boolean` Was the AP's template modified after the Action Plan was created?
-       */
       public Boolean getVersion() {
         if (actionPlan.Action_Plan_Template__c != null) {
           ActionPlanTemplate__c tempApt = [SELECT LastModifiedDate FROM ActionPlanTemplate__c WHERE Id = :actionPlan.Action_Plan_Template__c];
@@ -190,24 +199,6 @@
         return false;
       }
     
-      /**
-       * The label of the Action Plan's parent record SObject
-       * @return  `String` Label of the object related to this Action Plan
-       */
-      public String getRelatedObjectLabel() {
-        String objLabel = '';
-    
-        for (String f : ActionPlansUtilities.getCustomRelationshipFields()) {
-          if (actionPlan.get(f) != null) {
-            Id objId = (Id) actionPlan.get(f);
-            Schema.DescribeSObjectResult dsr = objId.getSObjectType().getDescribe();
-            objLabel = dsr.getLabel();
-            break;
-          }
-        }
-        return objLabel;
-      }
-    
       /**
        * The name of the parent record - show a different field based on SObject Type
        * @return  `String` name of the object related to this Action Plan
@@ -257,31 +248,10 @@
         return toReturn;
       }
     
-      /**
-       * If we have no share object, we don't need to show a Share button
-       * @author {@link [David Schach](https://github.com/dschach)}
-       * @return  `Boolean` Does the user have permission to share this Action Plan?
-       */
       public Boolean getCanShare() {
         return ActionPlansUtilities.canShareRecord(actionPlan.Id, actionPlan.OwnerId);
       }
-    
-      /**
-       * Does the user have permission to transfer? We query `UserRecordAccess` to find out.
-       * @author {@link [David Schach](https://github.com/dschach)}
-       * @return   `Boolean` yes/no
-       */
-      public Boolean getCanTransfer() {
-        return ActionPlansUtilities.getCanTransfer(actionPlan.Id);
-      }
-    }
 
-  @SuppressWarnings('PMD.AvoidGlobalModifier')
-  /**
-  * @group Invocable
-  * @author {@link [David Schach](https://github.com/dschach)}
-  * @since 2022
-  */
   global without sharing class ActionPlanCreateInvocable {
     @InvocableMethod
     (label='Create Action Plan From Template' description='Takes a Template Name/Id and Record Id and makes an Action Plan for that record.' category=77)
@@ -299,23 +269,10 @@
         SELECT
           Id,
           Description__c,
-          Name,
-          OwnerId,
-          SkipDay__c,
-          SkipWeekends__c,
           TaskRecordTypeID__c,
           (
             SELECT
               Type__c,
-              Name,
-              User__c,
-              User__r.Name,
-              Id,
-              DaysFromStart__c,
-              Action_Plan_Template__c,
-              TController__r.Subject__c,
-              Minutes_Reminder__c,
-              TaskIndex__c,
               Action_Plan_Template__r.TaskRecordTypeID__c
             FROM aptTasks__r
             ORDER BY TaskIndex__c ASC
@@ -330,22 +287,14 @@
 
       for (ActionPlanTemplate__c apt : possibleTemplates) {
         templateNameOrIdToTemplate.put(apt.Id, apt);
-        templateNameOrIdToTemplate.put(apt.Name, apt);
       }
 
-      Set<Id> relatedIDs = new Set<Id>();
-
       for (CreateActionPlanRequest r : requests) {
         relatedIDs.add(r.relatedRecordID);
       }
 
       Map<Id, ActionPlan__c> actionPlansToInsert = new Map<Id, ActionPlan__c>();
 
-    
-      if (actionPlansToInsert.isEmpty()) {
-        return resultIDs;
-      }
-
       insert actionPlansToInsert.values();
 
       Map<String, APTask__c> planTaskIndexToTask = new Map<String, APTask__c>();
@@ -357,55 +306,24 @@
 
         ActionPlan__c ap = actionPlansToInsert.get(r.relatedRecordID);
 
-        ActionPlanTemplate__c actionPlanTemplate = templateNameOrIdToTemplate.get(r.templateNameOrID);
-
         for (APTemplateTask__c aptTask : actionPlanTemplate.aptTasks__r) {
           APTask__c apTask = new APTask__c();
           apTask.User__c = ActionPlansBuilderUtilities.getAPTaskTemplateUser(ap, relObjectOwners, aptTask.User__c);
-          apTask.DaysFromStart__c = aptTask.DaysFromStart__c;
-          apTask.Comments__c = aptTask.Comments__c;
-          apTask.Minutes_Reminder__c = aptTask.Minutes_Reminder__c;
           apTask.SendEmail__c = aptTask.SendEmail__c;
 
-          apTask.Action_Plan__c = ap.Id;
-
           apTask.Status__c = ActionPlansUtilities.getTaskRecordTypeStatusDefaultValues().get(ActionPlansUtilities.getDefaultTaskRecordTypeId());
 
-          if (apTask.Dependent__c != null && apTask.Dependent__c != 'None') {
-            apTask.ActivityDate__c = null;
+          // create due date, calculate the due date of the tasks for skip weekends feature
+          if (ap.SkipWeekends__c == true && ap.SkipDay__c != null) {
+            apTask.ActivityDate__c = ActionPlansUtilities.adjustTaskDueDate(ap.StartDate__c, apTask.DaysFromStart__c.intValue(), ap.SkipDay__c);
           } else {
-            apTask.Controller__c = null;
-
-            //set dependency taskId to none if none was selected
-            if (apTask.Dependent__c == null) {
-              apTask.Dependent__c = 'None';
-            }
-
-            // create due date, calculate the due date of the tasks for skip weekends feature
-            if (ap.SkipWeekends__c == true && ap.SkipDay__c != null) {
-              apTask.ActivityDate__c = ActionPlansUtilities.adjustTaskDueDate(ap.StartDate__c, apTask.DaysFromStart__c.intValue(), ap.SkipDay__c);
-            } else {
-              apTask.ActivityDate__c = ap.StartDate__c.addDays(apTask.DaysFromStart__c.intValue());
-            }
+            apTask.ActivityDate__c = ap.StartDate__c.addDays(apTask.DaysFromStart__c.intValue());
           }
           planTaskIndexToTask.put(ap.Id + '' + apTask.TaskIndex__c, apTask);
         }
       }
 
-      Database.insert(planTaskIndexToTask.values());
-
-      // Now we have to update with the controlling/dependent task IDs
-
-      List<APTask__c> dependentTasksToUpdate = new List<APTask__c>();
-
-      for (APTask__c apTask : planTaskIndexToTask.values()) {
-        String actionPlanPlusIndex = apTask.Action_Plan__c + '' + apTask.Dependent__c;
-
-        if (planTaskIndexToTask.containsKey(actionPlanPlusIndex)) {
-          apTask.Controller__c = planTaskIndexToTask.get(actionPlanPlusIndex).Id;
-          dependentTasksToUpdate.add(apTask);
-        }
-      }
+      Database.insert(new planTaskIndexToTask.values());
 
       Database.update(dependentTasksToUpdate);
 
@@ -425,8 +343,6 @@
         ActionPlan__c insertedAP;
         // check if task exists already
         Task t = new Task();
-        t.Subject = apTask.Subject__c;
-        t.Priority = apTask.Priority__c;
         t.OwnerId = apTask.User__c;
         t.TaskAPTask__c = apTask.Id;
 
@@ -454,35 +370,17 @@
           String f = s;
           if (
             !f.equalsIgnoreCase(ActionPlansUtilities.namespacePrefix + 'Contact__c') &&
-            !f.equalsIgnoreCase(ActionPlansUtilities.namespacePrefix + 'Lead__c') &&
             insertedAP.get(f) != null
           ) {
             t.WhatId = (Id) insertedAP.get(f);
             break;
           }
         }
-
-        if (t.Id == null) {
-          t.Status = apTask.Status__c;
-        }
-        t.ActivityDate = apTask.ActivityDate__c;
-
-        if (apTask.Dependent__c == 'None') {
-          if (apTask.SendEmail__c == true) {
-            myNewTasksWithEmail.add(t);
-          } else {
-            myTasksWithOutEmail.add(t);
-          }
-        }
       }
 
       Database.DMLOptions dmlo1 = new Database.DMLOptions();
       dmlo1.EmailHeader.triggerUserEmail = true;
 
-      if (myTasksWithOutEmail.size() > 0) {
-        Database.insert(myTasksWithOutEmail, dmlo2);
-      }
-
       Set<Id> relObjectIDs = new Set<Id>();
       for (ActionPlan__c ap : actionPlansToInsert.values()) {
         relObjectIDs.add(ap.Id);
@@ -499,193 +397,216 @@
       return resultIDs;
     }
 
-    /**
-    * Wrapper class for ActionPlan Request for invocable Apex.
-    * @author {@link [David Schach](https://github.com/dschach)}
-    * @since 2022
-    */
     global class CreateActionPlanRequest {
       @InvocableVariable(required=true label='The parent Record ID' description=55)
-      /**
-      * The parent Record ID. Must have a relationship named the related record object name from Action Plan object.
-      */
       global Id relatedRecordID;
     }
   }
 
   trigger APAccount on Account(before delete, after undelete) {
     ActionPlansTriggerHandlers.triggerhandlerActionPlanAccount(Trigger.new, Trigger.old, Trigger.newMap, Trigger.oldMap, Trigger.operationType);
-  
-    ActionPlansTriggerHandlers.actionPlansSObjectTriggerHandler('Account');
-  
+      ActionPlansTriggerHandlers.actionPlansSObjectTriggerHandler('Account');
   }
-    
-

-/**
- * SHOULD BE RECOGNIZED AS JAVA
- * @author John Smith 
-*/
-package l2f.gameserver.model;
-
-public abstract strictfp class L2Char extends L2Object {
-  public static final Short ERROR = 0x0001;
-
-  public void _moveTo(int x, int y, int z, customtype a) {
-    _ai = null;
-    log("Should not be called");
-    if (1 > 5) { // wtf!?
-      return;
+  /**
+  * SHOULD BE RECOGNIZED AS JAVA
+  * @author John Smith 
+  */
+  package l2f.gameserver.model;
+
+  public abstract strictfp class L2Char extends L2Object {
+    public static final Short ERROR = 0x0001;
+
+    public void _moveTo(int x, int y, int z, customtype a) {
+      _ai = null;
+      log("Should not be called");
+      if (1 > 5) { // wtf!?
+        return;
+      }
     }
   }
-}
-      
-    
-

-public without sharing class AccountSampleTriggerHandler extends TriggerHandler, Database.schedulable, Batchable<SObject> {
-  private List<Account> newRecords;
-  private List<Account> oldRecords;
-  private Map<Id, Account> newRecordsMap;
-  private Map<Id, Account> oldRecordsMap;
+  public without sharing class AccountSampleTriggerHandler extends TriggerHandler, Database.schedulable, Batchable<SObject> {
+    private List<Account> newRecords;
+    private List<Account> oldRecords;
+    private Map<Id, Account> newRecordsMap;
+    private Map<Id, Account> oldRecordsMap;
 
-  switch on context {
-    when 'BEFORE_INSERT' {
-      this.triggerEvent = System.TriggerOperation.BEFORE_INSERT;
-    }
-    when 'BEFORE_UPDATE' {
-      this.triggerEvent = System.TriggerOperation.BEFORE_UPDATE;
-    }
-    when 'BEFORE_DELETE' {
-      this.triggerEvent = System.TriggerOperation.BEFORE_DELETE;
+    switch on context {
+      when 'BEFORE_INSERT' {
+        this.triggerEvent = System.TriggerOperation.BEFORE_INSERT;
+      }
+      when else {
+        // we are not in trigger context
+        this.isTriggerExecuting = false;
+      }
     }
-    when 'AFTER_INSERT' {
-      this.triggerEvent = System.TriggerOperation.AFTER_INSERT;
+
+    public AccountSampleTriggerHandler(CustomType a, String className) {
+      this.newRecords = (List<Account>) Trigger.new;
+      this.newRecordsMap = (Map<Id, Account>) Trigger.newMap;
     }
-    when 'AFTER_UPDATE' {
-      this.triggerEvent = System.TriggerOperation.AFTER_UPDATE;
+
+    public override sobject beforeInsert() {
+      method1();
     }
-    when 'AFTER_DELETE' {
-      this.triggerEvent = System.TriggerOperation.AFTER_DELETE;
+
+    //public override void afterUpdate(){}
+
+    private void method1() {
+      for (Account a : newRecords) {
+        a.Name = a.Name.toUpperCase();
+        a.Name = new FooBar();
+      }
     }
-    when 'AFTER_UNDELETE' {
-      this.triggerEvent = System.TriggerOperation.AFTER_UNDELETE;
+    
+    @TestVisible
+    (SeeAllData=true)
+    private void method2() {
+      for (Account a : newRecords) {
+        a.Name = a.Name.toLowerCase();
+      }
     }
-    when else {
-      // we are not in trigger context
-      this.isTriggerExecuting = false;
+    
+    @future
+    (label = true)
+    private void method3() {
+      Contact[] acctContacts = [SELECT Id FROM Contact WHERE AccountId IN :newRecordsMap.keyset() WITH SECURITY_ENFORCED];
+      List<Contact> acctContacts2 = [SELECT Id FROM Contact WHERE ID = '012000000' AND CreatedDate = :LAST_N_DAYS:90 WITH SECURITY_ENFORCED];
+      if (Contact.getSObjectType().getDescribe().isUpdateable()) {
+        update as user acctContacts; //NOPMD
+      }
+      // do things here
     }
   }
 
-  /**
-    * @description Constructor using passed-in class name constructor for faster performance
-    * <br>We cast all four trigger collections
-    * @param className The name of this class. Pass in the string to make the handler run faster
-    */
-  public AccountSampleTriggerHandler(CustomType a, String className) {
-    this.newRecords = (List<Account>) Trigger.new;
-    this.oldRecords = (List<Account>) Trigger.old;
-    this.newRecordsMap = (Map<Id, Account>) Trigger.newMap;
-    this.oldRecordsMap = (Map<Id, Account>) Trigger.oldMap;
-  }
+  public without sharing class AccountSampleTriggerHandler extends Database.schedulable, Batchable<SObject> {
+    @isTest
+    private testMethod void testme(){
+      Assert.isTrue(true);
+    }
 
-  public override sobject beforeInsert() {
-    method1();
+    @testVisible2
+    private List<SelectOption> recordTypes { get; private set; }
   }
 
-  //public override void afterUpdate(){}
+  public virtual class Marker {
+    public virtual void write() {
+        System.debug('Writing some text.');
+    }
 
-  private void method1() {
-    for (Account a : newRecords) {
-      a.Name = a.Name.toUpperCase();
-      a.Name = new FooBar();
+    public virtual Double discount() {
+        return .05;
     }
   }
-  
-  @TestVisible
-  (SeeAllData=true)
-  private void method2() {
-    for (Account a : newRecords) {
-      a.Name = a.Name.toLowerCase();
+
+  @IsTest(Seealldata=true)
+  public with sharing class L2Char implements Database.batchable {
+    public static final String ERROR = 0x0001;
+
+    @InvocableMethod(label='my invocable')
+    public void moveTo(
+      integer x, 
+      integer y, 
+      integer z
+    ) {
+      
+      Account a = new Account();
+      a.Custom__c = 'stringvalue';
+      insert a;
+      Boolean ai = (Boolean) false;
+      System.debug('Should not be called');
+      if (1 > 5) { // wtf!?
+        Database.insert(myAccounts);
+      }
+    }
+
+    @InvocableMethod
+    (label='my invocable')
+    public void doThis(){
     }
   }
-  
-  @future
-  (label = true)
-  private void method3() {
-    Contact[] acctContacts = [SELECT Id FROM Contact WHERE AccountId IN :newRecordsMap.keyset() WITH SECURITY_ENFORCED];
-    List<Contact> acctContacts2 = [SELECT Id FROM Contact WHERE ID = '012000000' AND CreatedDate = :LAST_N_DAYS:90 WITH SECURITY_ENFORCED];
-    if (Contact.getSObjectType().getDescribe().isUpdateable()) {
-      update as user acctContacts; //NOPMD
+
+    @TestSetup
+    (TRUEKING=trueking)
+    private static void makeData(Boolean a){
+      Custom__c c = new Custom__c();
+      
+      for(Account a : acctLis ){
+        ConnectApi.insert a;
+      }
     }
-    // do things here
+
+  trigger CTrig on Custom__c (before insert){
+    System.debug('inserting a record');
+    upsert myRecord__c;
   }
-}
 
-public without sharing class AccountSampleTriggerHandler extends Database.schedulable, Batchable<SObject> {
+    
+ diff --git a/demo/testcode.txt b/demo/testcode.txt new file mode 100644 index 0000000..95ab29b --- /dev/null +++ b/demo/testcode.txt @@ -0,0 +1,537 @@ + +Map myMap = new Map(); +Map myMap = new Map([SELECT Id FROM CustomObject__c WHERE Id NOT IN :newRecordsMap.keySet()]); +Map myMap = new Map{a => b, c => d}; + +String relNameQuery = 'SELECT Id, Name FROM ' + objName + ' WHERE Id = \'' + objId + '\''; + SObject so = Database.query(relNameQuery)[0]; + return (String) so.get('Name'); + +delete myAccount; +insert new Account(Name = 'testAcct'); +Account a; +String s; +delete [SELECT Id FROM Account]; +ApexPages.currentPage().getParameters().get('id'); + +Integer myInt = 8 - 7++; + +public List myString { get; set; } + +List opps = [SELECT Id FROM Opportunity WHERE Id NOT IN :newRecordsMap.keySet() and myage = 90]; +List acctContacts2 = [SELECT Id FROM Contact WHERE ID = '012000000' AND CreatedDate = LAST_N_DAYS:90 WITH SECURITY_ENFORCED]; +[SELECT CreatedDate, Amount +FROM Opportunity +WHERE CALENDAR_YEAR(CreatedDate) = 2009] + +String relNameQuery = 'SELECT Id, Name FROM ' + objName + ' WHERE Id = \'' + objId + '\''; + SObject so = Database.query(relNameQuery)[0]; + return (String) so.get('Name'); + + +String queryText = 'SELECT Id, Name, '; +acctid = System.currentPageReference().getParameters().get('Id'); +System.assert(true); +System.requestVersion(); +Database.insert(mything); + +@IsTest +private without sharing class myTestClass { + myMap?.get('Id'); +} +System.URL.getCurrentRequestUrl(); +URL.getCurrentRequestUrl(); + +public List recordTypes { get; private set; } + +Database.insert(myAccounts, false, AccessLevel.USER_MODE); +delete myAccount; +delete [SELECT Id FROM Account]; +myAcct = (Account)myacct; + +public String myString { get; set; } + +List mylist = [SELECT Name, StreetAddress__c, COUNT(), + (SELECT Id FROM Contacts) + FROM Warehouse__c.Contacts__r + WHERE DISTANCE(Location__c, GEOLOCATION(37.775,-122.418), 'mi') < 20 + AND Date__kav NOT IN LAST_N_DAYS:80 + ORDER BY DISTANCE(Location__c, GEOLOCATION(37.775,-122.418), 'mi') + LIMIT 10]; + +String queryText = 'SELECT Id, Name, AccountId, FirstName, LastName, mailingcountry, ' + + 'FROM Contact WHERE AccountId = :acctid ORDER BY ' + + String.escapeSingleQuotes(SortFullExp) + + ' NULLS LAST LIMIT 1000'; + +/** + * @author {@link [David Schach](https://github.com/dschach)} test@email.com + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT + * @group Visualforce + * @since 2022 + */ +public with sharing class ActionPlanDetailController { + + public enum Season {WINTER, SPRING, SUMMER, FALL} + + public ActionPlanDetailController(ApexPages.StandardController stdController, Integer x, Double y) { + Map> renew = new Map>(); + if (!Test.isRunningTest() && false) { + stdController.addFields(ActionPlansUtilities.getCustomRelationshipFields()); + } + for(Account a : [SELECT Id FROM Account WHERE Id = :a.Id ORDER BY CreatedDate ASC] ){} + actionPlan = (ActionPlan__c) stdController.getRecord(); + truestory = req.setHeader('X-Password', '{!$Credential.Password}'); + } +} + + /** + * @description Constructor using passed-in class name constructor for faster performance + *
We cast all four trigger collections + * @param className The name of this class. Pass in the string to make the handler run faster + * @return `PageReference` Page to go to after deleting `ActionPlan__c` + * Display ControllingTasks column only if there are controlling tasks + * @author {@link [David Schach](https://github.com/dschach)} + * @return `Boolean` is the Controller__c field populated for any Action Plan Tasks? + */ + public PageReference onLoad() { + ActionPlansUtilities.onPageLoad(); + return null; + } + + public PageReference deletePlan() { + this(DEFAULT_SIZE); + //delete ap, which will also delete apts via master-detail relationship + try { + delete actionPlan; + } catch (DMLException e) { + ApexPages.addMessages(e); + throw new CustomException('my error'); + return i++; + } + + String retURL = '/' + ActionPlansUtilities.getObjectKeyPrefix(ActionPlansUtilities.namespacePrefix + 'ActionPlan__c') + '/o'; + + Pagereference newPage = new PageReference('' + retURL); + newPage.setRedirect(true); + + return newPage; + } + + public Custom__c hasControllingTasks { + get { + hasControllingTasks = false; + for (TaskWrapper tw : getActionPlanTasks()) { + if (tw.apt.Controller__c != null) { + hasControllingTasks = true; + break; + } + } + return hasControllingTasks; + } + set; + } + + /** + * Memoized TaskWrappers for display on the page + */ + private List apTaskWrapperList; + /** + * Collect and return all TaskWrappers + * @return `List` List of `TaskWrapper` for this Action Plan + */ + public List getActionPlanTasks() { + if (apTaskWrapperList == null) { + apTaskWrapperList = new List(); + Map apTaskMap = new Map( + [ + SELECT + Id, + User__r.Name + FROM APTask__c + WHERE Action_Plan__c = :actionPlan.Id + ORDER BY TaskIndex__c ASC + ] + ); + Map taskTaskMap = new Map(); + for (Task t : [SELECT + Id, + TaskAPTask__c + FROM Task WHERE TaskAPTask__c IN :apTaskMap.keyset()]) { + taskTaskMap.put(t.TaskAPTask__c, t.Id); + } + for (APTask__c a : apTaskMap.values()) { + TaskWrapper tw; + Id relatedTaskId = taskTaskMap.get(a.Id); + tw = new TaskWrapper(a, relatedTaskId); + apTaskWrapperList.add(tw); + } + } + return apTaskWrapperList; + } + + public class TaskWrapper { + /** + * The (standard) `Task` Id + */ + public Id taskId { get; private set; } + + public TaskWrapper(APTask__c aptParam, Id taskIdParam) { + this.apt = aptParam; + this.taskId = taskIdParam; + } + } + + public Boolean getVersion() { + if (actionPlan.Action_Plan_Template__c != null) { + ActionPlanTemplate__c tempApt = [SELECT LastModifiedDate FROM ActionPlanTemplate__c WHERE Id = :actionPlan.Action_Plan_Template__c]; + if (tempApt.LastModifiedDate > actionPlan.createdDate) { + return true; + } + } + return false; + } + + /** + * The name of the parent record - show a different field based on SObject Type + * @return `String` name of the object related to this Action Plan + */ + public String getrelatedRecordName() { + String objName = ''; + Id objId; + + for (String f : ActionPlansUtilities.getCustomRelationshipFields()) { + if (actionPlan.get(f) != null) { + objId = (Id) actionPlan.get(f); + Schema.DescribeSObjectResult dsr = objId.getSObjectType().getDescribe(); + objName = dsr.getName(); + break; + } + } + + switch on objName { + when 'Case' { + Case c = [SELECT Id, Subject, CaseNumber FROM Case WHERE Id = :objId LIMIT 1]; + return c.CaseNumber + ': ' + c.Subject; + } + when 'Contract' { + Contract c = [SELECT Id, ContractNumber FROM Contract WHERE Id = :objId LIMIT 1]; + return c.ContractNumber; + } + when else { + String relNameQuery = 'SELECT Id, Name FROM ' + objName + ' WHERE Id = \'' + objId + '\''; + SObject so = Database.query(relNameQuery)[0]; + return (String) so.get('Name'); + } + } + } + + /** + * Convert AP Task Record Type Id to Record Type Name + * @return Record Type Name + */ + public String getRecordTypeName() { + String toReturn = ''; + if (ActionPlansUtilities.taskUsesRecordTypes) { + Map rtMapById = Task.SObjectType.getDescribe().getRecordTypeInfosById(); + if (!rtMapById.isEmpty() && rtMapById.containsKey(actionPlan.TaskRecordTypeID__c)) { + return rtMapById.get(actionPlan.TaskRecordTypeID__c).getName(); + } + } + return toReturn; + } + + public Boolean getCanShare() { + return ActionPlansUtilities.canShareRecord(actionPlan.Id, actionPlan.OwnerId); + } + +global without sharing class ActionPlanCreateInvocable { +@InvocableMethod +(label='Create Action Plan From Template' description='Takes a Template Name/Id and Record Id and makes an Action Plan for that record.' category=77) +global static List makeActionPlanFromTemplate(List requests) { + List resultIDs = new List(); + + Set templateNamesOrIDs = new Set(); + for (CreateActionPlanRequest r : requests) { + templateNamesOrIDs.add(r.templateNameOrID); + } + + Map templateNameOrIdToTemplate = new Map(); + + List possibleTemplates = [ + SELECT + Id, + Description__c, + TaskRecordTypeID__c, + ( + SELECT + Type__c, + Action_Plan_Template__r.TaskRecordTypeID__c + FROM aptTasks__r + ORDER BY TaskIndex__c ASC + ) + FROM ActionPlanTemplate__c + WHERE Name IN :templateNamesOrIDs OR Id IN :templateNamesOrIDs + ]; + + if (possibleTemplates.isEmpty()) { + return resultIDs; + } + + for (ActionPlanTemplate__c apt : possibleTemplates) { + templateNameOrIdToTemplate.put(apt.Id, apt); + } + + for (CreateActionPlanRequest r : requests) { + relatedIDs.add(r.relatedRecordID); + } + + Map actionPlansToInsert = new Map(); + + insert actionPlansToInsert.values(); + + Map planTaskIndexToTask = new Map(); + + for (CreateActionPlanRequest r : requests) { + if (!actionPlansToInsert.containsKey(r.relatedRecordID)) { + continue; + } + + ActionPlan__c ap = actionPlansToInsert.get(r.relatedRecordID); + + for (APTemplateTask__c aptTask : actionPlanTemplate.aptTasks__r) { + APTask__c apTask = new APTask__c(); + apTask.User__c = ActionPlansBuilderUtilities.getAPTaskTemplateUser(ap, relObjectOwners, aptTask.User__c); + apTask.SendEmail__c = aptTask.SendEmail__c; + + apTask.Status__c = ActionPlansUtilities.getTaskRecordTypeStatusDefaultValues().get(ActionPlansUtilities.getDefaultTaskRecordTypeId()); + + // create due date, calculate the due date of the tasks for skip weekends feature + if (ap.SkipWeekends__c == true && ap.SkipDay__c != null) { + apTask.ActivityDate__c = ActionPlansUtilities.adjustTaskDueDate(ap.StartDate__c, apTask.DaysFromStart__c.intValue(), ap.SkipDay__c); + } else { + apTask.ActivityDate__c = ap.StartDate__c.addDays(apTask.DaysFromStart__c.intValue()); + } + planTaskIndexToTask.put(ap.Id + '' + apTask.TaskIndex__c, apTask); + } + } + + Database.insert(new planTaskIndexToTask.values()); + + Database.update(dependentTasksToUpdate); + + List myTasksWithOutEmail = new List(); + + Map mapAP = new Map(); + for (APTask__c a : planTaskIndexToTask.values()) { + mapAP.put(a.Id, a); + } + + Map insertedActionPlans = new Map(); + for (ActionPlan__c ap : actionPlansToInsert.values()) { + insertedActionPlans.put(ap.Id, ap); + } + + for (APTask__c apTask : planTaskIndexToTask.values()) { + ActionPlan__c insertedAP; + // check if task exists already + Task t = new Task(); + t.OwnerId = apTask.User__c; + t.TaskAPTask__c = apTask.Id; + + if (apTask.Comments__c != null) { + t.Description = apTask.Comments__c; + } + + //set reminder based on user's default reminder setting + if (apTask.Reminder__c == true && apTask.ActivityDate__c != null) { + t.isReminderSet = true; + t.ReminderDateTime = Datetime.newInstance(apTask.ActivityDate__c.year(), apTask.ActivityDate__c.month(), apTask.ActivityDate__c.day(), 0, 0, 0); + t.ReminderDateTime = t.ReminderDateTime.addMinutes(Integer.valueOf(apTask.Minutes_Reminder__c)); + } else { + t.isReminderSet = false; + } + + APTask__c apt = mapAP.get(apTask.Id); + + if (apt != null) { + insertedAP = insertedActionPlans.get(apt.Action_Plan__c); + } + + //link to Action Plan's Related To Object + for (String s : ActionPlansUtilities.getCustomRelationshipFields()) { + String f = s; + if ( + !f.equalsIgnoreCase(ActionPlansUtilities.namespacePrefix + 'Contact__c') && + insertedAP.get(f) != null + ) { + t.WhatId = (Id) insertedAP.get(f); + break; + } + } + } + + Database.DMLOptions dmlo1 = new Database.DMLOptions(); + dmlo1.EmailHeader.triggerUserEmail = true; + + Set relObjectIDs = new Set(); + for (ActionPlan__c ap : actionPlansToInsert.values()) { + relObjectIDs.add(ap.Id); + } + + if (mySettings != null && mySettings.Chatter_Object_Brag__c) { + ActionPlansBuilderUtilities.generateObjectFeeds(relObjectIDs); + } + + for (CreateActionPlanRequest request : requests) { + resultIDs.add(actionPlansToInsert.get(request.relatedRecordID).Id); + } + + return resultIDs; +} + +global class CreateActionPlanRequest { + @InvocableVariable(required=true label='The parent Record ID' description=55) + global Id relatedRecordID; +} +} + +trigger APAccount on Account(before delete, after undelete) { +ActionPlansTriggerHandlers.triggerhandlerActionPlanAccount(Trigger.new, Trigger.old, Trigger.newMap, Trigger.oldMap, Trigger.operationType); + ActionPlansTriggerHandlers.actionPlansSObjectTriggerHandler('Account'); +} + +/** +* SHOULD BE RECOGNIZED AS JAVA +* @author John Smith +*/ +package l2f.gameserver.model; + +public abstract strictfp class L2Char extends L2Object { +public static final Short ERROR = 0x0001; + +public void _moveTo(int x, int y, int z, customtype a) { + _ai = null; + log("Should not be called"); + if (1 > 5) { // wtf!? + return; + } +} +} + +public without sharing class AccountSampleTriggerHandler extends TriggerHandler, Database.schedulable, Batchable { +private List newRecords; +private List oldRecords; +private Map newRecordsMap; +private Map oldRecordsMap; + +switch on context { + when 'BEFORE_INSERT' { + this.triggerEvent = System.TriggerOperation.BEFORE_INSERT; + } + when else { + // we are not in trigger context + this.isTriggerExecuting = false; + } +} + +public AccountSampleTriggerHandler(CustomType a, String className) { + this.newRecords = (List) Trigger.new; + this.newRecordsMap = (Map) Trigger.newMap; +} + +public override sobject beforeInsert() { + method1(); +} + +//public override void afterUpdate(){} + +private void method1() { + for (Account a : newRecords) { + a.Name = a.Name.toUpperCase(); + a.Name = new FooBar(); + } +} + +@TestVisible +(SeeAllData=true) +private void method2() { + for (Account a : newRecords) { + a.Name = a.Name.toLowerCase(); + } +} + +@future +(label = true) +private void method3() { + Contact[] acctContacts = [SELECT Id FROM Contact WHERE AccountId IN :newRecordsMap.keyset() WITH SECURITY_ENFORCED]; + List acctContacts2 = [SELECT Id FROM Contact WHERE ID = '012000000' AND CreatedDate = :LAST_N_DAYS:90 WITH SECURITY_ENFORCED]; + if (Contact.getSObjectType().getDescribe().isUpdateable()) { + update as user acctContacts; //NOPMD + } + // do things here +} +} + +public without sharing class AccountSampleTriggerHandler extends Database.schedulable, Batchable { +@isTest +private testMethod void testme(){ + Assert.isTrue(true); +} + +@testVisible2 +private List recordTypes { get; private set; } +} + +public virtual class Marker { +public virtual void write() { + System.debug('Writing some text.'); +} + +public virtual Double discount() { + return .05; +} +} + +@IsTest(Seealldata=true) +public with sharing class L2Char implements Database.batchable { +public static final String ERROR = 0x0001; + +@InvocableMethod(label='my invocable') +public void moveTo( + integer x, + integer y, + integer z +) { + + Account a = new Account(); + a.Custom__c = 'stringvalue'; + insert a; + Boolean ai = (Boolean) false; + System.debug('Should not be called'); + if (1 > 5) { // wtf!? + Database.insert(myAccounts); + } +} + +@InvocableMethod +(label='my invocable') +public void doThis(){ +} +} + +@TestSetup +(TRUEKING=trueking) +private static void makeData(Boolean a){ + Custom__c c = new Custom__c(); + + for(Account a : acctLis ){ + ConnectApi.insert a; + } +} + +trigger CTrig on Custom__c (before insert){ +System.debug('inserting a record'); +upsert myRecord__c; +} + diff --git a/demo/highlight.css b/demo/vs.css similarity index 74% rename from demo/highlight.css rename to demo/vs.css index 1fbe3fd..a1ed6da 100644 --- a/demo/highlight.css +++ b/demo/vs.css @@ -4,14 +4,14 @@ Visual Studio-like style based on original C# coloring by Jason Diamond {"use strict";return e=>{ -const t=e.regex,a="[a-zA-Z][a-zA-Z_0-9]*",s={scope:"number",variants:[{ -match:/\b[0-9]+(?:\.[0-9]+)?/},{match:/\s(?:[0-9,]+)?\.[0-9]+/},{ -match:/\b0(x|X)[0-9a-fA-F_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/},{ -match:/\b0(b|B)[01_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/},{ -match:/\b([0-9_]+)?\.[0-9_]+((e|E)[0-9]+)?(F|f|D|d|M|m)?\b/},{ -match:/\b[0-9_]+(e|E)[0-9_]+(F|f|D|d|M|m)?\b/},{match:/\b[0-9_]+(F|f|D|d|M|m)\b/ -},{match:/\b[0-9_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/}],relevance:0},c={ -$pattern:"[A-Za-z][0-9A-Za-z$_]*", -keyword:["trigger|10","class","interface","abstract","AccessLevel","USER_MODE","SYSTEM_MODE","AccessType","break","cast","catch","continue","default","do","else","exports","extends|6","finally","for","get","put","set","global","if","implements","new","newMap|10","old|10","oldMap|10","operationType","override","private","protected","public","return","size","static","throws","throw","testmethod|10","try","virtual","webservice","when","while"], -"variable.language":["final","instanceof","super","this","transient"], -built_in:["finish","start","execute"].concat(["insert","update","upsert|8","delete","undelete","merge","convertLead|10"]), -type:["anytype","blob|0","boolean|0","byte|0","currency|0","date|0","datetime|0","decimal|0","double|0","enum|0","float|0","integer|0","long|0","object","pagereference|10","selectoption|10","short|0","sobject|10","string|0","time|0","void|0","float|0"], -literal:["false","true","null"]},n={ -match:t.either(/-/,/--/,/~/,/\*/,/\*=/,/\/=/,/%/,/\+/,/\+\+/,/<>/,/>=/,/<=/,/\s<\s/,/\s>\s/,/\^/,/\^=/,/!=/,/!/,/==/,/&&/,/&/,/\|\|/,/\|/,/(?<=\s)\?|:(?=\s)/,/=/,/=>/,/\?\./), -scope:"operator",relevance:0},r={ -match:[/\b/,t.either("ApexPages|10","AppLauncher","Approval","Assert","Auth","Cache","Canvas","ChatterAnswers|10","CommercePayments|10","ConnectApi|10","Database","Datacloud|10","Dataweave|10","DataSource|10","Dom","EventBus|10","ExternalService","Flow","Functions","Invocable","KbManagement|10","Label","LxScheduler|10","Messaging","Metadata","Pref_center|10","Process","QuickAction","Reports","RichMessageing","Savepoint","SchedulableContext","Schema","Search","Sfc|10","Sfdc_Checkout|10","sfdc_surveys|10","Site","Support","System","TerritoryMgmt|10","Test","Trigger|10","TxnSecurity|10","Type","UserProvisioning|10","VisualEditor|10","Wave|10"),/(?=\.)/], -scope:{2:"built_in"},relevance:10 -},o=e.COMMENT("//",/[$\n]/),i=e.COMMENT("/\\*","\\*/",{relevance:0,contains:[{ -begin:/\w+@/,relevance:0},{scope:"doctag",begin:"@[A-Za-z_]+"},{begin:"`", -end:"`",excludeBegin:!0,excludeEnd:!0,scope:"code", -contains:[e.BACKSLASH_ESCAPE],relevance:0},e.APOS_STRING_MODE,{ -match:[/(?<=@param)/,/\s+/,/\w+/],scope:{3:"variable"}}]}) -;t.either("label","description","callout","required","category","configurationEditor","iconName","SeeAllData") -;const l={relevance:10,scope:{1:"meta"},match:["@"+a]},b=[{ -match:/\b[a-zA-Z\d]*Exception\b/,scope:"title.class",relevance:0},{ -match:[/\wthrow\s+new\s+/,a],scope:{1:"keyword",2:"title.class"},relevance:0 -}],p=[{match:[t.concat(/\b/,a,/\b/),/>/],scope:{1:"type"},relevance:10}],u=[{ -match:[/\b(list|set|map)\s*/,"<",/[\.\w]+/],scope:{1:"type",3:"type"}, -relevance:10},{match:[a,t.lookahead(/\s*\[\]/)],scope:{1:"type"}}],E={ -variants:[{match:[/\./,t.concat("(?:"+a+")"),/(?=\s*\(\))/],scope:{ -2:"title.function.invoke"}},{ -match:[/\./,t.concat("(?:"+a+")"),/(?=\s*\([^\)])/],scope:{ -2:"title.function.invoke"}},{ -match:[/(?<=\s)/,t.concat("(?:"+a+")"),/(?=\s*\()/],scope:{2:"title.function"} -}],contains:[o,i,e.APOS_STRING_MODE],relevance:0},m={ -begin:/\[[\s\n]*(?=(SELECT|FIND))/,end:/\]/,scope:"subst",relevance:10, -contains:[{ -begin:t.concat(/\b/,t.either("ABOVE_OR_BELOW","ABOVE","ACTIVE","ADVANCED","ALL",/ALL\s+FIELDS/,"AND","ANY","ARRAY","AS","ASC","BY","CATEGORY","CONTAINS","COUNT","COUNT_DISTINCT","SUM","MAX","MIN","HOUR_IN_DAY","CONVERTCURRENCY","CUBE","DATA","DESC","DIVISION","END","EXCLUDES","FIELDS","FIND|10","FIRST","FOR","FROM",/GROUP\s+BY/,"HAVING","INCLUDES","LAST","LAST_90_DAYS","LAST_MONTH","LAST_N_DAYS","LAST_WEEK","LAST","LIKE","LIMIT","NETWORK","NEXT_90_DAYS","NEXT_MONTH","NEXT_N_DAYS","NEXT_WEEK","NULLS","OFFSET","ON","OR",/ORDER\s+BY/,"REFERENCE","RETURNING","ROLLUP","ROWS","SEARCH","SECURITY_ENFORCED","SELECT","SNIPPET","SORT","THIS_MONTH","THIS_WEEK","TODAY","TOLABEL","TOMORROW","TRACKING","TYPEOF","UPDATE",/USING\s+SCOPE/,"VIEW","VIEWSTAT","VIEWSTATE","WHERE","WITH","YESTERDAY","USER_MODE"),/\b/), -scope:"keyword"},{match:/(\bIN\b|<|<=|>|>=|\bNOT\s+IN\b|=|!\s*=|\s:{1}|:{1}\s)/, -scope:"literal"},{match:/(?<=\bFROM\b\s+)\w+/,scope:"type",relevance:0},{ -match:[t.concat(/\b/,"[a-zA-Z][a-zA-Z_]*"),":",/[0-9]+\b/],scope:{1:"keyword", -3:"number"},relevance:10},s,E,e.APOS_STRING_MODE],illegal:"::"};return{ -name:"Apex",aliases:["apex","lightning"],case_insensitive:!0, -disableAutodetect:!1,ignoreIllegals:!1,keywords:c, -illegal:["","\x3c!--","!DOCTYPE",/)/,/(\<)(?=\w)/,/\{|\}/,/\(|\)/,/\{|\}/), +scope:"punctuation",relevance:0}],T=e.inherit(e.APOS_STRING_MODE,{contains:[{ +match:/\\'/,scope:"literal"}],scope:"string",relevance:0 +}),y=e.COMMENT("//",/[$\n]/,{relevance:0}),O=[e.COMMENT("/\\*","\\*/",{ +relevance:0,contains:[{begin:/\w+@/,relevance:0},{ +match:[/@(?:exception|throws)/,o,a],scope:{1:"doctag",3:"title.class"}, +relevance:0},{begin:"@[A-Za-z_-]+",scope:"doctag",relevance:0},{ +match:[/(?<=@param)\s+/,a],scope:{2:"variable"},relevance:0},{begin:"`",end:"`", +beginScope:"hidden",endScope:"hidden",scope:"string", +contains:[e.BACKSLASH_ESCAPE],relevance:0}]}),y],L={ +match:t.concat(/(?<=\W|\b|\s)/,t.either(/--/,/\+\+/,/\&\&|\|\|/,/\*\=|\/\=|\%\=|\+\=|-\=/,/\&\=|\^\=|<<\=|>>\=|>>>\=|\|\=/,/\&|~|\^|\|/,/<<|>>/,/<\=|>\=|\s(<|>)\s/,/\=\=|!\=/,/\=>/,/!(?=\w)/,/(?<=\s)(\?|:)(?=\s)/,/\?\./,/(?)/),/(?=\W|\b|\s)/), +scope:"operator",relevance:0},N=[{match:t.concat(c,/\b(?!\s*\()/),scope:"meta" +},{begin:[t.concat(c,/\b/),/\s*/,/\(/],beginScope:{1:"meta",3:"punctuation"}, +end:/(?=\))/,contains:[{match:[n,/\s*=/],scope:{2:"operator"},contains:[L] +},T,r],keywords:{literal:S}}],D=[{match:[/\b[a-zA-Z0-9\.]*Exception/,o,a], +scope:{1:"title.class",3:"variable"},relevance:0}],_=[{ +begin:/\b(list|set|map)(?=\s*<)/,beginScope:"type",end:/\>+/, +endScope:"punctuation",contains:[{match:/\<|,/,scope:"punctuation"},{match:n, +scope:"type"}],relevance:8},{match:[t.optional(n),/\[/,t.optional(/\d+/),/\]/], +scope:{1:"variable",2:"punctuation",3:"number",4:"punctuation"}},{ +match:[a,/\[\]/],scope:{1:"type",2:"punctuation"},relevance:0}],w=[{ +match:[/(?])/],scope:{2:"variable"},relevance:0},{ +match:[/(?<=\=\s*\()/,a,"(?=\\)\\s*"+a+")"],scope:{2:"type"},relevance:0}],C={ +match:[/(?<=[^\w\.])/,t.concat(/\b/,a,/__(c|pc|r|b|e|mdt|x|share|kav|ka|history|del|s)/,/\b/),/(?=[\(\s;,])/], +scope:{2:"type"},relevance:10},I=[{match:[/\bnew\s+/,a,s],scope:{2:"type"}, +relevance:0}],U={begin:/\((?!(\s*\[))/,beginScope:"punctuation",end:/\)/, +endScope:"punctuation",relevance:0,keywords:{KEYWORDS:g},illegal:l, +contains:[T,I,O,L,_,h,r,v,{keywords:{KEYWORDS:g}, +match:t.concat(/(?<=\s|\(|\,)/,i(...S),a,/\b/,/(?!\.)/),scope:"variable"},{ +match:/\,|\./,scope:"punctuation"}]},M={scope:"params declare",end:/\)/, +endScope:"punctuation",relevance:0,keywords:{KEYWORDS:g},illegal:l, +contains:[r,T,O,_,h,{match:/\,|\(/,scope:"punctuation"},v,{ +match:[/(?<=\(|\,)\s*/,a,/(?=\s)/],scope:{2:"type"}},{match:[o,a,/\s*(?=[,)])/], +scope:{2:"variable"}}]},f=[{begin:[/\btrigger/,o,a,o,"on",o,a],beginScope:{ +1:"keyword",3:"title.class",5:"operator",7:"type"},end:/(?=\{)/,returnEnd:!0, +contains:[O,{begin:/\(/,end:/\)/,contains:[{ +match:/\b(before|after)\s+(insert|update|delete|merge|undelete)\b/, +scope:"built_in",relevance:5}]}]},{relevance:5, +match:/\b(with|without|inherited)\s+sharing\b/,scope:"keyword"},{ +begin:[/[^\.]/,/\bclass\b/],beginScope:{2:"keyword"},end:/(?=\{)/,relevance:0, +keywords:{type:u,keyword:l},contains:[{match:[/(?<=\bclass)\s+/,a],scope:{ +2:"title.class"}},{returnEnd:!0,endsWithParent:!0,variants:[{ +beginKeywords:"implements",end:/\bextends\b|\{/},{beginKeywords:"extends", +end:/\bimplements\b|\{/}],contains:[h,{match:[n,/\./,a,/(?=[,\s<])/],scope:{ +1:"built_in",3:"title.class.inherited"}},{match:t.concat(n,/(?=>)/),scope:"type" +},{match:t.concat(n,/(?!<)/),scope:"title.class.inherited"},{ +match:t.concat(/\b/,t.either("schedulable","batchable","queueable","comparable","callable"),/\b\s*(?!>)/), +scope:"title.class.inherited",relevance:8}],relevance:0}]},{ +match:[/(public|private|protected)\s+/,a,s],scope:{1:"keyword", +2:"title.function"},starts:M,relevance:0},{ +match:[/(?|\w)\s+/,a,s],scope:{2:"title.function"}, +relevance:0,starts:M},{begin:[/\benum\s+/,a,/\s*(?=\{)/],beginScope:{2:"type"}, +end:/(?=[\}\n])/,relevance:0,contains:[O,R,{match:t.concat(n), +scope:"variable.constant"}]}],k=[{match:t.concat(i(...l),/\b/,a,s), +scope:"title.function.invoke method_call",starts:U,relevance:0},{ +match:[t.concat("(?","\x3c!--","!DOCTYPE",/","<%%",":-",/\bmergesort\(/,/\bvar\s+env\b/,/\bdef\b\s\W:/,/"[^"]+"/], +contains:[N,w,_,O,C,f,[{ +match:[t.concat(/\b/,t.either(...d)),/\s+(?!\()/,t.optional(/as\s+(user|system)\b/)], +scope:{3:"keyword"}},{begin:[/\bDatabase\b/,/\./,t.either(...d),s],beginScope:{ +1:"built_in",2:"punctuation",3:"keyword invoke_database"},starts:U +}],D,P,T,I,p,k,h,r,L,R,v,Y,F]}}})();export default hljsGrammar; \ No newline at end of file diff --git a/dist/apex.min.js b/dist/apex.min.js index d42e008..b3d19cf 100644 --- a/dist/apex.min.js +++ b/dist/apex.min.js @@ -1,69 +1,112 @@ -/*! `apex` grammar compiled for Highlight.js 11.8.0 */ +/*! `apex` grammar compiled for Highlight.js 11.9.0 */ (()=>{var e=(()=>{"use strict";return e=>{ -const t=e.regex,s="[a-zA-Z][a-zA-Z_0-9]*",a={scope:"number",variants:[{ -match:/\b[0-9]+(?:\.[0-9]+)?/},{match:/\s(?:[0-9,]+)?\.[0-9]+/},{ -match:/\b0(x|X)[0-9a-fA-F_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/},{ -match:/\b0(b|B)[01_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/},{ -match:/\b([0-9_]+)?\.[0-9_]+((e|E)[0-9]+)?(F|f|D|d|M|m)?\b/},{ -match:/\b[0-9_]+(e|E)[0-9_]+(F|f|D|d|M|m)?\b/},{match:/\b[0-9_]+(F|f|D|d|M|m)\b/ -},{match:/\b[0-9_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/}],relevance:0},c={ -$pattern:"[A-Za-z][0-9A-Za-z$_]*", -keyword:["trigger|10","class","interface","abstract","AccessLevel","USER_MODE","SYSTEM_MODE","AccessType","break","cast","catch","continue","default","do","else","exports","extends|6","finally","for","get","put","set","global","if","implements","new","newMap|10","old|10","oldMap|10","operationType","override","private","protected","public","return","size","static","throws","throw","testmethod|10","try","virtual","webservice","when","while"], -"variable.language":["final","instanceof","super","this","transient"], -built_in:["finish","start","execute"].concat(["insert","update","upsert|8","delete","undelete","merge","convertLead|10"]), -type:["anytype","blob|0","boolean|0","byte|0","currency|0","date|0","datetime|0","decimal|0","double|0","enum|0","float|0","integer|0","long|0","object","pagereference|10","selectoption|10","short|0","sobject|10","string|0","time|0","void|0","float|0"], -literal:["false","true","null"]},n={ -match:t.either(/-/,/--/,/~/,/\*/,/\*=/,/\/=/,/%/,/\+/,/\+\+/,/<>/,/>=/,/<=/,/\s<\s/,/\s>\s/,/\^/,/\^=/,/!=/,/!/,/==/,/&&/,/&/,/\|\|/,/\|/,/(?<=\s)\?|:(?=\s)/,/=/,/=>/,/\?\./), -scope:"operator",relevance:0},r={ -match:[/\b/,t.either("ApexPages|10","AppLauncher","Approval","Assert","Auth","Cache","Canvas","ChatterAnswers|10","CommercePayments|10","ConnectApi|10","Database","Datacloud|10","Dataweave|10","DataSource|10","Dom","EventBus|10","ExternalService","Flow","Functions","Invocable","KbManagement|10","Label","LxScheduler|10","Messaging","Metadata","Pref_center|10","Process","QuickAction","Reports","RichMessageing","Savepoint","SchedulableContext","Schema","Search","Sfc|10","Sfdc_Checkout|10","sfdc_surveys|10","Site","Support","System","TerritoryMgmt|10","Test","Trigger|10","TxnSecurity|10","Type","UserProvisioning|10","VisualEditor|10","Wave|10"),/(?=\.)/], -scope:{2:"built_in"},relevance:10 -},o=e.COMMENT("//",/[$\n]/),i=e.COMMENT("/\\*","\\*/",{relevance:0,contains:[{ -begin:/\w+@/,relevance:0},{scope:"doctag",begin:"@[A-Za-z_]+"},{begin:"`", -end:"`",excludeBegin:!0,excludeEnd:!0,scope:"code", -contains:[e.BACKSLASH_ESCAPE],relevance:0},e.APOS_STRING_MODE,{ -match:[/(?<=@param)/,/\s+/,/\w+/],scope:{3:"variable"}}]}) -;t.either("label","description","callout","required","category","configurationEditor","iconName","SeeAllData") -;const l={relevance:10,scope:{1:"meta"},match:["@"+s]},b=[{ -match:/\b[a-zA-Z\d]*Exception\b/,scope:"title.class",relevance:0},{ -match:[/\wthrow\s+new\s+/,s],scope:{1:"keyword",2:"title.class"},relevance:0 -}],p=[{match:[t.concat(/\b/,s,/\b/),/>/],scope:{1:"type"},relevance:10}],u=[{ -match:[/\b(list|set|map)\s*/,"<",/[\.\w]+/],scope:{1:"type",3:"type"}, -relevance:10},{match:[s,t.lookahead(/\s*\[\]/)],scope:{1:"type"}}],E={ -variants:[{match:[/\./,t.concat("(?:"+s+")"),/(?=\s*\(\))/],scope:{ -2:"title.function.invoke"}},{ -match:[/\./,t.concat("(?:"+s+")"),/(?=\s*\([^\)])/],scope:{ -2:"title.function.invoke"}},{ -match:[/(?<=\s)/,t.concat("(?:"+s+")"),/(?=\s*\()/],scope:{2:"title.function"} -}],contains:[o,i,e.APOS_STRING_MODE],relevance:0},m={ -begin:/\[[\s\n]*(?=(SELECT|FIND))/,end:/\]/,scope:"subst",relevance:10, -contains:[{ -begin:t.concat(/\b/,t.either("ABOVE_OR_BELOW","ABOVE","ACTIVE","ADVANCED","ALL",/ALL\s+FIELDS/,"AND","ANY","ARRAY","AS","ASC","BY","CATEGORY","CONTAINS","COUNT","COUNT_DISTINCT","SUM","MAX","MIN","HOUR_IN_DAY","CONVERTCURRENCY","CUBE","DATA","DESC","DIVISION","END","EXCLUDES","FIELDS","FIND|10","FIRST","FOR","FROM",/GROUP\s+BY/,"HAVING","INCLUDES","LAST","LAST_90_DAYS","LAST_MONTH","LAST_N_DAYS","LAST_WEEK","LAST","LIKE","LIMIT","NETWORK","NEXT_90_DAYS","NEXT_MONTH","NEXT_N_DAYS","NEXT_WEEK","NULLS","OFFSET","ON","OR",/ORDER\s+BY/,"REFERENCE","RETURNING","ROLLUP","ROWS","SEARCH","SECURITY_ENFORCED","SELECT","SNIPPET","SORT","THIS_MONTH","THIS_WEEK","TODAY","TOLABEL","TOMORROW","TRACKING","TYPEOF","UPDATE",/USING\s+SCOPE/,"VIEW","VIEWSTAT","VIEWSTATE","WHERE","WITH","YESTERDAY","USER_MODE"),/\b/), -scope:"keyword"},{match:/(\bIN\b|<|<=|>|>=|\bNOT\s+IN\b|=|!\s*=|\s:{1}|:{1}\s)/, -scope:"literal"},{match:/(?<=\bFROM\b\s+)\w+/,scope:"type",relevance:0},{ -match:[t.concat(/\b/,"[a-zA-Z][a-zA-Z_]*"),":",/[0-9]+\b/],scope:{1:"keyword", -3:"number"},relevance:10},a,E,e.APOS_STRING_MODE],illegal:"::"};return{ -name:"Apex",aliases:["apex","lightning"],case_insensitive:!0, -disableAutodetect:!1,ignoreIllegals:!1,keywords:c, -illegal:["","\x3c!--","!DOCTYPE",/)/,/(\<)(?=\w)/,/\{|\}/,/\(|\)/,/\{|\}/), +scope:"punctuation",relevance:0}],T=e.inherit(e.APOS_STRING_MODE,{contains:[{ +match:/\\'/,scope:"literal"}],scope:"string",relevance:0 +}),y=e.COMMENT("//",/[$\n]/,{relevance:0}),O=[e.COMMENT("/\\*","\\*/",{ +relevance:0,contains:[{begin:/\w+@/,relevance:0},{ +match:[/@(?:exception|throws)/,o,a],scope:{1:"doctag",3:"title.class"}, +relevance:0},{begin:"@[A-Za-z_-]+",scope:"doctag",relevance:0},{ +match:[/(?<=@param)\s+/,a],scope:{2:"variable"},relevance:0},{begin:"`",end:"`", +beginScope:"hidden",endScope:"hidden",scope:"string", +contains:[e.BACKSLASH_ESCAPE],relevance:0}]}),y],L={ +match:t.concat(/(?<=\W|\b|\s)/,t.either(/--/,/\+\+/,/\&\&|\|\|/,/\*\=|\/\=|\%\=|\+\=|-\=/,/\&\=|\^\=|<<\=|>>\=|>>>\=|\|\=/,/\&|~|\^|\|/,/<<|>>/,/<\=|>\=|\s(<|>)\s/,/\=\=|!\=/,/\=>/,/!(?=\w)/,/(?<=\s)(\?|:)(?=\s)/,/\?\./,/(?)/),/(?=\W|\b|\s)/), +scope:"operator",relevance:0},N=[{match:t.concat(c,/\b(?!\s*\()/),scope:"meta" +},{begin:[t.concat(c,/\b/),/\s*/,/\(/],beginScope:{1:"meta",3:"punctuation"}, +end:/(?=\))/,contains:[{match:[n,/\s*=/],scope:{2:"operator"},contains:[L] +},T,r],keywords:{literal:S}}],D=[{match:[/\b[a-zA-Z0-9\.]*Exception/,o,a], +scope:{1:"title.class",3:"variable"},relevance:0}],_=[{ +begin:/\b(list|set|map)(?=\s*<)/,beginScope:"type",end:/\>+/, +endScope:"punctuation",contains:[{match:/\<|,/,scope:"punctuation"},{match:n, +scope:"type"}],relevance:8},{match:[t.optional(n),/\[/,t.optional(/\d+/),/\]/], +scope:{1:"variable",2:"punctuation",3:"number",4:"punctuation"}},{ +match:[a,/\[\]/],scope:{1:"type",2:"punctuation"},relevance:0}],w=[{ +match:[/(?])/],scope:{2:"variable"},relevance:0},{ +match:[/(?<=\=\s*\()/,a,"(?=\\)\\s*"+a+")"],scope:{2:"type"},relevance:0}],C={ +match:[/(?<=[^\w\.])/,t.concat(/\b/,a,/__(c|pc|r|b|e|mdt|x|share|kav|ka|history|del|s)/,/\b/),/(?=[\(\s;,])/], +scope:{2:"type"},relevance:10},I=[{match:[/\bnew\s+/,a,s],scope:{2:"type"}, +relevance:0}],U={begin:/\((?!(\s*\[))/,beginScope:"punctuation",end:/\)/, +endScope:"punctuation",relevance:0,keywords:{KEYWORDS:v},illegal:l, +contains:[T,I,O,L,_,h,r,g,{keywords:{KEYWORDS:v}, +match:t.concat(/(?<=\s|\(|\,)/,i(...S),a,/\b/,/(?!\.)/),scope:"variable"},{ +match:/\,|\./,scope:"punctuation"}]},M={scope:"params declare",end:/\)/, +endScope:"punctuation",relevance:0,keywords:{KEYWORDS:v},illegal:l, +contains:[r,T,O,_,h,{match:/\,|\(/,scope:"punctuation"},g,{ +match:[/(?<=\(|\,)\s*/,a,/(?=\s)/],scope:{2:"type"}},{match:[o,a,/\s*(?=[,)])/], +scope:{2:"variable"}}]},f=[{begin:[/\btrigger/,o,a,o,"on",o,a],beginScope:{ +1:"keyword",3:"title.class",5:"operator",7:"type"},end:/(?=\{)/,returnEnd:!0, +contains:[O,{begin:/\(/,end:/\)/,contains:[{ +match:/\b(before|after)\s+(insert|update|delete|merge|undelete)\b/, +scope:"built_in",relevance:5}]}]},{relevance:5, +match:/\b(with|without|inherited)\s+sharing\b/,scope:"keyword"},{ +begin:[/[^\.]/,/\bclass\b/],beginScope:{2:"keyword"},end:/(?=\{)/,relevance:0, +keywords:{type:u,keyword:l},contains:[{match:[/(?<=\bclass)\s+/,a],scope:{ +2:"title.class"}},{returnEnd:!0,endsWithParent:!0,variants:[{ +beginKeywords:"implements",end:/\bextends\b|\{/},{beginKeywords:"extends", +end:/\bimplements\b|\{/}],contains:[h,{match:[n,/\./,a,/(?=[,\s<])/],scope:{ +1:"built_in",3:"title.class.inherited"}},{match:t.concat(n,/(?=>)/),scope:"type" +},{match:t.concat(n,/(?!<)/),scope:"title.class.inherited"},{ +match:t.concat(/\b/,t.either("schedulable","batchable","queueable","comparable","callable"),/\b\s*(?!>)/), +scope:"title.class.inherited",relevance:8}],relevance:0}]},{ +match:[/(public|private|protected)\s+/,a,s],scope:{1:"keyword", +2:"title.function"},starts:M,relevance:0},{ +match:[/(?|\w)\s+/,a,s],scope:{2:"title.function"}, +relevance:0,starts:M},{begin:[/\benum\s+/,a,/\s*(?=\{)/],beginScope:{2:"type"}, +end:/(?=[\}\n])/,relevance:0,contains:[O,R,{match:t.concat(n), +scope:"variable.constant"}]}],k=[{match:t.concat(i(...l),/\b/,a,s), +scope:"title.function.invoke method_call",starts:U,relevance:0},{ +match:[t.concat("(?","\x3c!--","!DOCTYPE",/","<%%",":-",/\bmergesort\(/,/\bvar\s+env\b/,/\bdef\b\s\W:/,/"[^"]+"/], +contains:[N,w,_,O,C,f,[{ +match:[t.concat(/\b/,t.either(...d)),/\s+(?!\()/,t.optional(/as\s+(user|system)\b/)], +scope:{3:"keyword"}},{begin:[/\bDatabase\b/,/\./,t.either(...d),s],beginScope:{ +1:"built_in",2:"punctuation",3:"keyword invoke_database"},starts:U +}],D,P,T,I,p,k,h,r,L,R,g,Y,F]}}})();hljs.registerLanguage("apex",e)})(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 80529dd..997eff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "highlightjs-apex", "version": "1.2.1", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -52,9 +52,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -86,13 +86,12 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -212,7 +211,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/debug": { @@ -326,13 +325,13 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -384,6 +383,16 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -425,7 +434,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -453,7 +462,7 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -565,15 +574,6 @@ "node": ">=10" } }, - "node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -653,7 +653,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -701,7 +701,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -758,7 +758,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -818,7 +818,7 @@ "node_modules/should-format": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", "dev": true, "dependencies": { "should-type": "^1.3.0", @@ -828,7 +828,7 @@ "node_modules/should-type": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", "dev": true }, "node_modules/should-type-adaptors": { @@ -938,7 +938,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "node_modules/y18n": { @@ -1004,719 +1004,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "highlight.js": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", - "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - } - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "requires": { - "should-type": "^1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } } } diff --git a/package.json b/package.json index a3583c8..753b7b5 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,10 @@ "scripts": { "test": "mocha --reporter spec", "mocha": "mocha test/markup", - "npm-patch": "npm version patch && npm publish", - "npm-beta": "npm publish --tag beta" + "npm-beta": "npm version patch && npm publish --tag beta", + "npm-patch": "npm version patch && npm publish", + "prettier:verify": "prettier --list-different \"{test,src,demo,scripts}/**/*\"", + "prettier": "prettier --write \"{test,src,demo,scripts}/**/*\"" }, "repository": { "type": "git", diff --git a/scripts/cheatsheet.txt b/scripts/cheatsheet.txt new file mode 100644 index 0000000..4867169 --- /dev/null +++ b/scripts/cheatsheet.txt @@ -0,0 +1,19 @@ +#!/bin/sh + +## build for webpage +npm run build-cdn apex + +## Set up developer.html +# build just common set +node ./tools/build.js -t browser :common + +# build common set + 3rd party `apex` from extra +node ./tools/build.js -t browser :common apex + +# build everything (including all in extra) +node ./tools/build.js -t browser + +# run all builds +node tools/build.js -t node apex +node tools/build.js -t cdn :common apex +node tools/build.js -t browser :common apex diff --git a/src/languages/apex.js b/src/languages/apex.js index 9fef05f..86f77cc 100644 --- a/src/languages/apex.js +++ b/src/languages/apex.js @@ -1,7 +1,7 @@ /* Language: Apex Author: David Schach -Category: Salesforce, Force.com, Lightning Platform, Salesforce Platform +Category: Salesforce, Force.com, Salesforce Platform, Einstein 1 Platform Website: https://developer.salesforce.com/ */ @@ -9,105 +9,86 @@ Website: https://developer.salesforce.com/ export default function (hljs) { const regex = hljs.regex; const APEX_IDENT_RE = '[a-zA-Z][a-zA-Z_0-9]*'; - const APEX_ALPHA_UNDER = '[a-zA-Z][a-zA-Z_]*'; - //const APEX_FULL_TYPE_RE = '[a-zA-Z][a-zA-Z_0-9.<>]*'; + const APEX_IDENT_WORD_RE = '\\b' + APEX_IDENT_RE + '\\b'; + const ANNOTATION_RE = '@' + APEX_IDENT_RE; + const SPACEPARENS_LOOKAHEAD = /(?=\s*\()/; + const SPACE = /\s+/; - const NUMBER = { + /** + * @param {...(RegExp | string) } args + * @returns {string} + */ + function negLookaheadAny(...list) { + return regex.concat('(?!', list.join('|'), ')'); + } + + const NUMBERS = { scope: 'number', - variants: [ - { - match: /\b[0-9]+(?:\.[0-9]+)?/ - }, - { - match: /\s(?:[0-9,]+)?\.[0-9]+/ - }, - { - // hex - // 0b binary-digits integer-type-suffix[opt] OR 0B binary-digits integer-type-suffix[opt] - match: /\b0(x|X)[0-9a-fA-F_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/ - }, - { - // numeric binary - match: /\b0(b|B)[01_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/ - }, - { - // numeric decimal - // decimal-digits . decimal-digits exponent-part[opt] real-type-suffix[opt] OR . decimal-digits exponent-part[opt] real-type-suffix[opt] - match: /\b([0-9_]+)?\.[0-9_]+((e|E)[0-9]+)?(F|f|D|d|M|m)?\b/ - }, - { - // numeric decimal - // decimal-digits exponent-part real-type-suffix[opt] - match: /\b[0-9_]+(e|E)[0-9_]+(F|f|D|d|M|m)?\b/ - }, - { - // numeric decimal - // decimal-digits real-type-suffix - match: /\b[0-9_]+(F|f|D|d|M|m)\b/ - }, - { - // numeric decimal - // decimal-digits integer-type-suffix[opt] - match: /\b[0-9_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/ - } - ], + match: regex.either( + /\b(\d{4}\-\d{2}\-\d{2}T\d{2}\:\d{2}\:\d{2}(\.\d{1,3})?(\-|\+)\d{2}\:\d{2})\b/, //datetime + /\b(\d{4}\-\d{2}\-\d{2}T\d{2}\:\d{2}\:\d{2}(\.\d{1,3})?(Z)?)\b/, //datetime + /\b(\d{4}\-\d{2}\-\d{2})\b/, //date + /\b0(x|X)[0-9a-fA-F_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/, //hex + /\b0(b|B)[01_]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/, //binary + /\b([0-9]+)?\.[0-9]+((e|E)[0-9]+)?(F|f|D|d|M|m)?\b/, //decimal + /(-?)\b[0-9]+(e|E)[0-9]+(F|f|D|d|M|m)?\b/, //decimal + /(-?)\b[0-9]+(F|f|D|d|M|m)\b/, //decimal + /(-?)\b[0-9]+(U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?\b/, //decimal + /(-?)(\b0[0-9]+|(\b\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)/ // C_NUMBER_MODE + ), relevance: 0 }; - const MAIN_KEYWORDS = [ - 'trigger|10', - 'class', - 'interface', - 'abstract', - 'AccessLevel', - 'USER_MODE', - 'SYSTEM_MODE', - 'AccessType', - 'break', - 'cast', + // keyword + const KEYWORD_LIST = [ + 'try', 'catch', - 'continue', - 'default', - 'do', - 'else', - 'exports', - 'extends|6', 'finally', - 'for', 'get', - 'put', 'set', - 'global', + 'put', 'if', + 'for', + 'else', + 'do', + 'while', + 'continue', + 'break', 'implements', - 'new', - 'newMap|10', - 'old|10', - 'oldMap|10', - 'operationType', + 'extends', + 'return', + 'throw', + 'when', + 'new' + ]; + + const LANGUAGE_VAR_LIST = ['instanceof', 'super', 'this']; + + const LANGUAGE_VARS_RE = { + match: regex.concat(/\b/, regex.either(...LANGUAGE_VAR_LIST), /\b/), + scope: 'variable.language', + relevance: 0 + }; + + // keyword + const STORAGE_MODIFIER_LIST = [ + 'abstract', + 'final', + 'global', + 'interface', 'override', 'private', 'protected', 'public', - 'return', - 'size', 'static', - 'throws', - 'throw', - 'testmethod|10', - 'try', + 'testMethod', + 'transient', 'virtual', - 'webservice', - 'when', - 'while' + 'webservice' ]; - const LANGUAGE_VARS = ['final', 'instanceof', 'super', 'this', 'transient']; - - const LITERALS = ['false', 'true', 'null']; - const TYPES = [ - 'anytype', + 'anytype|0', 'blob|0', 'boolean|0', 'byte|0', @@ -120,7 +101,7 @@ export default function (hljs) { 'float|0', 'integer|0', 'long|0', - 'object', + 'object|0', 'pagereference|10', 'selectoption|10', 'short|0', @@ -131,164 +112,268 @@ export default function (hljs) { 'float|0' ]; - const BUILT_INS = ['finish', 'start', 'execute']; - const DMLS = [ 'insert', 'update', - 'upsert|8', + 'upsert', 'delete', 'undelete', 'merge', - 'convertLead|10' + 'convertLead' ]; - const IMPORTANT_WORDS = { - beginKeywords: 'schedulable batchable queueable comparable callable', - relevance: 10 - }; - - // Extraneous for now - will be useful if we go this route BUT will need more maintenance - /* const APEX_ANNOTATIONS = [ - '@AuraEnabled', - '@Deprecated', - '@Future', - '@HttpDelete', - '@HttpGet', - '@HttpPatch', - '@HttpPost', - '@HttpPut', - '@InvocableMethod', - '@InvocableVariable', - '@IsTest', - '@JsonAccess', - '@namespaceAccessible,', - '@ReadOnly', - '@RemoteAction', - '@RestResource', - '@SuppressWarnings', - '@TestSetup', - '@TestVisible' - ]; */ - - const KEYWORDS = { - $pattern: '[A-Za-z][0-9A-Za-z$_]*', - keyword: MAIN_KEYWORDS, - 'variable.language': LANGUAGE_VARS, - built_in: BUILT_INS.concat(DMLS), - type: TYPES, - literal: LITERALS - }; - - const COMPOUND_KEYWORDS = { - match: /\b(switch\s+on|as\s+user|as\s+system)\b/, - relevance: 8, - scope: 'keyword' - }; + const SYSTEM_INTERFACES = [ + 'schedulable', + 'batchable', + 'queueable', + 'comparable', + 'callable' + ]; const NAMESPACE_LIST = [ - 'ApexPages|10', + //'ApexPages', // also a System class 'AppLauncher', 'Approval', - 'Assert', 'Auth', 'Cache', 'Canvas', - 'ChatterAnswers|10', - 'CommercePayments|10', - 'ConnectApi|10', + 'ChatterAnswers', + 'CommercePayments', + 'ConnectApi', 'Database', - 'Datacloud|10', - 'Dataweave|10', - 'DataSource|10', + 'Datacloud', + 'Dataweave', + 'DataSource', 'Dom', - 'EventBus|10', + 'EventBus', 'ExternalService', 'Flow', 'Functions', 'Invocable', - 'KbManagement|10', - 'Label', - 'LxScheduler|10', + 'KbManagement', + 'LxScheduler', 'Messaging', 'Metadata', - 'Pref_center|10', + 'Pref_center', 'Process', 'QuickAction', 'Reports', 'RichMessageing', - 'Savepoint', - 'SchedulableContext', - 'Schema', + //'Schema', // also a System class 'Search', - 'Sfc|10', - 'Sfdc_Checkout|10', - 'sfdc_surveys|10', + 'Sfc', + 'Sfdc_Checkout', + 'sfdc_surveys', 'Site', 'Support', 'System', - 'TerritoryMgmt|10', + 'TerritoryMgmt', + 'TxnSecurity', + 'UserProvisioning', + 'VisualEditor', + 'Wave' + ]; + + // TODO: Check if these are necessary + const SYSTEM_CLASSES = [ + 'AccessLevel', + 'Address', + 'Answers', + 'ApexPages', + 'Approval', + 'Assert', + 'AsyncInfo', + 'AsyncOptions', + 'BusinessHours', + 'Cases', + 'Collator', + 'Continuation', + 'Cookie', + 'Crypto', + 'Database', + 'Date', + 'Datetime', + 'Decimal', + 'Domain', + 'DomainCreator', + 'DomainParser', + 'EmailMessages', + 'EncodingUtil', + 'EventBus', + 'Exception', + 'FeatureManagement', + 'FlexQueue', + 'Formula', + 'FormulaRecalcFieldError', + 'FormulaRecalcResult', + 'Http', + 'HttpRequest', + 'HttpResponse', + 'Ideas', + 'JSON', + 'JSONGenerator', + 'JSONParser', + 'Label', + 'Limits', + 'Location', + 'Matcher', + 'Math', + 'Messaging', + 'MultiStaticResourceCalloutMock', + 'Network', + 'OrgLimit', + 'OrgLimits', + 'Packaging', + 'PageReference', + 'Pattern', + 'QueueableDuplicateSignature', + 'QueueableDuplicateSignature.Builder', + 'QuickAction', + 'Request', + 'ResetPasswordResult', + 'RestContext', + 'RestRequest', + 'RestResponse', + 'Schema', + 'Search', + 'Security', + 'SelectOption', + 'Site', + 'SObject', + 'SObjectAccessDecision', + 'StaticResourceCalloutMock', 'Test', - 'Trigger|10', - 'TxnSecurity|10', + 'TimeZone', + //'Trigger', // handled separately 'Type', - 'UserProvisioning|10', - 'VisualEditor|10', - 'Wave|10' + 'URL', + 'UserInfo', + 'UserManagement', + 'Version', + 'WebServiceCallout', + 'XmlStreamReader', + 'XmlStreamWriter' ]; - const OPERATOR_REGEX = [ - /-/, - /--/, - /~/, - /\*/, - /\*=/, - /\/=/, - /%/, - /\+/, - /\+\+/, - /<>/, - />=/, - /<=/, - /\s<\s/, - /\s>\s/, - /\^/, - /\^=/, - /!=/, - /!/, - /==/, - /&&/, - /&/, - /\|\|/, - /\|/, - /(?<=\s)\?|:(?=\s)/, - /=/, - /=>/, - /\?\./ + const SYSTEM_ENUMS = [ + 'AccessType', + 'AccessLevel', + 'DomainType', + 'JSONToken', + 'LoggingLevel', + 'Quiddity', + 'TriggerOperation', + 'operationType' ]; - const OPERATORS = { - match: regex.either(...OPERATOR_REGEX), - scope: 'operator', - relevance: 0 + const BUILT_INS = NAMESPACE_LIST.concat(...SYSTEM_CLASSES); + + const NAMESPACES = [ + { + match: [ + regex.concat(/\b/, regex.either(...SYSTEM_ENUMS)), + /\./, + APEX_IDENT_RE, + /(?![\.\(])/ + ], + scope: { 1: 'built_in', 2: 'punctuation', 3: 'variable.constant' }, // TODO: Find a better scope for the enum value + relevance: 0 + }, + { + match: regex.concat( + /\b/, + regex.either(...NAMESPACE_LIST), + regex.concat('\b(?!\\.', regex.either(...SYSTEM_CLASSES), ')') + ), + scope: 'built_in', + relevance: 0 + }, + { + // System and its classes + match: [/\b/, 'System', /\./, regex.either(...SYSTEM_CLASSES), /(?=\.)/], + scope: { 2: 'built_in', 3: 'punctuation', 4: 'built_in' }, + relevance: 5 + }, + { + match: [ + regex.concat('(?<=\\b', regex.either(...BUILT_INS), ')'), + /\./, + APEX_IDENT_RE, + regex.lookahead(/[\(\s]/) + ], + scope: { 2: 'punctuation', 3: 'keyword' }, + relevance: 0 + }, + { + begin: regex.concat(/\b/, 'Trigger', /\b/), + beginScope: 'built_in', + variants: [ + { + end: [ + /\./, + /(isExecuting|isInsert|isUpdate|isDelete|isBefore|isAfter|isUndelete|new|newMap|old|oldMap|size|operationType)\b(?!\.)/ + ], + endScope: { 1: 'punctuation', 2: 'keyword' }, + relevance: 10 + }, + { + end: [/\./, 'operationtype', /\./, APEX_IDENT_WORD_RE], + endScope: { + 1: 'punctuation', + 2: 'keyword', + 3: 'punctuation', + 4: 'variable.constant' + }, + relevance: 10 + } + ] + } + ]; + + const LITERALS = ['false', 'true', 'null']; + + const SALESFORCE_ID = { + match: /(?)/, + /(\<)(?=\w)/, + /\{|\}/, + /\(|\)/, + /\{|\}/ + ]; + const PUNCTUATION = [ + { + match: regex.either(...PUNCTUATION_LIST), + scope: 'punctuation', + relevance: 0 } - }; + ]; - const COMMENT_LINE = hljs.COMMENT('//', /[$\n]/); + const STRINGS = hljs.inherit(hljs.APOS_STRING_MODE, { + contains: [{ match: /\\'/, scope: 'literal' }], + scope: 'string', + relevance: 0 + }); + + const COMMENT_LINE = hljs.COMMENT('//', /[$\n]/, { + relevance: 0 + }); const COMMENT_BLOCK = hljs.COMMENT('/\\*', '\\*/', { relevance: 0, @@ -299,160 +384,454 @@ export default function (hljs) { relevance: 0 }, { + match: [/@(?:exception|throws)/, SPACE, APEX_IDENT_RE], + scope: { 1: 'doctag', 3: 'title.class' }, + relevance: 0 + }, + { + begin: '@[A-Za-z_-]+', scope: 'doctag', - begin: '@[A-Za-z_]+' + relevance: 0 + }, + { + match: [/(?<=@param)\s+/, APEX_IDENT_RE], + scope: { 2: 'variable' }, + relevance: 0 }, { begin: '`', end: '`', - excludeBegin: true, - excludeEnd: true, - scope: 'code', + beginScope: 'hidden', + endScope: 'hidden', + scope: 'string', contains: [hljs.BACKSLASH_ESCAPE], relevance: 0 - }, - hljs.APOS_STRING_MODE, - { - match: [/(?<=@param)/, /\s+/, /\w+/], - scope: { - 3: 'variable' - } } ] }); - // Extraneous for now - will be useful if we go this route BUT will need more maintenance - /* const ANNOTATION_MODIFIER_TYPES = [ - 'required', - 'label', - 'description', - 'seealldata|10', - 'isparallel|10', - 'callout', - 'urlMapping', - 'serializable', - 'deserializable', - 'category', - 'configurationEditor', - 'IconName', - 'cacheable', - 'scope' - ]; */ - - const ANNOTATION_ATTRIBUTES = [ - 'label', - 'description', - 'callout', - 'required', - 'category', - 'configurationEditor', - 'iconName', - 'SeeAllData' + const COMMENTS = [COMMENT_BLOCK, COMMENT_LINE]; + + const OPERATORS_RE = [ + /--/, // decrement + /\+\+/, // increment + /\&\&|\|\|/, // logical + /\*\=|\/\=|\%\=|\+\=|-\=/, // assignment.compound + /\&\=|\^\=|<<\=|>>\=|>>>\=|\|\=/, // assignment.compound.bitwise + /\&|~|\^|\|/, // bitwise + /<<|>>/, // bitwise.shift + /<\=|>\=|\s(<|>)\s/, // relational + /\=\=|!\=/, // comparison + /\=>/, // map assign + /!(?=\w)/, // negator + /(?<=\s)(\?|:)(?=\s)/, // standalone ? or : (ternary operator?) + /\?\./, // null-safe operator + /(?)/ // assignment ]; - const ANNOTATION_ATTRIBUTE_PARAMS = { - - match: [/(?/], + //scope: 'clause: collection', + begin: /\b(list|set|map)(?=\s*<)/, + beginScope: 'type', + end: /\>+/, + endScope: 'punctuation', + contains: [ + { match: /\<|,/, scope: 'punctuation' }, + { + match: APEX_IDENT_WORD_RE, + scope: 'type' + } + ], + relevance: 8 + }, + + { + // array reference (only has integer in array) + match: [ + regex.optional(APEX_IDENT_WORD_RE), + /\[/, + regex.optional(/\d+/), + /\]/ + ], + scope: { 1: 'variable', 2: 'punctuation', 3: 'number', 4: 'punctuation' } + }, + { + // type[] var = new type[]{values} + match: [APEX_IDENT_RE, /\[\]/], // array notation scope: { - 1: 'type' + 1: 'type', + 2: 'punctuation' }, - relevance: 10 + relevance: 0 } ]; - const COLLECTION_DECLARATION = [ + const MISCELLANEOUS = [ { - match: [/\b(list|set|map)\s*/, '<', /[\.\w]+/], - scope: { 1: 'type', 3: 'type' }, - relevance: 10 + // mynum = + // could also be a collection variable + match: [/(?])/], + scope: { 2: 'variable' }, + relevance: 0 }, + // Casting { - match: [APEX_IDENT_RE, regex.lookahead(/\s*\[\]/)], + match: [ + /(?<=\=\s*\()/, + APEX_IDENT_RE, + '(?=\\)\\s*' + APEX_IDENT_RE + ')' + ], scope: { - 1: 'type' - } + 2: 'type' + }, + relevance: 0 } ]; - - const CUSTOM_OBJECT = { + // * Can use later; omitted for now + const CUSTOM_METADATA = { // Custom fields, types, etc. - match: [/[^\.]/, /\b[a-zA-Z][a-zA-Z\d_]*__[cxebr]\b/, /[\(\s;,]+/], + match: [ + /(?<=[^\w\.])/, + regex.concat( + /\b/, + APEX_IDENT_RE, + /__(c|pc|r|b|e|mdt|x|share|kav|ka|history|del|s)/, + /\b/ + ), + /(?=[\(\s;,])/ + ], scope: { 2: 'type' }, relevance: 10 }; - const METHOD_CALL = { + const INSTANTIATE_TYPE = [ + { + // Account a = new Account(Name = 'test account); + match: [/\bnew\s+/, APEX_IDENT_RE, SPACEPARENS_LOOKAHEAD], + scope: { 2: 'type' }, + relevance: 0 + } + ]; + + const PARAMS_CALL = { + //scope: 'clause: params call', + begin: /\((?!(\s*\[))/, + beginScope: 'punctuation', + end: /\)/, + endScope: 'punctuation', + relevance: 0, + keywords: { + KEYWORDS + }, + illegal: KEYWORD_LIST, + contains: [ + STRINGS, + INSTANTIATE_TYPE, + COMMENTS, + OPERATORS, + COLLECTIONS, + NAMESPACES, + NUMBERS, + SALESFORCE_ID, + { + keywords: { KEYWORDS }, + // mymethod(var1, var2); comma-separated list + // must be followed by comma or paren + match: regex.concat( + /(?<=\s|\(|\,)/, + negLookaheadAny(...LITERALS), + APEX_IDENT_RE, + /\b/, + /(?!\.)/ + ), + scope: 'variable' + }, + { match: /\,|\./, scope: 'punctuation' } + ] + }; + + const EXTEND_IMPLEMENT = { + returnEnd: true, + endsWithParent: true, variants: [ { - match: [/\./, regex.concat('(?:' + APEX_IDENT_RE + ')'), /(?=\s*\(\))/], - scope: { 2: 'title.function.invoke' } + beginKeywords: 'implements', + end: /\bextends\b|\{/ + //scope: 'clause: implements block' }, { - match: [ - /\./, - regex.concat('(?:' + APEX_IDENT_RE + ')'), - /(?=\s*\([^\)])/ - ], - scope: { 2: 'title.function.invoke' } + beginKeywords: 'extends', + end: /\bimplements\b|\{/ + //scope: 'clause: extends block' + } + ], + contains: [ + NAMESPACES, + { + match: [APEX_IDENT_WORD_RE, /\./, APEX_IDENT_RE, /(?=[,\s<])/], + scope: { 1: 'built_in', 3: 'title.class.inherited' } }, { - match: [ - /(?<=\s)/, - regex.concat('(?:' + APEX_IDENT_RE + ')'), - /(?=\s*\()/ - ], - scope: { 2: 'title.function' } + match: regex.concat(APEX_IDENT_WORD_RE, /(?=>)/), + scope: 'type' + }, + { + match: regex.concat(APEX_IDENT_WORD_RE, /(?!<)/), + scope: 'title.class.inherited' + }, + { + match: regex.concat( + /\b/, + regex.either(...SYSTEM_INTERFACES), + /\b\s*(?!>)/ + ), + scope: 'title.class.inherited', + relevance: 8 } ], - contains: [COMMENT_LINE, COMMENT_BLOCK, hljs.APOS_STRING_MODE], relevance: 0 }; + const PARAMS_DECLARATION = { + scope: 'params declare', // NOTE: declaration + end: /\)/, + endScope: 'punctuation', + relevance: 0, + keywords: { + KEYWORDS + }, + illegal: KEYWORD_LIST, + contains: [ + NUMBERS, + + STRINGS, + COMMENTS, + COLLECTIONS, + NAMESPACES, + { match: /\,|\(/, scope: 'punctuation' }, + SALESFORCE_ID, + { + match: [/(?<=\(|\,)\s*/, APEX_IDENT_RE, /(?=\s)/], + scope: { 2: 'type' } + }, + { + // mymethod(Date myDate, Date yourDate); highlights second part of each parameter + // must be followed by comma or paren + match: [SPACE, APEX_IDENT_RE, /\s*(?=[,)])/], + + scope: { 2: 'variable' } + } + ] + }; + + const DECLARATIONS = [ + { + // trigger declaration + begin: [ + /\btrigger/, + SPACE, + APEX_IDENT_RE, + SPACE, + 'on', + SPACE, + APEX_IDENT_RE + ], + beginScope: { + 1: 'keyword', + 3: 'title.class', + 5: 'operator', + 7: 'type' + }, + end: /(?=\{)/, + returnEnd: true, + //scope: 'clause: trigger_declaration', + contains: [ + COMMENTS, + { + begin: /\(/, + end: /\)/, + contains: [ + { + match: + /\b(before|after)\s+(insert|update|delete|merge|undelete)\b/, + scope: 'built_in', + relevance: 5 + } + ] + } + ] + }, + { + // class sharing + relevance: 5, + match: /\b(with|without|inherited)\s+sharing\b/, + scope: 'keyword' + }, + { + // class declaration + begin: [/[^\.]/, /\bclass\b/], + beginScope: { 2: 'keyword' }, + end: /(?=\{)/, + relevance: 0, + //scope: 'clause: class_declaration', + keywords: { type: TYPES, keyword: KEYWORD_LIST }, + contains: [ + { + match: [/(?<=\bclass)\s+/, APEX_IDENT_RE], + scope: { 2: 'title.class' } + }, + EXTEND_IMPLEMENT + ] + }, + { + // * Constructor DECLARATION + // Matches public/private/protected methodname parens + match: [ + /(public|private|protected)\s+/, + APEX_IDENT_RE, + SPACEPARENS_LOOKAHEAD + ], + scope: { + 1: 'keyword', + 2: 'title.function' + }, + starts: PARAMS_DECLARATION, + relevance: 0 + }, + { + // * method declaration + match: [ + /(?|\w)\s+/, + APEX_IDENT_RE, + SPACEPARENS_LOOKAHEAD + ], + scope: { 2: 'title.function' }, + relevance: 0, + starts: PARAMS_DECLARATION + }, + { + // enum declaration + begin: [/\benum\s+/, APEX_IDENT_RE, /\s*(?=\{)/], + beginScope: { 2: 'type' }, + end: /(?=[\}\n])/, + //scope: 'enum_declaration', + relevance: 0, + contains: [ + COMMENTS, + PUNCTUATION, + + { + match: regex.concat(APEX_IDENT_WORD_RE), + scope: 'variable.constant' + } + ] + } + ]; + + const METHOD_CALL = [ + { + match: regex.concat( + negLookaheadAny(...KEYWORD_LIST), + /\b/, + APEX_IDENT_RE, + SPACEPARENS_LOOKAHEAD + ), + scope: 'title.function.invoke method_call', + starts: PARAMS_CALL, + relevance: 0 + }, + { + match: [ + regex.concat('(?|>=|\bNOT\s+IN\b|=|!\s*=|\s:{1}|:{1}\s)/, - scope: 'literal' + begin: [/\bFROM/, SPACE, APEX_IDENT_WORD_RE], + beginScope: { + 1: 'keyword', + 3: 'type' + }, + //scope: 'clause: from_clause', + end: /(?=\]|\s|\))/, + contains: [ + { + match: [/(?<=\.)/, APEX_IDENT_WORD_RE], + scope: { 2: 'type' } + } + ] }, { - match: /(?<=\bFROM\b\s+)\w+/, - scope: 'type', - relevance: 0 + match: /:/, + scope: 'operator' }, { - match: [regex.concat(/\b/, APEX_ALPHA_UNDER), ':', /[0-9]+\b/], + match: + /(NEXT|LAST|THIS)_(90_DAY|DAY|FISCAL_QUARTER|FISCAL_YEAR|MONTH|QUARTER|WEEK|YEAR)S?\b/, + scope: 'keyword', + relevance: 10 + }, + { + match: [ + /(NEXT|LAST)_N_(DAY|FISCAL_QUARTER|FISCAL_YEAR|MONTH|QUARTER|WEEK|YEAR)S/, + /\s*:\s*/, + /\d+/ + ], scope: { 1: 'keyword', + 2: 'operator', 3: 'number' }, relevance: 10 }, - NUMBER, + { + match: [/(?<=:)/, /\s*/, APEX_IDENT_RE], + scope: { 3: 'variable' } + }, + NUMBERS, METHOD_CALL, - hljs.APOS_STRING_MODE + OPERATORS, + STRINGS, + PUNCTUATION ], illegal: '::' }; - const APEX_DECLARATIONS = [ - { - match: [/\b(?<=enum|\bnew)/, /\s+/, APEX_IDENT_RE, /\s*(?=[{()])/], - scope: { - 3: 'type' - }, - contains: [COMMENT_LINE, COMMENT_BLOCK] // , CUSTOM_OBJECT - }, - // Class Name - { - match: [/(?<=\bclass\b)/, /\s+/, APEX_IDENT_RE], - scope: { - //1: 'keyword', - 3: 'title.class' - } - }, - // Constructor - { - match: [ - /(?<=(public|private))/, - /\s+/, - APEX_IDENT_RE, - /(?=\s*\(.*\)\s*{)/ - ], // /(?=\s*\()/], - scope: { - 3: 'constructor' - } - }, - // Trigger - { - begin: [ - /(?<=\btrigger\b)/, - /\s+/, - APEX_IDENT_RE, - /\s+/, - 'on', - /\s+/, - APEX_IDENT_RE - ], - end: '{', - scope: { - //1: 'keyword', - 3: 'title.class', - 7: 'type' - }, - contains: [ - COMMENT_LINE, - COMMENT_BLOCK, - { - match: /(?:before|after)\s+(?:insert|update|delete|undelete)/, - scope: 'built_in', - relevance: 10 - } - ], - relevance: 10 + const FOR_LOOP = { + begin: [ + /\bfor\b\s*/, + /\(/, + APEX_IDENT_RE, + SPACE, + APEX_IDENT_RE, + /\s*/, + /:/ + ], + beginScope: { + 3: 'type', + 5: 'variable', + 7: 'operator' }, - // Method declarations - /* begin: [ - '(?:' + APEX_IDENT_RE + '\\s+)', - '(?:' + APEX_IDENT_RE + '\\s+)', - hljs.UNDERSCORE_IDENT_RE, - /(?=\s*\()/ - ], - scope: { 2: 'type', 3: 'title.function' }, */ - /* { - begin: [ - /((?:public|private|protected|global))?\s* /, - /((?:static|override))?\s* /, - /((?:static|override))?\s* /, - '(?:' + APEX_FULL_TYPE_RE + ')\\s+', - APEX_IDENT_RE, - /(?=\s* \()/ - ], - scope: { - 1: 'keyword', - 2: 'keyword', - 3: 'keyword', - //4: 'type', - 5: 'title.function' - }, - keywords: KEYWORDS, + end: /(?=\{)/, + //scope: 'clause: for_loop', - contains: [ - COMMENT_LINE, - COMMENT_BLOCK, - hljs.APOS_STRING_MODE, - COLLECTION_DECLARATION, - COLLECTION_MAP_VALUE - ], - relevance: 0, - illegal: [/\b_/, /_\b/] - }, */ - // extending - { - match: [/(?:extends)/, /\s+/, APEX_IDENT_RE], - scope: { - 3: 'title.class.inherited' + contains: [ + COMMENTS, + SOQL_QUERY, + METHOD_CALL, + { + match: regex.concat(APEX_IDENT_RE, /\b(?!\()/), + scope: 'variable' }, - illegal: [/\b_/, /_\b/] - } - ]; - - const MERGE_FIELDS = { - begin: ['{', /\$[a-zA-Z]+]/, '.', /\w+/], - end: '}', - scope: { - 2: 'built_in', - 4: 'property' - } - }; - - const FOR_LOOP = { - variants: [ { - //for (APTask__c apTask : myTasks - match: [ - /\bfor\b/, - /\s*\(/, - APEX_IDENT_RE, - /\s+/, - APEX_IDENT_RE, - /\s+:/, - /(?=\s*\[)/ - ], - scope: { - 1: 'keyword', - 3: 'type' - //5: 'variable' - } + match: regex.concat(APEX_IDENT_WORD_RE, SPACEPARENS_LOOKAHEAD), + scope: 'title.function.invoke for_loop' }, { - match: [ - /\bfor\b/, - /\s*\(/, - APEX_IDENT_RE, - /\s+/, - APEX_IDENT_RE, - /\s+:/, - /\s*/, - APEX_IDENT_RE - ], - scope: { - 1: 'keyword', - 3: 'type', - //5: 'variable', - 8: 'variable' - } - } - ], - contains: [COMMENT_LINE, COMMENT_BLOCK, SOQL_QUERY] + match: /\{/, + endsParent: true + }, + OPERATORS, + NUMBERS, + PUNCTUATION + ] }; - const ASSIGNMENTS = [ - { - match: [APEX_IDENT_RE, /\s+/, APEX_IDENT_RE, /\s+/, /=/], - scope: { - 1: 'type', - 3: 'variable', - 5: 'operator' - }, - relevance: 0 - }, + const DML_OPERATIONS = [ + /* + * DML types + * naked - delete as system [SELECT Id FROM Account]; + * naked - insert a; + */ { - match: [APEX_IDENT_RE, /\s+/, APEX_IDENT_RE, /\s+/, ';'], - scope: { - 1: 'type', - 3: 'variable' - }, - relevance: 0 - }, - { - match: [/\s+/, APEX_IDENT_RE, /\s+/, /=/], - scope: { - 2: 'variable', - 4: 'operator' - }, - relevance: 0 + match: [ + regex.concat(/\b/, regex.either(...DMLS)), + /\s+(?!\()/, + regex.optional(/as\s+(user|system)\b/) + ], + scope: { 3: 'keyword' } }, + /* + * DML types + * Database - Database.insert( ); + * + */ { - match: [/(?<=\w+\s+=\s+\()/, APEX_IDENT_RE, /(?=\))/], - scope: { - 2: 'type' + begin: [ + /\bDatabase\b/, + /\./, + regex.either(...DMLS), + SPACEPARENS_LOOKAHEAD + ], + beginScope: { + 1: 'built_in', + 2: 'punctuation', + 3: 'keyword invoke_database' }, - relevance: 0 + starts: PARAMS_CALL } ]; - const SALESFORCE_ID = { - match: /(?', + '<%%', + ':-', + /\bmergesort\(/, + /\bvar\s+env\b/, + /\bdef\b\s\W:/, + /"[^"]+"/ // Quote_string_mode // /@\w+\[\w+\]/ //moonscript ]; return { name: 'Apex', - aliases: ['apex', 'lightning'], + aliases: ['apex', 'lightning', 'soql'], case_insensitive: true, // language is case-insensitive disableAutodetect: false, ignoreIllegals: false, @@ -813,27 +1182,25 @@ export default function (hljs) { illegal: ILLEGALS, contains: [ ANNOTATIONS, - APEX_DECLARATIONS, - ASSIGNMENTS, - CLASS_SHARING, - COLLECTION_DECLARATION, - COLLECTION_MAP_VALUE, - COMMENT_BLOCK, - COMMENT_LINE, - COMPOUND_KEYWORDS, - //CUSTOM_OBJECT, + MISCELLANEOUS, + COLLECTIONS, + COMMENTS, + CUSTOM_METADATA, + DECLARATIONS, + DML_OPERATIONS, EXCEPTION, FOR_LOOP, - hljs.APOS_STRING_MODE, + STRINGS, + INSTANTIATE_TYPE, + LANGUAGE_VARS_RE, METHOD_CALL, - MERGE_FIELDS, NAMESPACES, - NUMBER, + NUMBERS, OPERATORS, + PUNCTUATION, SALESFORCE_ID, SOQL_QUERY, - //ANNOTATION_ATTRIBUTE_PARAMS, - IMPORTANT_WORDS + SWITCH_STATEMENT ] }; } diff --git a/src/styles/monokai-sublime-apex.css b/src/styles/monokai-sublime-apex.css index f5a9644..1793124 100644 --- a/src/styles/monokai-sublime-apex.css +++ b/src/styles/monokai-sublime-apex.css @@ -15,7 +15,7 @@ Monokai color scheme by Wimer Hazenberg 2006 https://monokai.nl/ */ .hljs { - background-color: #272822; + background-color: #272822 !important; background: #272822; color: #f8f8f2; } diff --git a/test/markup/apex/apexcode.expected.txt b/test/markup/apex/apexcode.expected.txt index 0959558..36ff63a 100644 --- a/test/markup/apex/apexcode.expected.txt +++ b/test/markup/apex/apexcode.expected.txt @@ -1,50 +1,51 @@ /** * @author John Smith */ -@IsTest(Seealldata=true) -public with sharing class L2Char implements Database.batchable { - public static final String ERROR = 0x0001; +@IsTest(Seealldata=true) +public with sharing class L2Char implements Database.batchable { + public static final String ERROR = 0x0001; - @InvocableApex(label='my invocable') - public void moveTo( - integer x, - integer y, - integer z - ) { + @InvocableMethod(label='my invocable') + public static void moveTo( + Integer x, + Integer y, + Integer z + ) { - Account a = new Account(); - a.Custom__c = 'stringvalue'; - insert a; - Boolean ai = (Boolean) false; - System.debug('Should not be called'); - if (1 > 5) { // wtf!? - Database.insert(myAccounts); - } - } -} + Account a = new Account(); + a.Custom__c = 'stringvalue'; + insert a; + Boolean ai = (Boolean) false; + System.debug('Should not be called'); + if (1 > 5 && !Test.isRunningTest()) { // wtf!? + Database.insert(myAccounts, false); + } + } +} @TestSetup -private static void makeData(Boolean a){ - Custom__c c = new Custom__c(); +private static void makeData(Boolean a){ + Custom__c c = new Custom__c(); - for(Account a : acctLis ){ - ConnectApi.insert a; - } -} + for(Account a : acctLis ){ + ConnectApi.insert a; + } +} -private testMethod void testme(){ - System.assert(true); -} +@isTest +private static void testme(){ + System.assert(true); +} @testVisible -private List<SelectOption> recordTypes { get; private set; } +private List<SelectOption> recordTypes { get; private set; } -for(Account a : [SELECT Id FROM Account WHERE LastModifiedDate = LAST_N_DAYS:3]){ - Assert.fail(); -} +for(Account a : [SELECT Id FROM Account WHERE LastModifiedDate = LAST_N_DAYS:3]){ + Assert.fail(); +} -trigger CTrig on Custom__c (before insert){ - System.debug('inserting a record'); - upsert myRecord__c; -} \ No newline at end of file +trigger CTrig on Custom__c (before insert){ + System.debug('inserting a record'); + upsert myRecord__c; +} \ No newline at end of file diff --git a/test/markup/apex/apexcode.txt b/test/markup/apex/apexcode.txt index b370c9b..da78027 100644 --- a/test/markup/apex/apexcode.txt +++ b/test/markup/apex/apexcode.txt @@ -5,11 +5,11 @@ public with sharing class L2Char implements Database.batchable { public static final String ERROR = 0x0001; - @InvocableApex(label='my invocable') - public void moveTo( - integer x, - integer y, - integer z + @InvocableMethod(label='my invocable') + public static void moveTo( + Integer x, + Integer y, + Integer z ) { @@ -18,8 +18,8 @@ public with sharing class L2Char implements Database.batchable { insert a; Boolean ai = (Boolean) false; System.debug('Should not be called'); - if (1 > 5) { // wtf!? - Database.insert(myAccounts); + if (1 > 5 && !Test.isRunningTest()) { // wtf!? + Database.insert(myAccounts, false); } } } @@ -33,7 +33,8 @@ private static void makeData(Boolean a){ } } -private testMethod void testme(){ +@isTest +private static void testme(){ System.assert(true); }