@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.
- package/README.md +70 -18
- package/gprompts/gas-inventory.js +96 -0
- package/gprompts/gas-inventory.json +116 -20
- package/gprompts/inventory-list.json +1 -1
- package/gprompts/package-lock.json +234 -0
- package/gprompts/package.json +1 -0
- package/package.json +5 -2
- package/src/index.js +2 -1
- package/src/services/advdocs/app.js +4 -23
- package/src/services/advdrive/app.js +6 -28
- package/src/services/advforms/app.js +6 -25
- package/src/services/advgmail/app.js +6 -26
- package/src/services/advsheets/app.js +6 -26
- package/src/services/advslides/app.js +6 -28
- package/src/services/common/lazyloader.js +22 -0
- package/src/services/documentapp/app.js +8 -42
- package/src/services/documentapp/appenderhelpers.js +2 -2
- package/src/services/documentapp/fakeparagraph.js +1 -1
- package/src/services/driveapp/app.js +6 -28
- package/src/services/formapp/app.js +5 -40
- package/src/services/gmailapp/app.js +7 -40
- package/src/services/logger/app.js +8 -0
- package/src/services/logger/fakelogger.js +206 -0
- package/src/services/scriptapp/app.js +7 -1
- package/src/services/scriptapp/behavior.js +1 -1
- package/src/services/session/app.js +10 -0
- package/src/services/slidesapp/app.js +5 -40
- package/src/services/spreadsheetapp/app.js +6 -50
- package/src/services/spreadsheetapp/fakeovergridimage.js +47 -0
- package/src/services/spreadsheetapp/fakesheet.js +31 -4
- package/src/services/stores/app.js +0 -1
- package/src/services/urlfetchapp/app.js +0 -1
- package/src/services/utilities/app.js +6 -20
- package/src/support/proxies.js +16 -0
- package/src/support/sxxlsx.js +41 -0
- package/src/support/syncit.js +179 -141
- package/src/support/workersync/sxfunctions.js +11 -10
- package/gprompts/gas-inventory.mjs +0 -80
- package/src/services/base/app.js +0 -33
- /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
|
-
####
|
|
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
|
|
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
|
|
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
|
-
"
|
|
3
|
-
"name": "
|
|
4
|
-
"link": "https://developers.google.com/apps-script/reference/
|
|
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
|
-
"
|
|
10
|
+
"Alignment": {
|
|
11
11
|
"methods": {},
|
|
12
12
|
"properties": {}
|
|
13
13
|
},
|
|
14
|
-
"
|
|
14
|
+
"CheckboxGridItem": {
|
|
15
15
|
"methods": {},
|
|
16
16
|
"properties": {}
|
|
17
17
|
},
|
|
18
|
-
"
|
|
18
|
+
"CheckboxGridValidation": {
|
|
19
19
|
"methods": {},
|
|
20
20
|
"properties": {}
|
|
21
21
|
},
|
|
22
|
-
"
|
|
22
|
+
"CheckboxGridValidationBuilder": {
|
|
23
23
|
"methods": {},
|
|
24
24
|
"properties": {}
|
|
25
25
|
},
|
|
26
|
-
"
|
|
26
|
+
"CheckboxItem": {
|
|
27
27
|
"methods": {},
|
|
28
28
|
"properties": {}
|
|
29
29
|
},
|
|
30
|
-
"
|
|
30
|
+
"CheckboxValidation": {
|
|
31
31
|
"methods": {},
|
|
32
32
|
"properties": {}
|
|
33
33
|
},
|
|
34
|
-
"
|
|
34
|
+
"CheckboxValidationBuilder": {
|
|
35
35
|
"methods": {},
|
|
36
36
|
"properties": {}
|
|
37
37
|
},
|
|
38
|
-
"
|
|
38
|
+
"Choice": {
|
|
39
39
|
"methods": {},
|
|
40
40
|
"properties": {}
|
|
41
41
|
},
|
|
42
|
-
"
|
|
42
|
+
"DateItem": {
|
|
43
43
|
"methods": {},
|
|
44
44
|
"properties": {}
|
|
45
45
|
},
|
|
46
|
-
"
|
|
46
|
+
"DateTimeItem": {
|
|
47
47
|
"methods": {},
|
|
48
48
|
"properties": {}
|
|
49
49
|
},
|
|
50
|
-
"
|
|
50
|
+
"DestinationType": {
|
|
51
51
|
"methods": {},
|
|
52
52
|
"properties": {}
|
|
53
53
|
},
|
|
54
|
-
"
|
|
54
|
+
"DurationItem": {
|
|
55
55
|
"methods": {},
|
|
56
56
|
"properties": {}
|
|
57
57
|
},
|
|
58
|
-
"
|
|
58
|
+
"FeedbackType": {
|
|
59
59
|
"methods": {},
|
|
60
60
|
"properties": {}
|
|
61
61
|
},
|
|
62
|
-
"
|
|
62
|
+
"Form": {
|
|
63
63
|
"methods": {},
|
|
64
64
|
"properties": {}
|
|
65
65
|
},
|
|
66
|
-
"
|
|
66
|
+
"FormApp": {
|
|
67
67
|
"methods": {},
|
|
68
68
|
"properties": {}
|
|
69
69
|
},
|
|
70
|
-
"
|
|
70
|
+
"FormResponse": {
|
|
71
71
|
"methods": {},
|
|
72
72
|
"properties": {}
|
|
73
73
|
},
|
|
74
|
-
"
|
|
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
|
-
["
|
|
1
|
+
["forms"]
|