Search code examples
google-apps-scriptgoogle-apps-script-editor

Getting a list of functions within your GAS project


I want to see if there is a way to obtain a list of all the functions I have in a Google Apps Script project. I've seen multiple threads on getting a list of all of your Google Apps Script projects but none as of yet for listing all of the functions in each project. Does anyone know if this is possible? I've looked through the Google Apps Script Reference Overview but I wasn't able to find anything that stood out to me (I, of course, could've missed it). If anyone has any suggestions, please let me know!.

The best example I can provide is:

I have a Google Spreadsheet file. Attached to that Google Spreadsheet is a GAS project (accessed through the Google Sheet menu "Tools -> Script Editor") that has a couple of different functions used to grab values from the sheet, do some calculations and post the results to a different sheet.

What I am trying to accomplish: Run some sort of function that can provide me a list of all of the functions I have in the GAS project (preferably as string values). Example would be:

["runMyCalculations","myOnEdit","sortClosedFiles","formatSheets"]

All of these are functions that can only be run if I open up the Script Editor and select it in the drop-down menu and click the "Run" button.

What I want to be able to do is create a dynamic list of all the functions I have so I can pass them into an "on open" triggered function that creates a custom menu in the sheet, listing out all of the functions I have. I want this so I can simply make changes to my sheet, go to the drop-down menu and run the function I need to run, rather than having to open up the Script Editor.


Solution

  • You can use the Apps Script API to get all the content out of an Apps Script file. The following code has the option of passing in a file name to get. You must supply the Apps Script file ID. Passing in a gs file name is optional. Provided are 3 functions. The function that does all the work, a function to call that function with the parameters for testing, and a logging function. An OAuth library is not needed because the token is acquired from the ScriptApp service.

    NOTE: You will need to enable the Apps Script API, and approve permission to your Drive in order for this code to work. Make sure to check the return from the UrlFetchApp.fetch() call the first time that you run this code for an error message. It may have a link that you need to use to enable the Apps Script API.

    function getFuncNames(po) {
      var allFiles,dataContentAsString,downloadUrl,fileContents,fileData,i,options,
          theAccessTkn,thisFileName;
      var ndxOfFunction=0,counter=0, ndxOfEnd=0, functionName="", allFncNames=[],
          hasSpaces = 0;
      var innerObj, thisFile, fileType = "", thisGS_Content,howManyFiles, allGsContent="";
    
      /*
        Get all script function names.  If no gs file name is provided, the code
        gets all the function names.
      */
    
      /*
        po.fileID - required - The Apps Script file ID
        po.gsFileName - optional - the gs code file name to get - gets just one 
           file instead of all files
      */
    
      //ll('po',po);
    
      if (!po.fileID) {
        return false;
      }
    
      theAccessTkn = ScriptApp.getOAuthToken();//Get an access token for OAuth
    
      downloadUrl = "https://script.google.com/feeds/download/export?id=" +
          po.fileID + "&format=json";//create url
    
      options = {
        "kind": "drive#file",
        "id": po.fileID,
        "downloadUrl": downloadUrl,
        "headers": {
           'Authorization': 'Bearer ' +  theAccessTkn,
         },
        "contentType": "application/vnd.google-apps.script+json",
        "method" : "GET"
      };
    
      fileData = UrlFetchApp.fetch(downloadUrl, options);//Get all the content from the Apps Script file
      //ll('fileData',fileData)
    
      dataContentAsString = fileData.getContentText();
    
      fileContents = JSON.parse(dataContentAsString);//Parse string into object
    
      allFiles = fileContents.files;//All the files in the Apps Script project
    
      howManyFiles = allFiles.length;
    
      for (i=0;i<howManyFiles;i++) {
        thisFile = allFiles[i];//Get one inner element that represents one file
        if (!thisFile) {continue;}
    
        fileType = thisFile.type;
        if (fileType !== "server_js") {continue;}//This is not a gs file - its HTML or json
    
        thisFileName = thisFile.name;
        //ll('typeof thisFileName',typeof thisFileName)
        //ll('thisFileName',thisFileName)
        //ll('equal',po.gsFileName !== thisFile.name)
    
        if (po.gsFileName) {//Is there a setting for the file name to restrict the search to
          if (po.gsFileName !== thisFile.name) {//The name to search for is not this file name
            continue;
          }
        }
    
        thisGS_Content = thisFile.source;//source is the key name for the file content
        allGsContent = allGsContent + thisGS_Content;
      }
    
      //ll('allGsContent',allGsContent)
    
      while (ndxOfFunction !== -1 || counter < 1000) {
        ndxOfFunction = allGsContent.indexOf("function ");
    
        //ll('ndxOfFunction',ndxOfFunction)
        if (ndxOfFunction === -1) {break};
    
        allGsContent = allGsContent.slice(ndxOfFunction+9);//Remove everything in front of 'function' first
    
        ndxOfEnd = allGsContent.indexOf("(");
        functionName = allGsContent.slice(0,ndxOfEnd);
        allGsContent = allGsContent.slice(ndxOfEnd+2);//Remove the     
        hasSpaces = functionName.indexOf(" ");
    
        if (hasSpaces !== -1) {continue;}
    
        if (functionName.length < 150) {
          allFncNames.push(functionName);
        }//Any string over 150 long is probably not a function name
    
        counter ++;
      };
    
      //ll('allFncNames',allFncNames)
      return allFncNames;
    };
    
    function runOtherFnk() {
      getFuncNames({fileID:"Your File ID here",gsFileName:"Code"});
    }
    
    function ll(a,b) {
      //Logger.log(typeof a)
    
      if (typeof b === 'object') {
        b = JSON.stringify(b);
      }
    
      Logger.log(a + ":" + b)
    }
    

    The following code extracts file names from the this object:

    function getAllFnks() {
      var allFnks,fnkStr,k;
    
      allFnks = [];
    
      for (k in this) {
        //Logger.log(k)
        //Logger.log(typeof k)
        //Logger.log(this[k])
        //Logger.log(typeof this[k])
    
        fnkStr = this[k];
    
        if (fnkStr) {
          fnkStr = fnkStr.toString();
          //Logger.log(typeof fnkStr)
        } else {
          continue;
        }
    
        //Logger.log(fnkStr.toString().indexOf('function'))
        if (fnkStr.indexOf('function') === 1) {
          allFnks.push(k);
        }
      }
    
      Logger.log(allFnks)
      Logger.log('Number of functions: ' + allFnks.length)
    }