@mcpher/gas-fakes 1.0.20 → 1.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +70 -18
  2. package/gprompts/gas-inventory.js +96 -0
  3. package/gprompts/gas-inventory.json +116 -20
  4. package/gprompts/inventory-list.json +1 -1
  5. package/gprompts/package-lock.json +234 -0
  6. package/gprompts/package.json +1 -0
  7. package/package.json +5 -2
  8. package/src/index.js +2 -1
  9. package/src/services/advdocs/app.js +4 -23
  10. package/src/services/advdrive/app.js +6 -28
  11. package/src/services/advforms/app.js +6 -25
  12. package/src/services/advgmail/app.js +6 -26
  13. package/src/services/advsheets/app.js +6 -26
  14. package/src/services/advslides/app.js +6 -28
  15. package/src/services/common/lazyloader.js +22 -0
  16. package/src/services/documentapp/app.js +8 -42
  17. package/src/services/documentapp/appenderhelpers.js +2 -2
  18. package/src/services/documentapp/fakeparagraph.js +1 -1
  19. package/src/services/driveapp/app.js +6 -28
  20. package/src/services/formapp/app.js +5 -40
  21. package/src/services/gmailapp/app.js +7 -40
  22. package/src/services/logger/app.js +8 -0
  23. package/src/services/logger/fakelogger.js +206 -0
  24. package/src/services/scriptapp/app.js +7 -1
  25. package/src/services/scriptapp/behavior.js +1 -1
  26. package/src/services/session/app.js +10 -0
  27. package/src/services/slidesapp/app.js +5 -40
  28. package/src/services/spreadsheetapp/app.js +6 -50
  29. package/src/services/spreadsheetapp/fakeovergridimage.js +47 -0
  30. package/src/services/spreadsheetapp/fakesheet.js +31 -4
  31. package/src/services/stores/app.js +0 -1
  32. package/src/services/urlfetchapp/app.js +0 -1
  33. package/src/services/utilities/app.js +6 -20
  34. package/src/support/proxies.js +16 -0
  35. package/src/support/sxxlsx.js +41 -0
  36. package/src/support/syncit.js +179 -141
  37. package/src/support/workersync/sxfunctions.js +11 -10
  38. package/gprompts/gas-inventory.mjs +0 -80
  39. package/src/services/base/app.js +0 -33
  40. /package/src/services/{base → session}/fakesession.js +0 -0
package/README.md CHANGED
@@ -37,23 +37,15 @@ In order to avoid a bunch of Node specific code and credentials, yet still handl
37
37
 
38
38
  At the very least you need to add the gcp project id and optionally the id of some file you have access to - this'll be used to check that you have set up ADC properly.
39
39
 
40
- #### Option 1 - automated setup
41
-
42
- In the shells folder run
43
- ```sh
44
- bash setup.sh
45
- ```
46
- This will prompt you for project id and a file id to test with. It will also ask it you want to set up all the parameters needed for testing. If you answer yes, this will set up other things from the .env-template you can ignore unless you're planning to run the test suite. More information on that is in [collaborators info](collaborators.md)
47
-
48
- Running set up will enhance your .env file and auth you in ADC with the required scopes
49
-
50
- #### Option 2 - manual setup
40
+ #### Your .env file
51
41
 
52
42
  You can setup the .env file your self using the .env.template as a guide.
53
43
 
54
44
  ```
55
45
  # must set these
56
46
  GCP_PROJECT_ID="add your gcp project id here"
47
+
48
+ # optional reference if you want to run a test after setting up
57
49
  DRIVE_TEST_FILE_ID="add the id of some test file you have access to here"
58
50
 
59
51
  # we'll use the default config for application default credentials
@@ -62,12 +54,13 @@ AC=default
62
54
  # these are the scopes set by default - take some of these out if you want to minimize access
63
55
  DEFAULT_SCOPES="https://www.googleapis.com/auth/userinfo.email,openid,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/sqlservice.login"
64
56
  EXTRA_SCOPES=",https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets"
57
+
58
+ # optional logging destination
59
+ # can be CONSOLE (default), CLOUD, BOTH, NONE
60
+ LOG_DESTINATION="BOTH"
65
61
 
66
62
  ```
67
63
 
68
- - goto ./shells and execute sp.sh
69
-
70
-
71
64
  #### Manifest file
72
65
 
73
66
  If you have an associated apps script project, you'll probably be using clasp to sync with the apps script IDE, and you'll have an appsscript.json available in your project folder
@@ -104,6 +97,66 @@ Optionally, gasfakes.json holds various location and behavior parameters to info
104
97
  | properties | string | /tmp/gas-fakes/properties | gas-fakes uses a local file to emulate apps script's PropertiesService. This is where it should put the files. You may want to put it somewhere other than /tmp to avoid accidental deletion, but don't put it in a place that'll get commited to public git repo |
