11 Replies Latest reply on Oct 1, 2014 11:39 PM by Trevorׅ

    How to keep track of all the classes/methods/properties created in a long script

    TᴀW Adobe Community Professional & MVP


      Hi,

       

      I'm curious to know what method people use to keep track of all the classes, methods, and properties you've created when writing a longer script.

       

      For quick scripts, this isn't a problem. But for long scripts it can get quite difficult to keep track of all the objects one has created, and all their methods and properties, and overloaded constructors, etc.

       

      ESTK is great, and it's the IDE I use for InDesign scripting, if only because of it's powerful debugging options.

       

      But it doesn't provide any way of keeping track of this stuff. No proper Intellisense as in Visual Studio.

       

      I'd be interested to hear how people solve this issue.

        • 1. Re: How to keep track of all the classes/methods/properties created in a long script
          Harbs. Level 6

          I tend to use very little OOP in ExtendScript for this reason.

           

          For the most part I stick to functional programming where each function is very specific and takes pretty much everything as variables. Sometimes I cut corners and use global variables or global objects with properties. But I do this sparingly. My function names are very specific about what they do, so just by reading the name, things are pretty obvious.

           

          I almost never write code in ESTK. My current app of choice is Sublime Text. It has decent code complete for existing variables and functions. It can be customized as well (if you have the patience to do so...) I do use ESTK to debug when necessary, but depending on the situation I sometimes skip that and just use alerts to track down issues.

           

          HTH,

          Harbs

          • 2. Re: How to keep track of all the classes/methods/properties created in a long script
            TᴀW Adobe Community Professional & MVP

            Hi Harbs,

             

            Long time no see!

             

            Until now I've also stuck to functional programming. But for a large,

            complex script I'm working on at the moment, I found that it was getting

            too messy. So I started creating separate "classes" (inasmuch as

            Javascript has such a concept), and saving each one as a separate file,

            and #including them. It's much, much easier to deal with this way. Also,

            everything is encapsulated within a single ScriptApp class, so the

            global namespace is staying very clean.

             

            However, now the challenge is to keep track of all these classes, and

            have some sort of system for efficient, consistent documentation. Hence

            I was wondering how people cope with this particular challenge.

             

            Wishing you a good concluding signature

             

            Ariel

            • 3. Re: How to keep track of all the classes/methods/properties created in a long script
              Marc Autret Level 4

              Hi Ariel,

               

              Not sure it is relevant to your question but I have an old snippet that collects and displays ExtendScript references using $.list(). This may help to track some object relationships.

               

              // WARNING: this is just a WIP -- Not tested in all platforms and versions
              
              $.scanRefs = function scanRefs(/*0|1*/showAll)
              {
                  var s = $.list(),
                      p = (!showAll) && s.indexOf('[toplevel]'),
                      a = ((!showAll) ? s.substr(0,10+p) : s).split(/[\r\n]+/),
                      n = a.length,
                      // --- Address:1     L:2  Rf:3   Pp:4  Type:5  Name:6
                      re = /^([0-9a-z]{8}) (.) +(\d+) +(\d+) (.{10}) (.{1,17})/,
                      reTrim = / +$/,
                      i, t, k, m,
                      refBy, type, name, tag, rest, rfCount, props, j,
                      o = {},
                      // ---
                      TYPES = {'Function':"FCT", 'Object':"OBJ", 'Array':"ARR", 'RegExp':"REG"};
              
                  for( i=2, refBy=0 ; i < n ; ++i )
                      {
                      s=a[i];
              
                      while( s && m=s.match(re) )
                          {
                          k = '&'+m[1].toUpperCase();
                          rfCount = parseInt(m[4],10);
                          rest = s.substr(m[0].length);
                          type = m[5].replace(reTrim,'');
                          name = m[6].replace(reTrim,'');
                          
                          if( 0x5B==rest.charCodeAt(0) )
                              {
                              p = rest.indexOf(']');
                              tag = rest.substr(0,1+p);
                              rest = rest.substr(1+p);
                              }
                          else
                              {
                              tag = '';
                              }
                          
                          if( 0x20==rest.charCodeAt(0) )
                              {
                              rest=rest.substr(1);
                              }
              
                          if( p=!(rest.indexOf("referenced by:")) )
                              {
                              rest = rest.substr(14);
                              }
              
                          o[k] || (o[k] = {
                              locked:        +('L'==m[2]),
                              rfCount:    parseInt(m[3],10),
                              ppCount:    rfCount,
                              type:        TYPES[type]||type,
                              name:        name,
                              tag:        tag,
                              from:        [],
                              order:        -1,
                              });
              
                          if( 0 < refBy )
                              {
                              if( p || !rest ){ throw "Unable to parse references." }
                              props = rest.split(' ');
                              refBy -= (j=props.length);
                              while( j-- ) t.from.push([k,props[j]]);
                              (props.length=0)||(props=null);
                              rest = '';
                              }
                          else
                              {
                              refBy = rfCount;
                              if( p != !!refBy )
                                  {
                                  if( p ){ throw "Unable to parse references."; }
                                  refBy = 0;
                                  }
                              (t = o[k]).order = n - i;
                              }
              
                          (m.length=0)||(m=null);
                          s = rest;
                          }
                      }
              
                  a.length=i=0;
                  for( k in o )
                      {
                      if( !o.hasOwnProperty(k) ) continue;
                      a[i++] = k;
                      }
                  a.sort( function(x,y){return o[x].order-o[y].order;} );
                  //a.sort( function(x,y){return parseInt(x.substr(1),16)-parseInt(y.substr(1),16);} );
              
                  var u,
                      pngLock = "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\x0E\x00\x00\x00\x0E\b\x06\x00\x00\x00\x1FH-\xD1\x00\x00\x00\tpHYs\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01VIDAT(\xCF\xA5\x91\xB1j\xC2P\x14\x86\x93\xD6\x94\x98\xA4\xB5\xA5\x85\x0E-R\xAF\xA5\xB8\xF4\x1D\xAA\xEF\x10_B\x9C\xDD\x0B]\xA4o`C\xE9$B\x1C\xCD\x10\x10C6\x05q\td\xA9%\x83d2\x83O\xF0\xF7\xDCp#i\xB5\x1D\xDA\xC0\xC7\xB97\xE7|\xF7\xDC\xCB\x91\x00H\x7FA\xFA\xB7\x98\xFF\xAA\xD5\xEA\x0B\x855\xC1\x13k\xDA\xBF\xEA\x9A\xA6\x9C\x18\xC6\xC1\xB6\xE8\xBBHE\x16\x85w\xC6\xD8\xE3\x91\xA2\xDCQ|\xA2\xFD\x07\xC57\xADXT\x8B\xAAz\xB8#\x8A\x13\xD7\xBC\xD8\xD0\xB4kC\xD7\x19q\xCB*\x95g\xFA\x9FP\xD7\x0B\x8A\n!oE.\xB5Z-\xEC\xA3\xD9l\xA2\xFEP\x07\x1D\xC8;\x18D!/\x16x\x91\xEF\xFBX.\x97\xD8l6H\x92$]O\xA7S\x8CF#\x887\x9F\x13j^T\xB9\xD8\xE9t0\x99L\x10\xC71V\xAB\x15\x82 \xC0\xD0\x1E\xA2\xDDng\xE2\x15q\x9C\x175.:\x8E\x83\xC5b\x81(\x8A \xCB2\xE6\xF39\\\u00D7E\xBF\xDF\xCF\xC4\x1B\xE24/\x1A\\\u00ECv\xBB\xF0<\x0Fa\x18\xA2\xD1h`<\x1E\xC3\xB2,\x98\xA6\x99\x89\x8C8\xDB\x11\x07\x83AzU\xDEu6\x9B\xA5\xA2m\xDB\xE8\xF5z?\x8B4\xC3,\xF9\x1B_E1\x9F\x12Q&j\xC4\xFD\x1Ej\"_\xCA\x8B\x051\xA3K\x91d{(\x8B\xBC\xFE\t\xC1TI!\xE3L\x03\x7F\x00\x00\x00\x00IEND\xAEB`\x82",
                      pngNop = "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\x0E\x00\x00\x00\x0E\b\x03\x00\x00\x00(\x96\xDD\xE3\x00\x00\x00\x03PLTE\x00\x00\x00\xA7z=\xDA\x00\x00\x00\x01tRNS\x00@\xE6\xD8f\x00\x00\x00\x15IDATx\xDA\xDD\xC1\x01\x01\x00\x00\x00\x80\x90\xFE\xAF\xF6#\xDA\x01\x00\xD2\x00\x01\xCC \x10\x14\x00\x00\x00\x00IEND\xAEB`\x82",
                      w = new Window('dialog', " ExtendScript Memory"),
                      p1 = w.add('panel', u, "References"),
                      lRefs = p1.add('listbox', u, "",
                          {
                          numberOfColumns: 4,
                          showHeaders: true,
                          columnTitles: ["Address", "Type", "Name", "Refs"],
                          columnWidths: [90,60,120,36],
                          }),
                      g = w.add('group'),
                      pFrom = g.add('panel', u, "From"),
                      lFrom = pFrom.add('listbox', u, "",
                          {
                          numberOfColumns: 4,
                          showHeaders: true,
                          columnTitles: ["Address", "Type", "Name", "Property"],
                          columnWidths: [90,60,120, 120],
                          }),
                      pTo = g.add('panel', u, "To"),
                      lTo = pTo.add('listbox', u, "",
                          {
                          numberOfColumns: 4,
                          showHeaders: true,
                          columnTitles: ["Property", "Address", "Type", "Name"],
                          columnWidths: [120,90,60, 120],
                          });
                  
                  g.orientation = 'column';
                  w.orientation = 'row';
                  w.alignChildren = ['left','top'];
              
                  lRefs.maximumSize = lRefs.minimumSize = [330,450];
                  lFrom.maximumSize = lFrom.minimumSize = [420,120];
                  lTo.maximumSize = lTo.minimumSize = [420,220];
                  
                  lRefs.onChange = function()
                  {
                      lFrom.removeAll();
                      lTo.removeAll();
                      lFrom.parent.text = "From";
                      lTo.parent.text = "To";
                      if( !this.selection ) return;
              
                      var key = '&'+this.selection.text,
                          t = o[key],
                          from = t.from,
                          i = from.length,
                          k;
              
                      lFrom.parent.text = "["+key.substr(1)+"] is reachable from " + t.ppCount + (1<t.ppCount ? " properties" : " property");
                      
                      if( t.ppCount && !i )
                          {
                          with( lFrom.add('item', '--------') )
                              {
                              image = pngNop;
                              subItems[0].text = '';
                              subItems[1].text = '<UNKNOWN REFERRER>';
                              subItems[2].text = '';
                              }
                          }
              
                      while( i-- )
                          {
                          k = from[i][0];
                          t = o[k];
                          with( lFrom.add('item', k.substr(1)) )
                              {
                              image = t.locked ? pngLock : pngNop;
                              subItems[0].text = t.type;
                              subItems[1].text = t.name + ' ' + t.tag;
                              subItems[2].text = from[i][1];
                              }
                          }
              
                      for( k in o )
                          {
                          if( !o.hasOwnProperty(k) ) continue;
                          t = o[k];
                          from = o[k].from;
                          i = from.length;
                          while( i-- )
                              {
                              if( from[i][0]!=key ) continue;
              
                              with( lTo.add('item', from[i][1]) )
                                  {
                                  image = pngNop;
                                  subItems[0].text = k.substr(1);
                                  subItems[1].text = t.type;
                                  subItems[2].text = t.name + ' ' + t.tag;
                                  }
                              }
                          }
              
                      lTo.parent.text = "["+key.substr(1)+"]'s properties had access to " + lTo.items.length + " addr.";
              
                      from = t = null;
                  };
              
                  for( i=0, n=a.length ; i < n ; ++i )
                      {
                      t = o[k=a[i]];
                      with( lRefs.add('item', k.substr(1)) )
                          {
                          image = t.locked ? pngLock : pngNop;
                          subItems[0].text = t.type;
                          subItems[1].text = t.name + ' ' + t.tag;
                          subItems[2].text = t.ppCount + '/' + t.rfCount;
                          }
                      }
              
                  w.show ();
              };
              
              
              // -------------------
              // TEST
              // -------------------
              
              var t;
              var f = function MyFunc()
              {
                  (function MyInnerFunc(){})();
              };
              
              
              $.scanRefs(1);
              
              

               

              @+

              Marc

              • 4. Re: How to keep track of all the classes/methods/properties created in a long script
                Trevorׅ Adobe Community Professional

                Hi All,

                 

                I also use Sublime Text which has many advantages over the ESTK.  It takes a little learning to get the relevant plug-ins but I find that scripting goes much quicker with it.

                I have builds for Mac (by Basil) and for Windows (by me) that allow one to execute the scripts for Sublime Text, although significantly one can't use $.writeln when using the builds but there are workarounds for that.

                 

                I made a script that retrieves the entire Indesign methods and properties collection including the enumerations so one doesn't have to remember all the thousands of spellings and enums and puts it into an auto-complete file.  The auto-complete uses fuzzy logic and is a huge time saver.

                untitled • - Sublime Text (UNREGISTERED)_2014-09-29_09-51-03.png

                untitled • - Sublime Text (UNREGISTERED)_2014-09-29_09-49-06.png

                The auto-complete even uses logic for the ordering and auto selection of the suggestion base one previous usage.

                 

                Send me a mail if you want a copy of the auto-complete file.

                 

                The much clearer presentation which is very significant, you can pick from umpteen themes (You need to do a little customization for jsx files to format) which are either specific to particular languages or not.

                 

                You can safely close the program without being asked to save all the unsaved files (they will open up next time you open the program) if the system crashes when you reopen ST the same windows and tabs will reopen without having to go to recent files and restoring all the #BK34634645745467# files.

                 

                The file cloning and window arrangement is much more effective than on the ESTK especially with the excellent origami plugin.

                 

                Often I edit the scripts in ST and have the same script open in the ESTK in a way that they bidirectionally sync in real time and then run the script from the ESTK so I get the best of both worlds.  In fact I ofter do this on a Sugar Sync backed up file and have the script open both on Mac and Windows which will all sync together.

                 

                Back to your original question, if you need to maybe you could have the files open on visual-studio synced with sublime text or the ESTK and then maybe you could use the Intellisense feature in VS. I'm not too sure about that but you can give it a go.

                 

                Gmar Hasima Tova

                 

                Trevor

                 

                P.s. Marc any idea what this is or how to investigate it's properties?!

                Adobe InDesign CS5_2014-09-29_08-39-43.png

                Also where did you see about $.list I didn't see that documented anywhere? Are the any other undocumented $ functions?

                • 5. Re: How to keep track of all the classes/methods/properties created in a long script
                  Marc Autret Level 4

                  @ Trevor

                   

                  P.s. Marc any idea what this is or how to investigate it's properties?!

                  Adobe InDesign CS5_2014-09-29_08-39-43.png

                  Also where did you see about $.list I didn't see that documented anywhere? Are the any other undocumented $ functions?

                   

                  According to your own screenshot, mySecretTest is a property that refers to an anonymous function which you can access from an object located at [27C7A558] in your ExtendScript memory. I guess that this object is $.global.indesign. It contains a lot of preloaded properties and methods. $.global.indesign.mySecretTest.toSource() reveals that this is an empty function (no effect).

                   

                  Tip: use $.scanRefs(0) to ignore this huge set of preloaded objects that mainly come from ESTK's workspace.

                   

                  > Also where did you see about $.list?

                   

                  My own investigations on hidden stuff ;-)

                  Nice ones in that scope are $.list(), $.listLO(), and $.summary().

                  Il also noticed that $.objects (hidden numeric property) returns the count of created objects.

                   

                  @+

                  Marc

                  • 6. Re: Re: How to keep track of all the classes/methods/properties created in a long script
                    Harbs. Level 6

                    Trevorׅ wrote:


                    Send me a mail if you want a copy of the auto-complete file.

                     

                    Yes. Please!

                    Often I edit the scripts in ST and have the same script open in the ESTK in a way that they bidirectionally sync in real time and then run the script from the ESTK so I get the best of both worlds.  In fact I ofter do this on a Sugar Sync backed up file and have the script open both on Mac and Windows which will all sync together.

                     

                    I do the same. I have a alias to a Dropbox folder in my scripts folder where I store all my scripts. That way, all scripts are available on all versions of InDesign on all machines. The same file can be open in ESTK and another text editor. ESTK usually automatically updates the file when it's edited externally.

                     

                    Harbs

                    • 7. Re: Re: How to keep track of all the classes/methods/properties created in a long script
                      Trevorׅ Adobe Community Professional

                      Hi Marc,

                       

                      Thanks for the feed back, so I guess one can have a text file of an English dictionary and have a script run through the word list and catch all the defineds and hope the machine doesn't blow it's head ;-)

                       

                      $["summary"] >= summary()

                      $["cat"] >= undefined // not meow

                       

                      I knew about the summary one and can't understand why it's not documented. Dirk's got a nice proto on it that you probably knew about http://www.ixta.com/scripts/utilities/summaryDifference.html

                       

                      Question: What can one do with the knowledge of the memory addresses?

                       

                      Trevor

                      • 8. Re: How to keep track of all the classes/methods/properties created in a long script
                        antosuv Level 1

                        JsDoc can generate the API documentation for the commented JavaScript and can be used for ExtendScript.

                        • 9. Re: How to keep track of all the classes/methods/properties created in a long script
                          TᴀW Adobe Community Professional & MVP

                          antosuv,

                           

                          JsDoc looks very interesting -- this is what I was looking for I think.

                           

                          Thank you!

                          • 10. Re: How to keep track of all the classes/methods/properties created in a long script
                            TᴀW Adobe Community Professional & MVP

                            Hi Marc,

                             

                            Thanks for this weird and wonderful script. I'm also not sure if it's relevant   I'll let you know when I figure out what it does.

                             

                            Ariel


                            • 11. Re: How to keep track of all the classes/methods/properties created in a long script
                              Trevorׅ Adobe Community Professional

                              Hi Ariel

                               

                              The JsDoc looks quite interesting but if you were to use sublime text you might find it more simple to make a comment before each set of class or var declarations something like

                              // Class Declare blah blah blah

                              // list the classes here before you declare them.

                               

                              Then you can do a simple search of the folder contains all the sub-folders and documents of your project for the word Declare (or whatever you chose).

                              The results tab (which is hyper-linked) will not close unless you close it and you can have as many of them as you like.

                               

                              This will only work if the include libraries are contained within this folder set, but the implementation is very simple and the searches seem to be pretty much instant even on large folders.

                               

                              In the screen shot I just did a search for the word doc but you can see the general idea.

                               

                              Trevors Mini - TightVNC Viewer_2014-10-02_09-19-48.png

                               

                              Regards

                               

                              Trevor