@mcpher/gas-fakes 1.0.18 → 1.0.20
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/.aiexclude +6 -0
- package/README.md +17 -23
- package/fakeadvdocuments.js +0 -0
- package/gasmess/bruce/pbx.js +109 -8
- package/gasmess/bruce/sorting.js +106 -0
- package/gprompts/gas-inventory.json +80 -0
- package/gprompts/gas-inventory.mjs +80 -0
- package/gprompts/inventory-list.json +1 -0
- package/gprompts/model.json +34 -0
- package/gprompts/package-lock.json +869 -0
- package/gprompts/package.json +17 -0
- package/gprompts/regenerate-progress-reports.sh +38 -0
- package/gprompts/temp_fetch.mjs +9 -0
- package/gprompts/update-progress.js +142 -0
- package/package.json +6 -1
- package/setup.sh +147 -0
- package/src/index.js +10 -2
- package/src/services/advforms/app.js +31 -0
- package/src/services/advforms/fakeadvforms.js +221 -0
- package/src/services/advforms/fakeadvformsform.js +80 -0
- package/src/services/advforms/formsapis.js +15 -0
- package/src/services/advgmail/app.js +31 -0
- package/src/services/advgmail/fakeadvgmail.js +39 -0
- package/src/services/advgmail/fakeadvgmaillabels.js +119 -0
- package/src/services/advgmail/fakeadvgmailusers.js +23 -0
- package/src/services/advgmail/gmailapis.js +15 -0
- package/src/services/documentapp/appenderhelpers.js +53 -25
- package/src/services/documentapp/elementblasters.js +78 -2
- package/src/services/documentapp/elementhelpers.js +105 -1
- package/src/services/documentapp/elementoptions.js +120 -49
- package/src/services/documentapp/fakebody.js +244 -1
- package/src/services/documentapp/fakedocument.js +55 -4
- package/src/services/documentapp/fakedocumentapp.js +14 -5
- package/src/services/documentapp/fakeelement.js +20 -3
- package/src/services/documentapp/fakelistitem.js +244 -24
- package/src/services/documentapp/fakeparagraph.js +287 -62
- package/src/services/documentapp/faketable.js +16 -0
- package/src/services/documentapp/faketablerow.js +15 -0
- package/src/services/documentapp/nrhelpers.js +1 -0
- package/src/services/documentapp/shadowdocument.js +37 -33
- package/src/services/documentapp/stylehelpers.js +1 -0
- package/src/services/enums/docsenums.js +2 -1
- package/src/services/enums/formsenums.js +62 -0
- package/src/services/enums/gmailenums.js +8 -0
- package/src/services/formapp/app.js +44 -0
- package/src/services/formapp/fakecheckboxitem.js +142 -0
- package/src/services/formapp/fakechoice.js +45 -0
- package/src/services/formapp/fakeform.js +167 -0
- package/src/services/formapp/fakeformapp.js +107 -0
- package/src/services/formapp/fakeformitem.js +218 -0
- package/src/services/formapp/formitemregistry.js +23 -0
- package/src/services/formapp/formitems.js +6 -0
- package/src/services/gmailapp/app.js +44 -0
- package/src/services/gmailapp/fakegmailapp.js +35 -0
- package/src/services/gmailapp/fakegmaillabel.js +44 -0
- package/src/services/scriptapp/app.js +2 -1
- package/src/services/scriptapp/behavior.js +2 -1
- package/src/services/slidesapp/app.js +3 -3
- package/src/services/spreadsheetapp/fakeprotection.js +38 -38
- package/src/services/spreadsheetapp/fakesheet.js +2 -4
- package/src/services/spreadsheetapp/fakesheetrange.js +0 -1
- package/src/support/formscacher.js +7 -0
- package/src/support/gmailcacher.js +7 -0
- package/src/support/helpers.js +3 -5
- package/src/support/proxies.js +4 -1
- package/src/support/sxdocs.js +3 -3
- package/src/support/sxforms.js +50 -0
- package/src/support/sxgmail.js +55 -0
- package/src/support/syncit.js +7 -0
- package/src/support/utils.js +46 -15
- package/src/support/workersync/sxfunctions.js +5 -9
- package/togas.bash +18 -5
- package/ghissues/image-size-inconsistency-issue.sh +0 -46
- package/ghissues/issue-positioned-image.sh +0 -25
- package/ghissues/post-issue.sh +0 -53
- package/ghissues/review-sandbox-listing-issue.sh +0 -45
- package/ghissues/sandbox-issue.sh +0 -31
- package/ghissues/setup-under-construction.sh +0 -107
- /package/src/services/{session → base}/app.js +0 -0
- /package/src/services/{session → base}/fakesession.js +0 -0
package/.aiexclude
ADDED
package/README.md
CHANGED
|
@@ -33,12 +33,24 @@ In order to duplicate the OAuth management handled by GAS, we'll use Application
|
|
|
33
33
|
|
|
34
34
|
#### Application default credentials
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
In order to avoid a bunch of Node specific code and credentials, yet still handle OAuth, I figured that we could simply rely on ADC. This is a problem I already wrote about here [Application Default Credentials with Google Cloud and Workspace APIs](https://ramblings.mcpher.com/application-default-credentials-with-google-cloud-and-workspace-apis/)
|
|
37
|
+
|
|
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
|
+
|
|
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
|
|
37
49
|
|
|
38
|
-
|
|
50
|
+
#### Option 2 - manual setup
|
|
39
51
|
|
|
52
|
+
You can setup the .env file your self using the .env.template as a guide.
|
|
40
53
|
|
|
41
|
-
These should be in your .env file to enable ADC authentication. The purpose of the DRIVE_TEST_FILE_ID is so that the script can check you've enabled ADC correctly by pinging a file you have access to. The GCP_PROJECT_ID is required as it will be used by gas-fakes to access the workspace apis on your behalf.
|
|
42
54
|
```
|
|
43
55
|
# must set these
|
|
44
56
|
GCP_PROJECT_ID="add your gcp project id here"
|
|
@@ -55,25 +67,6 @@ EXTRA_SCOPES=",https://www.googleapis.com/auth/drive,https://www.googleapis.com/
|
|
|
55
67
|
|
|
56
68
|
- goto ./shells and execute sp.sh
|
|
57
69
|
|
|
58
|
-
### OAuth
|
|
59
|
-
|
|
60
|
-
There's 2 pieces to this solution.
|
|
61
|
-
|
|
62
|
-
#### Application default credentials (ADC)
|
|
63
|
-
|
|
64
|
-
In order to avoid a bunch of Node specific code and credentials, yet still handle OAuth, I figured that we could simply rely on ADC. This is a problem I already wrote about here [Application Default Credentials with Google Cloud and Workspace APIs](https://ramblings.mcpher.com/application-default-credentials-with-google-cloud-and-workspace-apis/)
|
|
65
|
-
|
|
66
|
-
This section in your env file controls which scopes you plan to use.
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
we'll use the default config for application default credentials
|
|
70
|
-
AC=default
|
|
71
|
-
# these are the scopes set by default - take some of these out if you want to minimize access
|
|
72
|
-
DEFAULT_SCOPES="https://www.googleapis.com/auth/userinfo.email,openid,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/sqlservice.login"
|
|
73
|
-
EXTRA_SCOPES=",https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets"
|
|
74
|
-
|
|
75
|
-
.....etc
|
|
76
|
-
```
|
|
77
70
|
|
|
78
71
|
#### Manifest file
|
|
79
72
|
|
|
@@ -144,4 +137,5 @@ As I mentioned earlier, to take this further, I'm going to need a lot of help to
|
|
|
144
137
|
- [setup env](setup-env.md) - ([credit Eric Shapiro] - additional info on contents of .env file
|
|
145
138
|
- [this file](README.md)
|
|
146
139
|
- [named colors](named-colors.md)
|
|
147
|
-
- [sandbox](sandbox.md)
|
|
140
|
+
- [sandbox](sandbox.md)
|
|
141
|
+
- [named range identity](named-range-identity.md)
|
|
File without changes
|
package/gasmess/bruce/pbx.js
CHANGED
|
@@ -2,7 +2,108 @@ import '../../main.js';
|
|
|
2
2
|
import { moveToTempFolder, deleteTempFile } from '../tempfolder.js';
|
|
3
3
|
import { report, scl } from './dreport.js';
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
|
|
5
7
|
const suffix = "-bruce"
|
|
8
|
+
const tli = () => {
|
|
9
|
+
let doc = DocumentApp.create("abc")
|
|
10
|
+
const id = doc.getId()
|
|
11
|
+
moveToTempFolder(id, suffix)
|
|
12
|
+
let body = doc.getBody();
|
|
13
|
+
let li = body.appendListItem("Initial list item text.");
|
|
14
|
+
|
|
15
|
+
doc = scl(doc)
|
|
16
|
+
let d = Docs.Documents.get(id)
|
|
17
|
+
console.log('after append item', doc.getBody().getNumChildren())
|
|
18
|
+
console.log(JSON.stringify(d.body.content))
|
|
19
|
+
|
|
20
|
+
body = doc.getBody()
|
|
21
|
+
li = body.getChild(1)
|
|
22
|
+
li.clear();
|
|
23
|
+
|
|
24
|
+
doc = scl(doc)
|
|
25
|
+
d = Docs.Documents.get(id)
|
|
26
|
+
console.log('after clear', doc.getBody().getNumChildren())
|
|
27
|
+
console.log(JSON.stringify(d.body.content))
|
|
28
|
+
|
|
29
|
+
body = doc.getBody()
|
|
30
|
+
li = body.getChild(1)
|
|
31
|
+
li.setText("New text after clear.");
|
|
32
|
+
doc = scl(doc)
|
|
33
|
+
d = Docs.Documents.get(id)
|
|
34
|
+
console.log('after new text', doc.getBody().getNumChildren())
|
|
35
|
+
console.log(JSON.stringify(d.body.content))
|
|
36
|
+
|
|
37
|
+
body = doc.getBody()
|
|
38
|
+
li = body.getChild(1)
|
|
39
|
+
li.setText("Image test: "); // setText returns void, so we can't chain.
|
|
40
|
+
|
|
41
|
+
doc = scl(doc)
|
|
42
|
+
d = Docs.Documents.get(id)
|
|
43
|
+
console.log('after image text', doc.getBody().getNumChildren())
|
|
44
|
+
console.log(JSON.stringify(d.body.content))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const imageUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png';
|
|
48
|
+
const imageBlob = UrlFetchApp.fetch(imageUrl).getBlob();
|
|
49
|
+
body = doc.getBody()
|
|
50
|
+
li = body.getChild(1)
|
|
51
|
+
li.appendInlineImage(imageBlob.copyBlob());
|
|
52
|
+
|
|
53
|
+
console.log('after inlinr image', doc.getBody().getNumChildren())
|
|
54
|
+
console.log(JSON.stringify(d.body.content))
|
|
55
|
+
|
|
56
|
+
deleteTempFile(id)
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
tli()
|
|
60
|
+
|
|
61
|
+
const tx2 = () => {
|
|
62
|
+
let doc = DocumentApp.create("abc")
|
|
63
|
+
const id = doc.getId()
|
|
64
|
+
moveToTempFolder(id, suffix)
|
|
65
|
+
|
|
66
|
+
let body = doc.getBody()
|
|
67
|
+
|
|
68
|
+
const p1 = body.appendParagraph("p1")
|
|
69
|
+
doc = scl(doc)
|
|
70
|
+
let d = Docs.Documents.get(id)
|
|
71
|
+
console.log(JSON.stringify(d))
|
|
72
|
+
|
|
73
|
+
const attributesToSet = {
|
|
74
|
+
[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT]: DocumentApp.HorizontalAlignment.CENTER,
|
|
75
|
+
[DocumentApp.Attribute.ITALIC]: true,
|
|
76
|
+
[DocumentApp.Attribute.FONT_FAMILY]: 'Comic Sans MS'
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
body = doc.getBody()
|
|
80
|
+
body.setAttributes(attributesToSet);
|
|
81
|
+
doc = scl(doc)
|
|
82
|
+
d = Docs.Documents.get(id)
|
|
83
|
+
console.log(JSON.stringify(d))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
deleteTempFile(id)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const tx1 = () => {
|
|
90
|
+
let doc = DocumentApp.create("abc")
|
|
91
|
+
const id = doc.getId()
|
|
92
|
+
moveToTempFolder(id, suffix)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
const body = doc.getBody();
|
|
97
|
+
const paraText = "p1";
|
|
98
|
+
|
|
99
|
+
const appendedPara = body.appendParagraph(paraText);
|
|
100
|
+
const paraToTest = body.getChild(1);
|
|
101
|
+
doc = scl(doc)
|
|
102
|
+
console.log(report(Docs.Documents.get(id, { includeTabsContent: true }), `\n1.empty document`))
|
|
103
|
+
const attributes = paraToTest.getAttributes();
|
|
104
|
+
|
|
105
|
+
deleteTempFile(id)
|
|
106
|
+
}
|
|
6
107
|
|
|
7
108
|
const tabsa = () => {
|
|
8
109
|
|
|
@@ -11,11 +112,11 @@ const tabsa = () => {
|
|
|
11
112
|
moveToTempFolder(id, suffix)
|
|
12
113
|
|
|
13
114
|
let body = doc.getBody()
|
|
14
|
-
console.log
|
|
115
|
+
console.log(body)
|
|
15
116
|
doc = scl(doc)
|
|
16
|
-
console.log(report(Docs.Documents.get(id, {includeTabsContent: true}), `\n1.empty document`))
|
|
117
|
+
console.log(report(Docs.Documents.get(id, { includeTabsContent: true }), `\n1.empty document`))
|
|
118
|
+
|
|
17
119
|
|
|
18
|
-
|
|
19
120
|
deleteTempFile(id)
|
|
20
121
|
}
|
|
21
122
|
|
|
@@ -70,7 +171,7 @@ const pbnew = () => {
|
|
|
70
171
|
console.log(report(Docs.Documents.get(id), `\n4.inserted para 2`))
|
|
71
172
|
|
|
72
173
|
body = doc.getBody()
|
|
73
|
-
body.insertTable(1, [['eboo', 'fbar']]
|
|
174
|
+
body.insertTable(1, [['eboo', 'fbar']])
|
|
74
175
|
doc = scl(doc)
|
|
75
176
|
console.log(report(Docs.Documents.get(id), `\nt4.inserted table at child 1`))
|
|
76
177
|
|
|
@@ -81,12 +182,12 @@ const pbnew = () => {
|
|
|
81
182
|
|
|
82
183
|
body = doc.getBody()
|
|
83
184
|
let c = body.getChild(2)
|
|
84
|
-
c.appendText(
|
|
185
|
+
c.appendText('p2 appended text')
|
|
85
186
|
doc = scl(doc)
|
|
86
187
|
console.log(report(Docs.Documents.get(id), `\n6.appended text to para 2`))
|
|
87
188
|
|
|
88
189
|
body = doc.getBody()
|
|
89
|
-
body.insertTable(3, [['bar', 'foo'], ['barfoo', 'foobar'], ['eboo', 'fbar']]
|
|
190
|
+
body.insertTable(3, [['bar', 'foo'], ['barfoo', 'foobar'], ['eboo', 'fbar']])
|
|
90
191
|
doc = scl(doc)
|
|
91
192
|
console.log(report(Docs.Documents.get(id), `\nt6.inserted table at child 3`))
|
|
92
193
|
|
|
@@ -107,7 +208,7 @@ const pbnew = () => {
|
|
|
107
208
|
console.log(report(Docs.Documents.get(id), `\n9.inserted page break in para 3`))
|
|
108
209
|
|
|
109
210
|
body = doc.getBody()
|
|
110
|
-
c=body.getChild(3)
|
|
211
|
+
c = body.getChild(3)
|
|
111
212
|
c.appendText('after pagebreak in 3')
|
|
112
213
|
doc = scl(doc)
|
|
113
214
|
console.log(report(Docs.Documents.get(id), `\n10.inserted text after pagebreak in 3`))
|
|
@@ -120,7 +221,7 @@ const pbnew = () => {
|
|
|
120
221
|
deleteTempFile(id)
|
|
121
222
|
}
|
|
122
223
|
|
|
123
|
-
|
|
224
|
+
|
|
124
225
|
|
|
125
226
|
|
|
126
227
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Compares two values using Google Sheets' ascending sort logic.
|
|
4
|
+
* @param {*} a first value to compare
|
|
5
|
+
* @param {*} b second value to compare
|
|
6
|
+
* @returns {number} a<b: -1, a===b: 0, a>b: 1
|
|
7
|
+
*/
|
|
8
|
+
const compareMixedValues = (a, b) => {
|
|
9
|
+
const isBlankA = (a === null || a === undefined || a === "");
|
|
10
|
+
const isBlankB = (b === null || b === undefined || b === "");
|
|
11
|
+
|
|
12
|
+
// Handle blanks - always sorted to the top in this ascending comparator
|
|
13
|
+
if (isBlankA && !isBlankB) return -1;
|
|
14
|
+
if (!isBlankA && isBlankB) return 1;
|
|
15
|
+
if (isBlankA && isBlankB) return 0;
|
|
16
|
+
|
|
17
|
+
// Get type priorities (lower number = sorts first)
|
|
18
|
+
const getTypePriority = (val) => {
|
|
19
|
+
// Correct Google Sheets ascending priority
|
|
20
|
+
if (typeof val === 'number') return 1;
|
|
21
|
+
if (typeof val === 'string') return 2;
|
|
22
|
+
if (typeof val === 'boolean') return 3;
|
|
23
|
+
if (val instanceof Date) return 4;
|
|
24
|
+
return 5;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const priorityA = getTypePriority(a);
|
|
28
|
+
const priorityB = getTypePriority(b);
|
|
29
|
+
|
|
30
|
+
// If different types, sort by type priority
|
|
31
|
+
if (priorityA !== priorityB) {
|
|
32
|
+
return priorityA < priorityB ? -1 : 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Same types - compare values
|
|
36
|
+
if (typeof a === 'number' && typeof b === 'number') {
|
|
37
|
+
return a - b;
|
|
38
|
+
}
|
|
39
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
40
|
+
return a.localeCompare(b, undefined, { sensitivity: 'base', numeric: true });
|
|
41
|
+
}
|
|
42
|
+
if (typeof a === 'boolean' && typeof b === 'boolean') {
|
|
43
|
+
return (a === b) ? 0 : (a ? 1 : -1);
|
|
44
|
+
}
|
|
45
|
+
if (a instanceof Date && b instanceof Date) {
|
|
46
|
+
return a.getTime() - b.getTime();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Fallback for other types
|
|
50
|
+
const strA = String(a);
|
|
51
|
+
const strB = String(b);
|
|
52
|
+
return strA.localeCompare(strB, undefined, { sensitivity: 'base' });
|
|
53
|
+
};
|
|
54
|
+
// ... your sort2d function remains correct, just pass the 'ascending' flag to compareMixedValues.
|
|
55
|
+
export const sort2d = (spec, arr) => {
|
|
56
|
+
const deepCopy = arr.map(row => [...row]);
|
|
57
|
+
return deepCopy.sort((a, b) => {
|
|
58
|
+
for (const s of spec) {
|
|
59
|
+
const index = (typeof s === 'object' && s !== null) ? s.column - 1 : s - 1;
|
|
60
|
+
const ascending = (typeof s === 'object' && s !== null) ? s.ascending !== false : true;
|
|
61
|
+
let result = compareMixedValues(a[index], b[index]);
|
|
62
|
+
if (!ascending) {
|
|
63
|
+
result = -result;
|
|
64
|
+
}
|
|
65
|
+
if (result !== 0) {
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return 0;
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Test function to verify behavior
|
|
74
|
+
export const testSorting = (spec) => {
|
|
75
|
+
const testData = [
|
|
76
|
+
[false, 120, 'cheese', 'peach', 'armpit', 10],
|
|
77
|
+
['kiwi', 'orange', 'apple', 'bub ble', 'bucket', 'armpit'],
|
|
78
|
+
['plum', 'butter', 'buckle', 'grape', 65, 65],
|
|
79
|
+
[false, "", 'armpit', 'orange', 21, 'buckle'],
|
|
80
|
+
['cherry', 'foo', 'butter', 21, 'red eye', 'foo'],
|
|
81
|
+
['kiwi', 77, false, 'banana', 'red eye', 'apple'],
|
|
82
|
+
['buckle', 'bar', 'foo', 21, 10, 'foo'],
|
|
83
|
+
['bub ble', 65, 'butter', 'buckle', 'bub ble', null],
|
|
84
|
+
['cheese', 'pear', 'pear', 77, 10, 'foo'],
|
|
85
|
+
[
|
|
86
|
+
'bub ble',
|
|
87
|
+
'armpit',
|
|
88
|
+
'melon',
|
|
89
|
+
'buckle',
|
|
90
|
+
'red eye',
|
|
91
|
+
3.141592653589793
|
|
92
|
+
],
|
|
93
|
+
['pear', false, 0.3963452962629548, 'foo', 'banana', 'plum'],
|
|
94
|
+
['cherry', true, 'apple', 'cheese', 'butter', 'peach']
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
console.log('Original:', testData);
|
|
98
|
+
|
|
99
|
+
// Sort by column 2 (booleans) ascending
|
|
100
|
+
const sorted = sort2d(spec, testData);
|
|
101
|
+
console.log('Sorted by column 2 (booleans ASC):', sorted);
|
|
102
|
+
|
|
103
|
+
return sorted;
|
|
104
|
+
};
|
|
105
|
+
const spec = [1,{column:2 , ascending:false}]
|
|
106
|
+
testSorting(spec)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Base Service": {
|
|
3
|
+
"name": "Base Service",
|
|
4
|
+
"link": "https://developers.google.com/apps-script/reference/base",
|
|
5
|
+
"classes": {
|
|
6
|
+
"Classes": {
|
|
7
|
+
"methods": {},
|
|
8
|
+
"properties": {}
|
|
9
|
+
},
|
|
10
|
+
"Blob": {
|
|
11
|
+
"methods": {},
|
|
12
|
+
"properties": {}
|
|
13
|
+
},
|
|
14
|
+
"BlobSource": {
|
|
15
|
+
"methods": {},
|
|
16
|
+
"properties": {}
|
|
17
|
+
},
|
|
18
|
+
"Browser": {
|
|
19
|
+
"methods": {},
|
|
20
|
+
"properties": {}
|
|
21
|
+
},
|
|
22
|
+
"Button": {
|
|
23
|
+
"methods": {},
|
|
24
|
+
"properties": {}
|
|
25
|
+
},
|
|
26
|
+
"ButtonSet": {
|
|
27
|
+
"methods": {},
|
|
28
|
+
"properties": {}
|
|
29
|
+
},
|
|
30
|
+
"ColorType": {
|
|
31
|
+
"methods": {},
|
|
32
|
+
"properties": {}
|
|
33
|
+
},
|
|
34
|
+
"Logger": {
|
|
35
|
+
"methods": {},
|
|
36
|
+
"properties": {}
|
|
37
|
+
},
|
|
38
|
+
"Menu": {
|
|
39
|
+
"methods": {},
|
|
40
|
+
"properties": {}
|
|
41
|
+
},
|
|
42
|
+
"MimeType": {
|
|
43
|
+
"methods": {},
|
|
44
|
+
"properties": {}
|
|
45
|
+
},
|
|
46
|
+
"Month": {
|
|
47
|
+
"methods": {},
|
|
48
|
+
"properties": {}
|
|
49
|
+
},
|
|
50
|
+
"PromptResponse": {
|
|
51
|
+
"methods": {},
|
|
52
|
+
"properties": {}
|
|
53
|
+
},
|
|
54
|
+
"RgbColor": {
|
|
55
|
+
"methods": {},
|
|
56
|
+
"properties": {}
|
|
57
|
+
},
|
|
58
|
+
"Session": {
|
|
59
|
+
"methods": {},
|
|
60
|
+
"properties": {}
|
|
61
|
+
},
|
|
62
|
+
"Ui": {
|
|
63
|
+
"methods": {},
|
|
64
|
+
"properties": {}
|
|
65
|
+
},
|
|
66
|
+
"User": {
|
|
67
|
+
"methods": {},
|
|
68
|
+
"properties": {}
|
|
69
|
+
},
|
|
70
|
+
"Weekday": {
|
|
71
|
+
"methods": {},
|
|
72
|
+
"properties": {}
|
|
73
|
+
},
|
|
74
|
+
"console": {
|
|
75
|
+
"methods": {},
|
|
76
|
+
"properties": {}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
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/"
|
|
7
|
+
const items = JSON.parse(await fs.readFile('/home/bruce/gas-fakes/gprompts/inventory-list.json', 'utf-8'));
|
|
8
|
+
const outputFile = '/home/bruce/gas-fakes/gprompts/gas-inventory.json';
|
|
9
|
+
|
|
10
|
+
const visited = new Set();
|
|
11
|
+
const queue = items.map (f=>baseUrl+f);
|
|
12
|
+
|
|
13
|
+
async function scrape() {
|
|
14
|
+
const inventory = {};
|
|
15
|
+
|
|
16
|
+
while (queue.length > 0) {
|
|
17
|
+
const url = queue.shift();
|
|
18
|
+
if (visited.has(url)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
visited.add(url);
|
|
22
|
+
|
|
23
|
+
console.log(`Scraping ${url}`);
|
|
24
|
+
const response = await got(url);
|
|
25
|
+
const $ = cheerio.load(response.body);
|
|
26
|
+
|
|
27
|
+
const serviceName = $('h1').text().split('\n').map(f=>f.replace(/^\s+/,'').trim()).filter (f=>f)[0];
|
|
28
|
+
console.log ('...starting service name',serviceName)
|
|
29
|
+
inventory[serviceName] = {
|
|
30
|
+
name: serviceName,
|
|
31
|
+
link: url,
|
|
32
|
+
classes: {},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
$('a').each((i, el) => {
|
|
36
|
+
const href = $(el).attr('href');
|
|
37
|
+
if (href && href.startsWith(url)) {
|
|
38
|
+
const absoluteUrl = new URL(href, url).href;
|
|
39
|
+
if (!visited.has(absoluteUrl)) {
|
|
40
|
+
queue.push(absoluteUrl);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Extract classes and methods
|
|
46
|
+
$('h2').each((i, el) => {
|
|
47
|
+
const className = $(el).text().trim();
|
|
48
|
+
if (className) {
|
|
49
|
+
console.log ('...found class',className,'for service',serviceName)
|
|
50
|
+
inventory[serviceName].classes[className] = {
|
|
51
|
+
methods: {},
|
|
52
|
+
properties: {},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Find the table of methods for the current class
|
|
56
|
+
const methodsTable = $(el).nextAll('table').first();
|
|
57
|
+
methodsTable.find('tbody tr').each((j, row) => {
|
|
58
|
+
const methodName = $(row).find('td').eq(1).text().trim();
|
|
59
|
+
const methodLink = $(row).find('td').eq(1).find('a').attr('href');
|
|
60
|
+
const returnType = $(row).find('td').eq(0).text().trim();
|
|
61
|
+
|
|
62
|
+
if (methodName) {
|
|
63
|
+
inventory[serviceName].classes[className].methods[methodName] = {
|
|
64
|
+
link: methodLink ? new URL(methodLink, url).href : '',
|
|
65
|
+
returns: {
|
|
66
|
+
type: returnType,
|
|
67
|
+
link: '' // to be extracted later
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await fs.writeFile(outputFile, JSON.stringify(inventory, null, 2));
|
|
77
|
+
console.log(`Inventory saved to ${outputFile}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
scrape().catch(console.error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
["base"]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Document Service",
|
|
3
|
+
"link": "https://developers.google.com/apps-script/reference/document",
|
|
4
|
+
"classes": {
|
|
5
|
+
"DocumentApp": {
|
|
6
|
+
"methods": {
|
|
7
|
+
"create": {
|
|
8
|
+
"link": "https://developers.google.com/apps-script/reference/document/document-app#create(String)",
|
|
9
|
+
"returns": {
|
|
10
|
+
"type": "Document",
|
|
11
|
+
"link": "https://developers.google.com/apps-script/reference/document/document"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"properties": {
|
|
15
|
+
"Attribute": {
|
|
16
|
+
"type": "Attribute",
|
|
17
|
+
"link": "https://developers.google.com/apps-script/reference/document/attribute"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"Bookmark": {
|
|
22
|
+
"methods": {
|
|
23
|
+
"getId": {
|
|
24
|
+
"link": "https://developers.google.com/apps-script/reference/document/bookmark#getId()",
|
|
25
|
+
"returns": {
|
|
26
|
+
"type": "String",
|
|
27
|
+
"link": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|