105
98
  | scriptId | string | from clasp, or some random value | If you have a clasp file, it'll pick up the scriptId from there. If not you can enter your scriptId manually, or just leave it to create a fake one. It's use for the moment is to return something useful from ScriptApp.getScriptId() and to partition the cache and properties stores |
106
99
 
100
+
101
+
102
+ ### Cloud Logging Integration
103
+
104
+ `gas-fakes` emulates the native Google Apps Script `Logger.log()` integration with Google Cloud Logging, allowing you to send structured logs from your local Node.js environment directly to your Google Cloud project. Note that console.log is the normal Node console and writes to the local console only. All messages from gas-fakes api still go to the console, so the Logger.log is for your own user messages as required.
105
+
106
+ #### Initial Configuration
107
+
108
+ The initial logging behavior is controlled by the `LOG_DESTINATION` environment variable in your `.env` file.
109
+
110
+ | `LOG_DESTINATION` | Behavior |
111
+ |---|---|
112
+ | `CONSOLE` (Default) | Logs structured JSON to the console (`stdout`). This is the default behavior if the variable is not set. |
113
+ | `CLOUD` | Sends logs directly to Google Cloud Logging. Nothing is written to the console. |
114
+ | `BOTH` | Sends logs to both Google Cloud Logging and the console. |
115
+ | `NONE` | Disables all output from `Logger.log()`. |
116
+
117
+ When logging to the cloud, entries are sent to the `gas-fakes/console_logs` log name and include the following labels for easy filtering in the Log Explorer:
118
+ - `gas-fakes-scriptId`
119
+ - `gas-fakes-userId`
120
+
121
+ #### Dynamic Control
122
+
123
+ You can change the logging destination at any time during runtime by setting the `Logger.__logDestination` property. This is especially useful for testing or for applications that need to change their logging behavior dynamically.
124
+
125
+ The method accepts one of the following string values: `'CONSOLE'`, `'CLOUD'`, `'BOTH'`, or `'NONE'`.
126
+
127
+ #### Example Usage
128
+
129
+ To set the initial destination, modify your `.env` file:
130
+ ```
131
+ LOG_DESTINATION="BOTH"
132
+ ```
133
+
134
+ To change the destination during runtime in your script:
135
+ ```javascript
136
+ // Initially logs to BOTH (from .env)
137
+ Logger.log('This goes to console and cloud');
138
+
139
+ // Switch to only logging to the console
140
+ Logger.__logDestination='CONSOLE';
141
+ Logger.log('This now only goes to the console');
142
+
143
+ // Disable logging completely
144
+ Logger.__logDestination='NONE';
145
+ Logger.log('This goes nowhere');
146
+ ```
147
+
148
+ #### Link to Cloud log for this run
149
+
150
+ If you have used Logging to cloud, you can get a link to the log data like this.
151
+
152
+ ```javascript
153
+ console.log ('....example cloud log link for this session',Logger.__cloudLogLink)
154
+ ````
155
+
156
+ It contains a cloud logging query that will display any logging done in this session - the filter is based on the scriptId (from gasfakes.json), the projectId and userId (from Auth), as well as the start and end time of the session.
157
+
158
+
159
+
107
160
  ### Pushing files to GAS
108
161
 
109
162
  There are a couple of syntactical differences between Node and Apps Script. Not in the body of the code but in how the IDE executes. The 2 main ones are
@@ -113,16 +166,15 @@ There are a couple of syntactical differences between Node and Apps Script. Not
113
166
  // this required on Node but not on Apps Script
114
167
  if (ScriptApp.isFake) testFakes()
115
168
  ````
116
- For inspiration on pushing modified files to the IDE, see the [bash script](https://github.com/brucemcpherson/gas-fakes/blob/main/togas.bash) I use for the test suite.
117
-
118
-
169
+ For inspiration on pushing modified files to the IDE, see the togas.sh bash script I use for the test suite.
119
170
 
120
171
  ## Help
121
172
 
122
- As I mentioned earlier, to take this further, I'm going to need a lot of help to extend the methods and services supported - so if you feel this would be useful to you, and would like to collaborate, please ping me on [bruce@mcpher.com](mailto:bruce@mcpher.com) and we'll talk.
173
+ As I mentioned earlier, to take this further, I'm going to need a lot of help to extend the methods and services supported - so if you feel this would be useful to you, and would like to collaborate, please ping me on bruce@mcpher.com and we'll talk.
123
174
 
124
175
  ## Translations and writeups
125
176
 
177
+
126
178
  - [initial idea and thoughts](https://ramblings.mcpher.com/a-proof-of-concept-implementation-of-apps-script-environment-on-node/)
127
179
  - [Inside the volatile world of a Google Document](https://ramblings.mcpher.com/inside-the-volatile-world-of-a-google-document/
128
180
  - [Apps Script Services on Node – using apps script libraries](https://ramblings.mcpher.com/apps-script-services-on-node-using-apps-script-libraries/)
@@ -0,0 +1,96 @@
1
+ import got from 'got';
2
+ import * as cheerio from 'cheerio';
3
+ import fs from 'fs/promises';
4
+ import { URL } from 'url';
5
+
6
+ const baseUrl = "https://developers.google.com/apps-script/reference/script/"
7
+ const outputFile = './gas-inventory.json';
8
+
9
+ const visited = new Map();
10
+ const queue = [baseUrl]
11
+
12
+ // the urls are kebab cased
13
+ const kebabCamel = (s) => {
14
+ return s.replace(/([-][a-z])/ig, ($1) => {
15
+ return $1.toUpperCase()
16
+ .replace('-', '')
17
+ });
18
+ };
19
+
20
+ function debugPageStructure($) {
21
+ console.log('=== PAGE STRUCTURE DEBUG ===');
22
+
23
+ // Check if main elements exist
24
+ console.log('#main-content exists:', $('#main-content').length > 0);
25
+ console.log('devsite-content exists:', $('devsite-content').length > 0);
26
+ console.log('article exists:', $('article').length > 0);
27
+ console.log('h1 elements:', $('h1').length);
28
+
29
+ // Show all h1 texts
30
+ $('h1').each((i, el) => {
31
+ console.log(`H1[${i}]:`, $(el).text().trim());
32
+ });
33
+
34
+ // Show structure of main-content
35
+ const mainContent = $('#main-content');
36
+ if (mainContent.length > 0) {
37
+ console.log('Main-content children:', mainContent.children().length);
38
+ mainContent.children().each((i, el) => {
39
+ console.log(`Child ${i}:`, el.tagName, $(el).attr('class') || $(el).attr('id'));
40
+ });
41
+ }
42
+ }
43
+
44
+
45
+ const getNextCheer = async (u) => {
46
+ console.log(`Scraping ${u}`);
47
+ const response = await got(u);
48
+ return cheerio.load(response.body);
49
+ }
50
+
51
+ const getHrefs = ($) => {
52
+ return $('a').map((i, el) => {
53
+ const r = $(el).attr('href');
54
+ if (r) {
55
+ const absolute = new URL(r, baseUrl).href;
56
+ // skip references to elsewhere and blank anchors
57
+ if (absolute.startsWith(baseUrl) && !absolute.endsWith('#')) return absolute;
58
+ }
59
+ }).get();
60
+ }
61
+
62
+
63
+ const s2 = async () => {
64
+ const umap = new Map();
65
+ const uset = new Set()
66
+ while (queue.length) {
67
+
68
+ const url = queue.shift();
69
+ console.log('working on url', url)
70
+ const $ = await getNextCheer(url);
71
+ debugPageStructure($);
72
+
73
+ // get all the hrefs
74
+ getHrefs($).forEach(f => {
75
+ // so a url could have an anchor for a method so we need to strip that out
76
+ const u = new URL(f);
77
+ const method = u.hash.substring(1);
78
+ const classUrl = u.origin + '/' + u.pathname
79
+ const methodUrl = u.href
80
+ if (!umap.has(classUrl)) {
81
+ umap.set(classUrl, {
82
+ parents: new Map(),
83
+ classUrl,
84
+ methods: new Map()
85
+ })
86
+ console.log ('pushing', classUrl)
87
+ queue.push (classUrl)
88
+ }
89
+ const ob = umap.get(classUrl)
90
+ ob.methods.set(method, { method, methodUrl })
91
+ ob.parents.set(url, { url })
92
+ console.log('adding', f)
93
+ })
94
+ }
95
+ }
96
+ s2().catch(console.error)
@@ -1,77 +1,173 @@
1
1
  {
2
- "Base Service": {
3
- "name": "Base Service",
4
- "link": "https://developers.google.com/apps-script/reference/base",
2
+ "Forms Service": {
3
+ "name": "Forms Service",
4
+ "link": "https://developers.google.com/apps-script/reference/forms",
5
5
  "classes": {
6
6
  "Classes": {
7
7
  "methods": {},
8
8
  "properties": {}
9
9
  },
10
- "Blob": {
10
+ "Alignment": {
11
11
  "methods": {},
12
12
  "properties": {}
13
13
  },
14
- "BlobSource": {
14
+ "CheckboxGridItem": {
15
15
  "methods": {},
16
16
  "properties": {}
17
17
  },
18
- "Browser": {
18
+ "CheckboxGridValidation": {
19
19
  "methods": {},
20
20
  "properties": {}
21
21
  },
22
- "Button": {
22
+ "CheckboxGridValidationBuilder": {
23
23
  "methods": {},
24
24
  "properties": {}
25
25
  },
26
- "ButtonSet": {
26
+ "CheckboxItem": {
27
27
  "methods": {},
28
28
  "properties": {}
29
29
  },
30
- "ColorType": {
30
+ "CheckboxValidation": {
31
31
  "methods": {},
32
32
  "properties": {}
33
33
  },
34
- "Logger": {
34
+ "CheckboxValidationBuilder": {
35
35
  "methods": {},
36
36
  "properties": {}
37
37
  },
38
- "Menu": {
38
+ "Choice": {
39
39
  "methods": {},
40
40
  "properties": {}
41
41
  },
42
- "MimeType": {
42
+ "DateItem": {
43
43
  "methods": {},
44
44
  "properties": {}
45
45
  },
46
- "Month": {
46
+ "DateTimeItem": {
47
47
  "methods": {},
48
48
  "properties": {}
49
49
  },
50
- "PromptResponse": {
50
+ "DestinationType": {
51
51
  "methods": {},
52
52
  "properties": {}
53
53
  },
54
- "RgbColor": {
54
+ "DurationItem": {
55
55
  "methods": {},
56
56
  "properties": {}
57
57
  },
58
- "Session": {
58
+ "FeedbackType": {
59
59
  "methods": {},
60
60
  "properties": {}
61
61
  },
62
- "Ui": {
62
+ "Form": {
63
63
  "methods": {},
64
64
  "properties": {}
65
65
  },
66
- "User": {
66
+ "FormApp": {
67
67
  "methods": {},
68
68
  "properties": {}
69
69
  },
70
- "Weekday": {
70
+ "FormResponse": {
71
71
  "methods": {},
72
72
  "properties": {}
73
73
  },
74
- "console": {
74
+ "GridItem": {
75
+ "methods": {},
76
+ "properties": {}
77
+ },
78
+ "GridValidation": {
79
+ "methods": {},
80
+ "properties": {}
81
+ },
82
+ "GridValidationBuilder": {
83
+ "methods": {},
84
+ "properties": {}
85
+ },
86
+ "ImageItem": {
87
+ "methods": {},
88
+ "properties": {}
89
+ },
90
+ "Item": {
91
+ "methods": {},
92
+ "properties": {}
93
+ },
94
+ "ItemResponse": {
95
+ "methods": {},
96
+ "properties": {}
97
+ },
98
+ "ItemType": {
99
+ "methods": {},
100
+ "properties": {}
101
+ },
102
+ "ListItem": {
103
+ "methods": {},
104
+ "properties": {}
105
+ },
106
+ "MultipleChoiceItem": {
107
+ "methods": {},
108
+ "properties": {}
109
+ },
110
+ "PageBreakItem": {
111
+ "methods": {},
112
+ "properties": {}
113
+ },
114
+ "PageNavigationType": {
115
+ "methods": {},
116
+ "properties": {}
117
+ },
118
+ "ParagraphTextItem": {
119
+ "methods": {},
120
+ "properties": {}
121
+ },
122
+ "ParagraphTextValidation": {
123
+ "methods": {},
124
+ "properties": {}
125
+ },
126
+ "ParagraphTextValidationBuilder": {
127
+ "methods": {},
128
+ "properties": {}
129
+ },
130
+ "QuizFeedback": {
131
+ "methods": {},
132
+ "properties": {}
133
+ },
134
+ "QuizFeedbackBuilder": {
135
+ "methods": {},
136
+ "properties": {}
137
+ },
138
+ "RatingIconType": {
139
+ "methods": {},
140
+ "properties": {}
141
+ },
142
+ "RatingItem": {
143
+ "methods": {},
144
+ "properties": {}
145
+ },
146
+ "ScaleItem": {
147
+ "methods": {},
148
+ "properties": {}
149
+ },
150
+ "SectionHeaderItem": {
151
+ "methods": {},
152
+ "properties": {}
153
+ },
154
+ "TextItem": {
155
+ "methods": {},
156
+ "properties": {}
157
+ },
158
+ "TextValidation": {
159
+ "methods": {},
160
+ "properties": {}
161
+ },
162
+ "TextValidationBuilder": {
163
+ "methods": {},
164
+ "properties": {}
165
+ },
166
+ "TimeItem": {
167
+ "methods": {},
168
+ "properties": {}
169
+ },
170
+ "VideoItem": {
75
171
  "methods": {},
76
172
  "properties": {}
77
173
  }
@@ -1 +1 @@
1
- ["base"]
1
+ ["forms"]