@mcpher/gas-fakes 1.0.11 → 1.0.13
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 +151 -11
- package/package.json +4 -1
- package/src/index.js +4 -1
- package/src/services/advdocs/app.js +31 -0
- package/src/services/{driveapp/drapis.js → advdocs/docapis.js} +7 -7
- package/src/services/advdocs/fakeadvdocs.js +33 -0
- package/src/services/advdocs/fakeadvdocuments.js +91 -0
- package/src/services/advdrive/app.js +1 -1
- package/src/services/advdrive/drapis.js +11 -0
- package/src/services/advdrive/fakeadvdrive.js +3 -3
- package/src/services/advdrive/fakeadvdrivepermissions.js +48 -28
- package/src/services/advdrive/fakeadvvalues.js +0 -0
- package/src/services/advsheets/app.js +2 -2
- package/src/services/advsheets/fakeadvsheets.js +3 -45
- package/src/services/advsheets/fakeadvsheetsdevelopermetadata.js +14 -26
- package/src/services/advsheets/fakeadvsheetsspreadsheets.js +28 -52
- package/src/services/advsheets/fakeadvsheetsvalues.js +76 -0
- package/src/services/advsheets/shapis.js +11 -0
- package/src/services/advslides/app.js +31 -0
- package/src/services/advslides/fakeadvpresentations.js +40 -0
- package/src/services/advslides/fakeadvslides.js +32 -0
- package/src/services/{spreadsheetapp/shapis.js → advslides/slapis.js} +6 -6
- package/src/services/common/fakeadvresource.js +31 -0
- package/src/services/{commonclasses → common}/fakeborder.js +1 -1
- package/src/services/documentapp/app.js +21 -0
- package/src/services/documentapp/fakebody.js +13 -0
- package/src/services/documentapp/fakedocument.js +87 -0
- package/src/services/documentapp/fakedocumentapp.js +51 -0
- package/src/services/driveapp/fakedriveapp.js +6 -0
- package/src/services/driveapp/fakedrivemeta.js +58 -7
- package/src/services/scriptapp/app.js +7 -2
- package/src/services/session/fakesession.js +1 -1
- package/src/services/spreadsheetapp/fakesheet.js +1 -1
- package/src/services/spreadsheetapp/fakesheetrange.js +39 -19
- package/src/services/spreadsheetapp/fakesheetrangelist.js +153 -45
- package/src/services/spreadsheetapp/fakesortspec.js +1 -1
- package/src/services/spreadsheetapp/fakespreadsheet.js +1 -1
- package/src/services/spreadsheetapp/fakespreadsheetapp.js +16 -5
- package/src/services/spreadsheetapp/sheetrangemakers.js +30 -16
- package/src/support/auth.js +41 -15
- package/src/support/docscacher.js +36 -0
- package/src/support/fetchcacher.js +85 -0
- package/src/support/fileiterators.js +1 -2
- package/src/support/filesharers.js +1 -1
- package/src/support/helpers.js +55 -9
- package/src/support/sxauth.js +60 -20
- package/src/support/sxdocs.js +67 -0
- package/src/support/sxdrive.js +71 -34
- package/src/support/sxfetch.js +7 -9
- package/src/support/sxsheets.js +52 -0
- package/src/support/sxstore.js +11 -13
- package/src/support/sxstorekit.js +0 -1
- package/src/support/sxzip.js +49 -62
- package/src/support/syncit.js +120 -144
- package/src/support/workersync/sxfunctions.js +8 -0
- package/src/support/workersync/synchronizer.js +129 -0
- package/src/support/workersync/synclogger.js +15 -0
- package/src/support/workersync/worker.js +119 -0
- package/togas.bash +1 -0
- package/src/services/advsheets/fakeadvvalues.js +0 -115
- package/src/support/sxapi.js +0 -44
- package/tsynk/t.mjs +0 -10
- package/tsynk/w.mjs +0 -13
- /package/src/services/{commonclasses → common}/fakeborders.js +0 -0
- /package/src/services/{commonclasses → common}/fakecolor.js +0 -0
- /package/src/services/{commonclasses → common}/fakecolorbase.js +0 -0
- /package/src/services/{commonclasses → common}/fakecolorbuilder.js +0 -0
- /package/src/services/{commonclasses → common}/fakeprotection.js +0 -0
- /package/src/services/{commonclasses → common}/fakergbcolor.js +0 -0
- /package/src/services/{commonclasses → common}/fakerichtextvalue.js +0 -0
- /package/src/services/{commonclasses → common}/fakerun.js +0 -0
- /package/src/services/{commonclasses → common}/faketextdirection.js +0 -0
- /package/src/services/{commonclasses → common}/faketextrotation.js +0 -0
- /package/src/services/{commonclasses → common}/faketextstyle.js +0 -0
- /package/src/services/{commonclasses → common}/faketextstylebuilder.js +0 -0
- /package/src/services/{commonclasses → common}/fakethemecolor.js +0 -0
- /package/src/services/{commonclasses → common}/fakeuser.js +0 -0
- /package/src/services/{commonclasses → common}/fakewrapstrategy.js +0 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ This is a proof of concept so I've implemented a subset of number of services an
|
|
|
6
6
|
|
|
7
7
|
## progress
|
|
8
8
|
|
|
9
|
-
This is a pretty huge task, so I'm working on adding services a little bit at a time, with usually just a few methods added in each release.
|
|
9
|
+
This is a pretty huge task, so I'm working on adding services a little bit at a time, with usually just a few methods added in each release. I'm using this readme to report not just on how to use this thing, but also on challenges and things I've learned along the way. So it's going to get pretty long.
|
|
10
10
|
|
|
11
11
|
## Getting started
|
|
12
12
|
|
|
@@ -18,10 +18,18 @@ npm i @mcpher/gas-fakes
|
|
|
18
18
|
|
|
19
19
|
The idea is that you can run GAS services (so far implemented) locally on Node, and it will use various Google Workspace APIS to emulate what would happen if you were to run the same thing in the GAS environment. Other than logging in with application default credentials (see below) you don't have to do any intitialization and can start using the implemented Apps Script services directly from Node using the same syntax and getting equivalent responses.
|
|
20
20
|
|
|
21
|
+
### Use exactly the same code as in Apps Script
|
|
22
|
+
|
|
21
23
|
Just as on Apps Script, everything is executed synchronously so you don't need to bother with handling Promises/async/await. Note that the intended audience is Apps Script developers who want to run the same code and access the same services in both Node and Apps Script.
|
|
22
24
|
|
|
25
|
+
### Where to use (and not use)
|
|
26
|
+
|
|
23
27
|
If you don't plan on using Apps Script at all, the Node Workspace APIs (which I use in the background for all these services in any case) will be more efficient when operating in their normal asynchronous mode. On the other hand, if you only casually want to access workspace resources from Node, and can't be bothered digging into how the Node Workspace APIs work, you could still use this as part of your node project. Apps Script services are much simpler than the full API. Apps Script advanced services are also available via gas-fakes if you want a hybrid solution.
|
|
24
28
|
|
|
29
|
+
### Development schedule
|
|
30
|
+
|
|
31
|
+
As a background project I'm chipping away at this when I can. There's a mountain of work to do, and I'm not that bothered about the general order I do it in. If you would specifically like some service or method prioritized, let me know and I'll see if I can push it forward. Better still, if you'd like to have a crack at implementing it yourself, let me know and I'll get you started.
|
|
32
|
+
|
|
25
33
|
### Cloud project
|
|
26
34
|
|
|
27
35
|
You don't have access to the GAS maintained cloud project, so you'll need to create a GCP project to use locally. In order to duplicate the OAuth management handled by GAS, we'll use Application Default Credentials.
|
|
@@ -71,6 +79,10 @@ TEST_SHEET_NAME="sharedlibraries"
|
|
|
71
79
|
PUBLIC_SHARE_FILE_ID="1OFJk38kW9TRrEf-B9F1gTZk2uLV-ZSpR"
|
|
72
80
|
SHARED_FILE_ID="1uz4cxEDxtQzu0cBb1B4h6fsjgWy7hNFf"
|
|
73
81
|
PDF_ID="1v5kJ5SOY2nu3DI1LKwALb3seaBpF3kWu"
|
|
82
|
+
SCRATCH_VIEWER="viewer@mcpher.com"
|
|
83
|
+
SCRATCH_EDITOR="editor@mcpher.com"
|
|
84
|
+
SCRATCH_B_VIEWER="viewer2@mcpher.com"
|
|
85
|
+
SCRATCH_B_EDITOR="editor2@mcpher.com"
|
|
74
86
|
|
|
75
87
|
# these are parameters for testing
|
|
76
88
|
MIN_ROOT_PDFS=20
|
|
@@ -160,9 +172,30 @@ Beyond that, implementation is just a lot of busy work. If you are interested, h
|
|
|
160
172
|
|
|
161
173
|
Although Apps Script supports async/await/promise syntax, it operates in blocking mode. I didn't really want to have to insist on async coding in code targeted at GAS, so I needed to find a way to emulate what the GAS environment probably does.
|
|
162
174
|
|
|
163
|
-
Since asynchonicity is fundamental to Node, there's no real simple way to convert async to sync. However, there is such a thing as a [child-process](https://nodejs.org/api/child_process.html#child-process) which you can start up to run things, and it features an [execSync](https://nodejs.org/api/child_process.html#child_processexecsynccommand-options) method which delays the return from the child process until the promise queue is all settled. So the simplest solution is to run an async method in a child process, wait till it's done, and return the results synchronously. I found that [Sindre Sorhus](https://github.com/sindresorhus) uses this approach with [make-synchronous](https://github.com/sindresorhus/make-synchronous),
|
|
175
|
+
Since asynchonicity is fundamental to Node, there's no real simple way to convert async to sync. However, there is such a thing as a [child-process](https://nodejs.org/api/child_process.html#child-process) which you can start up to run things, and it features an [execSync](https://nodejs.org/api/child_process.html#child_processexecsynccommand-options) method which delays the return from the child process until the promise queue is all settled. So the simplest solution is to run an async method in a child process, wait till it's done, and return the results synchronously. I found that [Sindre Sorhus](https://github.com/sindresorhus) uses this approach with [make-synchronous](https://github.com/sindresorhus/make-synchronous).However, runnng up a child process in Node is pretty expensive and slow, and each subprocess has to reimport the google apis and go through a reauth chain which can take up to 1.5 secs per call.
|
|
176
|
+
|
|
177
|
+
#### Worker Update
|
|
178
|
+
|
|
179
|
+
I'm now upgrading to use a worker thread to handle all activities that need to be performed synchronously. It's a lot more tricky to implement and handle exceptions, but worth the effort.
|
|
180
|
+
|
|
181
|
+
- The worker thread only needs to be authed once on initialization and retains state between each call.
|
|
182
|
+
- Control to shared memory is via [Node Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics) which gives a mutex style control.
|
|
183
|
+
- Node has built in [worker threads](https://nodejs.org/api/worker_threads.html), so there's no need for any external libraries
|
|
184
|
+
- Only arguments that can be stringified can be passed to and from a worker - but this is the same limitiation as passing arguments to a subprocess
|
|
185
|
+
- To avoid grabbing too much shared memory,I use a temporary file to pass huge amounts of data - but this will be a rarish exception.
|
|
186
|
+
- There are lot of async gotchas with workers so your async handling needs to be very precise. I spent a lot of time trying to track down potentially unsettled promises only to discover that worker.unref() is required to prevent the worker from stopping the main process exiting.
|
|
187
|
+
- console.log doesnt work reliable in a worker, even if you redirect the workers stdout & stder
|
|
164
188
|
|
|
165
|
-
|
|
189
|
+
```js
|
|
190
|
+
worker.stdout.pipe(process.stdout);
|
|
191
|
+
worker.stderr.pipe(process.stderr);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
This is because console.log is async, and never shows. You need a sync version of console.log - as implemented in `./src/support/workersync/synclogger`
|
|
195
|
+
|
|
196
|
+
The result is a dramatic speed up over the subprocess approach (x5). So much so, that I had to add exponential backup to the worker threads to overcome quota limits on the workspace APIS to be able to run the test suite. Having said that it is still very much slower (x4 but variable) than most of the same calls in Apps Script - which appears to feature some mixture of in memory shadowing, caching and api call bundling - which I don't intend to mimic in this fake enironment (for now anyway) as this is not about improving the speed of Apps Script but about emulating it.
|
|
197
|
+
|
|
198
|
+
It's additionally slowed down because there are an unnatural amount of rapid, consecutive calls in the test suite which means that we get an unnatural amount of delay waiting for a quota window (sometimes as much as 15 seconds) added due to exponential back off delays when running the full test suite (I assume Apps script doesn't have the same quota restrictions). In normal operation this is unlikely to be problem.
|
|
166
199
|
|
|
167
200
|
### Global intialization
|
|
168
201
|
|
|
@@ -170,7 +203,7 @@ This was a little problematic to sequence, but I wanted to make sure that any GA
|
|
|
170
203
|
|
|
171
204
|
Only a subset of methods are currently available for some of them - the rest are work in progress. My approach is to start with a little bit of each service to prove feasibility and provide a base to build on.
|
|
172
205
|
|
|
173
|
-
v1.0.
|
|
206
|
+
v1.0.13
|
|
174
207
|
|
|
175
208
|
- `DriveApp` - 50%
|
|
176
209
|
- `ScriptApp` - almost all
|
|
@@ -184,7 +217,11 @@ v1.0.10
|
|
|
184
217
|
- `Blob` - all
|
|
185
218
|
- `User` - all
|
|
186
219
|
- `Drive (Advanced Service)` - 40%
|
|
187
|
-
- `Sheets (Advanced Service)` -
|
|
220
|
+
- `Sheets (Advanced Service)` - 60%
|
|
221
|
+
- `Slides (Advanced Service)` - 2%
|
|
222
|
+
- `Docs (Advanced Service)` - 75%
|
|
223
|
+
- `DocumentApp` - 10%
|
|
224
|
+
- `SlidesApp` - placeholder
|
|
188
225
|
|
|
189
226
|
### Testing coverage
|
|
190
227
|
|
|
@@ -238,7 +275,7 @@ In the main, these will be slight differences in error message text, which I'll
|
|
|
238
275
|
|
|
239
276
|
### Tradeoffs
|
|
240
277
|
|
|
241
|
-
I've come across various Apps Script bugs/issues as I work through this which I've reported to the GAS team, and added workarounds in the gas fakes code - not sure at this point whether to duplicate the buggy behavior or simulate what would seem to be the correct one. This is not a complete list, so any things you come across please use the issues in the repo to report.
|
|
278
|
+
I've come across various Apps Script bugs/issues as I work through this which I've reported to the GAS team, and added workarounds in the gas fakes code - not sure at this point whether to duplicate the buggy behavior or simulate what would seem to be the correct one. This is not a complete list, so any things you come across please use the issues in the repo to report.
|
|
242
279
|
|
|
243
280
|
## Oddities
|
|
244
281
|
|
|
@@ -734,6 +771,110 @@ In the Apps Script DataValidation builder, setting showCustomUi is achieved via
|
|
|
734
771
|
|
|
735
772
|
Despite the various defaults, a missing value for these properties returned via the Sheets API always means false, and a missing displayStyle with showCustomUi set to true default is "ARROW".
|
|
736
773
|
|
|
774
|
+
### Document API
|
|
775
|
+
|
|
776
|
+
Getting started on the advanced services of the Document API. These notes are for my TIL (things I learned today), but may be useful if you are digging into the Document API yourself.
|
|
777
|
+
|
|
778
|
+
#### Tabs
|
|
779
|
+
|
|
780
|
+
Tabs are a recent addition to Docs, and have added a bit of complication to handling Document responses. Here's what they say happens.
|
|
781
|
+
|
|
782
|
+
```
|
|
783
|
+
[docs](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/get)
|
|
784
|
+
|
|
785
|
+
suggestionsViewMode - enum (SuggestionsViewMode)
|
|
786
|
+
|
|
787
|
+
The suggestions view mode to apply to the document. This allows viewing the document with all suggestions inline, accepted or rejected. If one is not specified, DEFAULT_FOR_CURRENT_ACCESS is used.
|
|
788
|
+
|
|
789
|
+
includeTabsContent - boolean
|
|
790
|
+
|
|
791
|
+
Whether to populate the Document.tabs field instead of the text content fields like body and documentStyle on Document.
|
|
792
|
+
|
|
793
|
+
When True: Document content populates in the Document.tabs field instead of the text content fields in Document.
|
|
794
|
+
|
|
795
|
+
When False: The content of the document's first tab populates the content fields in Document excluding Document.tabs. If a document has only one tab, then that tab is used to populate the document content. Document.tabs will be empty.
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
It's actually a little more complicated than that - here are the properties of the each response variation.
|
|
799
|
+
|
|
800
|
+
##### case 1 {includeTabsContent: false}
|
|
801
|
+
|
|
802
|
+
{ r1k:
|
|
803
|
+
|
|
804
|
+
r2k:
|
|
805
|
+
[ 'suggestionsViewMode',
|
|
806
|
+
'documentId',
|
|
807
|
+
'tabs',
|
|
808
|
+
'title',
|
|
809
|
+
'revisionId' ],
|
|
810
|
+
r3k:
|
|
811
|
+
[ 'title',
|
|
812
|
+
'body',
|
|
813
|
+
'namedStyles',
|
|
814
|
+
'revisionId',
|
|
815
|
+
'documentId',
|
|
816
|
+
'suggestionsViewMode',
|
|
817
|
+
'documentStyle' ] }
|
|
818
|
+
14:09:40 Info { r1b: [ 'content' ],
|
|
819
|
+
r2b: [ 'documentTab', 'tabProperties' ],
|
|
820
|
+
r3b: [ 'content' ],
|
|
821
|
+
r2tb: [ 'documentStyle', 'body', 'namedStyles' ] }
|
|
822
|
+
|
|
823
|
+
Response has these properties:
|
|
824
|
+
|
|
825
|
+
```
|
|
826
|
+
'revisionId',
|
|
827
|
+
'documentStyle',
|
|
828
|
+
'body',
|
|
829
|
+
'title',
|
|
830
|
+
'suggestionsViewMode',
|
|
831
|
+
'documentId',
|
|
832
|
+
'namedStyles'
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
The body contains just 1 property - `content`
|
|
836
|
+
|
|
837
|
+
##### case 2 {includeTabsContent: true}
|
|
838
|
+
|
|
839
|
+
Response has these properties:
|
|
840
|
+
|
|
841
|
+
```
|
|
842
|
+
'suggestionsViewMode',
|
|
843
|
+
'documentId',
|
|
844
|
+
'tabs',
|
|
845
|
+
'title',
|
|
846
|
+
'revisionId'
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
The tabs property is an array of tabs, the first of which contains these properties
|
|
850
|
+
|
|
851
|
+
```
|
|
852
|
+
documentTab, tabProperties
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
The documentTab has these properties - so the tab[0] in a document with no tabs isn't exactly the same as the legacy style as implied in the docs, since the document metadata is not repeated in each tab.
|
|
856
|
+
````
|
|
857
|
+
'documentStyle', 'body', 'namedStyles'
|
|
858
|
+
````
|
|
859
|
+
The tab properties has these properties
|
|
860
|
+
````
|
|
861
|
+
'tabId', 'title', 'index'
|
|
862
|
+
````
|
|
863
|
+
|
|
864
|
+
##### case 3 - default
|
|
865
|
+
|
|
866
|
+
Response includes thes same keys as case 1. As an aside, the property orders are all unpredictable so you can't just compare stringified versions of the response.
|
|
867
|
+
|
|
868
|
+
```
|
|
869
|
+
'title',
|
|
870
|
+
'body',
|
|
871
|
+
'namedStyles',
|
|
872
|
+
'revisionId',
|
|
873
|
+
'documentId',
|
|
874
|
+
'suggestionsViewMode',
|
|
875
|
+
'documentStyle'
|
|
876
|
+
```
|
|
877
|
+
|
|
737
878
|
### Enums
|
|
738
879
|
|
|
739
880
|
All Apps Script enums are imitated using a seperate class 'newFakeGasenum()'. A complete write up of that is in [fakegasenum](https://github.com/brucemcpherson/fakegasenum). The same functionality is also available as an Apps Script library if you'd like to make your own enums over on GAS just like you find in Apps Script.
|
|
@@ -742,7 +883,6 @@ All Apps Script enums are imitated using a seperate class 'newFakeGasenum()'. A
|
|
|
742
883
|
|
|
743
884
|
Sometime between v144 and v150 of googleapis library, it appeared to become mandatory to include the project id in the auth pattern for API clients. Since we get the project id from the ADC, we actually have to do double auths. One to get the project id (which is async), and another to get an auth with the scopes required for the sheets, drive etc client (which is not async). All this now taken care of during the init phase, so look at an existing getauthenticated client function for how if you are adding a new service,
|
|
744
885
|
|
|
745
|
-
|
|
746
886
|
## Some experiences with using Gemini code assist
|
|
747
887
|
|
|
748
888
|
I tried using Gemini to generate the code and test cases for a number of method types. The results were mixed ranging from 'wow, how did it do that' to endless hallucinatory loops with Gemini insisting it was right despite the evidence. In the end I think it was mildly helpful but probably didnt save me any time or effort. It was just a different kind of effort.
|
|
@@ -751,10 +891,9 @@ Another annoyance is after deep sessions of back and forwards, code assist is ge
|
|
|
751
891
|
|
|
752
892
|
I also dislike the habit gemini has of 'mansplaining' back to me the answer I've just provided to correct some of it's code.
|
|
753
893
|
|
|
754
|
-
|
|
755
894
|
#### range.banding
|
|
756
895
|
|
|
757
|
-
This was a fairly convoluted section. I used gemini code assist heavily on this to do the legwork and all in all it made a pretty decent job of it, although with the endlessly repeated updates and test refactoring it took longer from start to finish than I would have expected it to take had I done it from scratch manually as all the previous classes. I think the right approach going forward is mainly manual with gemini doing the busy work. The tests Gemini came up with were
|
|
896
|
+
This was a fairly convoluted section. I used gemini code assist heavily on this to do the legwork and all in all it made a pretty decent job of it, although with the endlessly repeated updates and test refactoring it took longer from start to finish than I would have expected it to take had I done it from scratch manually as all the previous classes. I think the right approach going forward is mainly manual with gemini doing the busy work. The tests Gemini came up with were also far from exhaustive, and pretty much ignored edge cases, so it needed additional requests to add more robust tests. On the plus side, it very quickly figured out how to reuse functions that already existed.
|
|
758
897
|
|
|
759
898
|
#### developer meta data
|
|
760
899
|
|
|
@@ -796,10 +935,11 @@ The Sheets API doesn't know about these, so all r1c1 style methods such as setFo
|
|
|
796
935
|
|
|
797
936
|
I'm torn. On the one hand, it's been great at doing busy work like writing test cases and detecting dependencies that I might otherwise have missed. It can often be pretty good at refactoring/renaming things. On the other hand, if it gets it wrong, it's very hard to get it back on track as it tries bury itself deeper and deeper into previous misconceptions. It also has huge difficulty in updating large files no matter the detailed guidance. The usual end game is to restart a fresh context and/or copy and paste the content into a file you create manually.
|
|
798
937
|
|
|
799
|
-
There were ocassions when the content Gemini provided content to be copied and pasted that was invalid syntax, or worse, dropped lines of code in sections it didn't plan to make any changes. In particular, code that had something like `ob[method](args)` was regularily truncated to just `ob`
|
|
938
|
+
There were ocassions when the content Gemini provided content to be copied and pasted that was invalid syntax, or worse, dropped lines of code in sections it didn't plan to make any changes. In particular, code that had something like `ob[method](args)` was regularily truncated to just `obmethod`. I've found that if you enter `ob[method](args)` in the code assist chat window it will also interpret it as `obmethod` unless you escape the brackets (which of course you wouldnt do in code).
|
|
800
939
|
|
|
801
|
-
|
|
940
|
+
Another issue is that Gemini can take 10 mins or more to create the full content for a large class in its chat window, sometimes ending in the gray screen of death. I've found it's best to completely avoid using Gemini to make minor changes, but to just make them manually.
|
|
802
941
|
|
|
942
|
+
Overall it saves some time, for sure. However, the result is often suboptimal, wordy, lacking in reusability and not something I would be be happy to put my name to. From a coder perspective, the role becomes one of repetetive specification, debugging, checking and testing, while failing to develop a deep understanding of the work in hand. I like coding, so from a satisfaction perspective, I'm not entirely convinced yet. I've found it's very impressive when creating small, standalone scripts but deteriorates rapidly both in speed and effectiveness as the codebase and dependencies grows. There's a point at which it becomes more trouble than it's worth.
|
|
803
943
|
|
|
804
944
|
## Testing
|
|
805
945
|
|
package/package.json
CHANGED
|
@@ -38,10 +38,13 @@
|
|
|
38
38
|
"testsheetsdeveloper": "cp mainlocal.js main.js && node --env-file=.env ./test/testsheetsdeveloper.js execute",
|
|
39
39
|
"testsheetsexotics": "cp mainlocal.js main.js && node --env-file=.env ./test/testsheetsexotics.js execute",
|
|
40
40
|
"testsheetsdata": "cp mainlocal.js main.js && node --env-file=.env ./test/testsheetsdata.js execute",
|
|
41
|
+
"testdocsadv": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsadv.js execute",
|
|
42
|
+
"testslidesadv": "cp mainlocal.js main.js && node --env-file=.env ./test/testslidesadv.js execute",
|
|
43
|
+
"testdocs": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocs.js execute",
|
|
41
44
|
"pub": "cp mainlocal.js main.js && npm publish --access public"
|
|
42
45
|
},
|
|
43
46
|
"name": "@mcpher/gas-fakes",
|
|
44
|
-
"version": "1.0.
|
|
47
|
+
"version": "1.0.13",
|
|
45
48
|
"license": "MIT",
|
|
46
49
|
"main": "main.js",
|
|
47
50
|
"description": "A proof of concept implementation of Apps Script Environment on Node",
|
package/src/index.js
CHANGED
|
@@ -6,4 +6,7 @@ import './services/spreadsheetapp/app.js'
|
|
|
6
6
|
import './services/stores/app.js'
|
|
7
7
|
import './services/session/app.js'
|
|
8
8
|
import './services/advdrive/app.js'
|
|
9
|
-
import './services/advsheets/app.js'
|
|
9
|
+
import './services/advsheets/app.js'
|
|
10
|
+
import './services/advdocs/app.js'
|
|
11
|
+
import './services/advslides/app.js'
|
|
12
|
+
import './services/documentapp/app.js'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* the idea here is to create a global entry for the singleton
|
|
4
|
+
* before we actually have everything we need to create it.
|
|
5
|
+
* We do this by using a proxy, intercepting calls to the
|
|
6
|
+
* initial sigleton and diverting them to a completed one
|
|
7
|
+
*/
|
|
8
|
+
import { newFakeAdvDocs } from './fakeadvdocs.js'
|
|
9
|
+
import { Proxies } from '../../support/proxies.js'
|
|
10
|
+
|
|
11
|
+
// This will eventually hold a proxy for DriveApp
|
|
12
|
+
let _app = null
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* adds to global space to mimic Apps Script behavior
|
|
16
|
+
*/
|
|
17
|
+
const name = "Docs"
|
|
18
|
+
if (typeof globalThis[name] === typeof undefined) {
|
|
19
|
+
|
|
20
|
+
const getApp = () => {
|
|
21
|
+
// if it hasne been intialized yet then do that
|
|
22
|
+
if (!_app) {
|
|
23
|
+
_app = newFakeAdvDocs()
|
|
24
|
+
}
|
|
25
|
+
// this is the actual driveApp we'll return from the proxy
|
|
26
|
+
return _app
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Proxies.registerProxy (name, getApp)
|
|
30
|
+
|
|
31
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { google } from "googleapis";
|
|
2
2
|
import { Auth } from '../../support/auth.js'
|
|
3
3
|
|
|
4
|
-
let
|
|
4
|
+
let _client = null
|
|
5
5
|
|
|
6
6
|
export const getApiClient = (auth) => {
|
|
7
|
-
if (!
|
|
8
|
-
|
|
7
|
+
if (!_client) {
|
|
8
|
+
_client = google.docs({version: 'v1', auth});
|
|
9
9
|
}
|
|
10
|
-
return
|
|
10
|
+
return _client
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const getAuthedClient = () => {
|
|
14
14
|
|
|
15
|
-
if (!
|
|
15
|
+
if (!_client) {
|
|
16
16
|
const auth = Auth.getAuth()
|
|
17
17
|
return getApiClient (auth)
|
|
18
18
|
}
|
|
19
|
-
return
|
|
20
|
-
}
|
|
19
|
+
return _client
|
|
20
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced sheets service
|
|
3
|
+
*/
|
|
4
|
+
import { Proxies } from '../../support/proxies.js'
|
|
5
|
+
import { advClassMaker, notYetImplemented } from '../../support/helpers.js'
|
|
6
|
+
import { getAuthedClient } from './docapis.js'
|
|
7
|
+
import { newFakeAdvDocuments } from './fakeadvdocuments.js'
|
|
8
|
+
|
|
9
|
+
class FakeAdvDocs {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.client = Proxies.guard(getAuthedClient())
|
|
12
|
+
this.__fakeObjectType = "Docs"
|
|
13
|
+
|
|
14
|
+
const propLists = { "newNamedStyles": ["styles"], "newHorizontalRule": ["suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newUpdateTextStyleRequest": ["fields", "range", "textStyle"], "newCreateHeaderRequest": ["sectionBreakLocation", "type"], "newDeleteHeaderRequest": ["headerId", "tabId"], "newSectionColumnProperties": ["paddingEnd", "width"], "newTableCell": ["content", "endIndex", "startIndex", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTableCellStyleChanges", "tableCellStyle"], "newBatchUpdateDocumentRequest": ["requests", "writeControl"], "newReplaceAllTextRequest": ["containsText", "replaceText", "tabsCriteria"], "newDeleteContentRangeRequest": ["range"], "newTabsCriteria": ["tabIds"], "newUpdateTableColumnPropertiesRequest": ["columnIndices", "fields", "tableColumnProperties", "tableStartLocation"], "newRequest": ["createFooter", "createFootnote", "createHeader", "createNamedRange", "createParagraphBullets", "deleteContentRange", "deleteFooter", "deleteHeader", "deleteNamedRange", "deleteParagraphBullets", "deletePositionedObject", "deleteTableColumn", "deleteTableRow", "insertInlineImage", "insertPageBreak", "insertSectionBreak", "insertTable", "insertTableColumn", "insertTableRow", "insertText", "mergeTableCells", "pinTableHeaderRows", "replaceAllText", "replaceImage", "replaceNamedRangeContent", "unmergeTableCells", "updateDocumentStyle", "updateParagraphStyle", "updateSectionStyle", "updateTableCellStyle", "updateTableColumnProperties", "updateTableRowStyle", "updateTextStyle"], "newUpdateDocumentStyleRequest": ["documentStyle", "fields", "tabId"], "newCreateParagraphBulletsRequest": ["bulletPreset", "range"], "newBody": ["content"], "newParagraphBorder": ["color", "dashStyle", "padding", "width"], "newDocumentTab": ["body", "documentStyle", "footers", "footnotes", "headers", "inlineObjects", "lists", "namedRanges", "namedStyles", "positionedObjects", "suggestedDocumentStyleChanges", "suggestedNamedStylesChanges"], "newSectionStyle": ["columnProperties", "columnSeparatorStyle", "contentDirection", "defaultFooterId", "defaultHeaderId", "evenPageFooterId", "evenPageHeaderId", "firstPageFooterId", "firstPageHeaderId", "flipPageOrientation", "marginBottom", "marginFooter", "marginHeader", "marginLeft", "marginRight", "marginTop", "pageNumberStart", "sectionType", "useFirstPageHeaderFooter"], "newUpdateParagraphStyleRequest": ["fields", "paragraphStyle", "range"], "newAutoText": ["suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle", "type"], "newPerson": ["personId", "personProperties", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newNamedStyle": ["namedStyleType", "paragraphStyle", "textStyle"], "newInsertInlineImageRequest": ["endOfSegmentLocation", "location", "objectSize", "uri"], "newDocument": ["body", "documentId", "documentStyle", "footers", "footnotes", "headers", "inlineObjects", "lists", "namedRanges", "namedStyles", "positionedObjects", "revisionId", "suggestedDocumentStyleChanges", "suggestedNamedStylesChanges", "suggestionsViewMode", "tabs", "title"], "newInsertTableRequest": ["columns", "endOfSegmentLocation", "location", "rows"], "newEquation": ["suggestedDeletionIds", "suggestedInsertionIds"], "newInsertSectionBreakRequest": ["endOfSegmentLocation", "location", "sectionType"], "newStructuralElement": ["endIndex", "paragraph", "sectionBreak", "startIndex", "table", "tableOfContents"], "newDeleteNamedRangeRequest": ["name", "namedRangeId", "tabsCriteria"], "newInsertPageBreakRequest": ["endOfSegmentLocation", "location"], "newRange": ["endIndex", "segmentId", "startIndex", "tabId"], "newUpdateTableCellStyleRequest": ["fields", "tableCellStyle", "tableRange", "tableStartLocation"], "newPinTableHeaderRowsRequest": ["pinnedHeaderRowsCount", "tableStartLocation"], "newColor": ["rgbColor"], "newInsertTextRequest": ["endOfSegmentLocation", "location", "text"], "newColumnBreak": ["suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newFootnoteReference": ["footnoteId", "footnoteNumber", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newTableColumnProperties": ["width", "widthType"], "newEndOfSegmentLocation": ["segmentId", "tabId"], "newReplaceImageRequest": ["imageObjectId", "imageReplaceMethod", "tabId", "uri"], "newInsertTableRowRequest": ["insertBelow", "tableCellLocation"], "newUpdateSectionStyleRequest": ["fields", "range", "sectionStyle"], "newTab": ["childTabs", "documentTab", "tabProperties"], "newTextRun": ["content", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newInlineObjectElement": ["inlineObjectId", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newTabStop": ["alignment", "offset"], "newParagraphStyle": ["alignment", "avoidWidowAndOrphan", "borderBetween", "borderBottom", "borderLeft", "borderRight", "borderTop", "direction", "headingId", "indentEnd", "indentFirstLine", "indentStart", "keepLinesTogether", "keepWithNext", "lineSpacing", "namedStyleType", "pageBreakBefore", "shading", "spaceAbove", "spaceBelow", "spacingMode", "tabStops"], "newSubstringMatchCriteria": ["matchCase", "searchByRegex", "text"], "newDeleteTableColumnRequest": ["tableCellLocation"], "newShading": ["backgroundColor"], "newTabProperties": ["index", "nestingLevel", "parentTabId", "tabId", "title"], "newRgbColor": ["blue", "green", "red"], "newSize": ["height", "width"], "newOptionalColor": ["color"], "newDeleteTableRowRequest": ["tableCellLocation"], "newPersonProperties": ["email", "name"], "newBullet": ["listId", "nestingLevel", "textStyle"], "newDimension": ["magnitude", "unit"], "newCreateFootnoteRequest": ["endOfSegmentLocation", "location"], "newPageBreak": ["suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newCreateNamedRangeRequest": ["name", "range"], "newLink": ["bookmark", "bookmarkId", "heading", "headingId", "tabId", "url"], "newLocation": ["index", "segmentId", "tabId"], "newUpdateTableRowStyleRequest": ["fields", "rowIndices", "tableRowStyle", "tableStartLocation"], "newRichLinkProperties": ["mimeType", "title", "uri"], "newDeleteParagraphBulletsRequest": ["range"], "newBookmarkLink": ["id", "tabId"], "newTableRange": ["columnSpan", "rowSpan", "tableCellLocation"], "newDocumentStyle": ["background", "defaultFooterId", "defaultHeaderId", "evenPageFooterId", "evenPageHeaderId", "firstPageFooterId", "firstPageHeaderId", "flipPageOrientation", "marginBottom", "marginFooter", "marginHeader", "marginLeft", "marginRight", "marginTop", "pageNumberStart", "pageSize", "useCustomHeaderFooterMargins", "useEvenPageHeaderFooter", "useFirstPageHeaderFooter"], "newRichLink": ["richLinkId", "richLinkProperties", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTextStyleChanges", "textStyle"], "newTableRowStyle": ["minRowHeight", "preventOverflow", "tableHeader"], "newDeleteFooterRequest": ["footerId", "tabId"], "newTableCellStyle": ["backgroundColor", "borderBottom", "borderLeft", "borderRight", "borderTop", "columnSpan", "contentAlignment", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "rowSpan"], "newTextStyle": ["backgroundColor", "baselineOffset", "bold", "fontSize", "foregroundColor", "italic", "link", "smallCaps", "strikethrough", "underline", "weightedFontFamily"], "newInsertTableColumnRequest": ["insertRight", "tableCellLocation"], "newMergeTableCellsRequest": ["tableRange"], "newTableRow": ["endIndex", "startIndex", "suggestedDeletionIds", "suggestedInsertionIds", "suggestedTableRowStyleChanges", "tableCells", "tableRowStyle"], "newHeadingLink": ["id", "tabId"], "newParagraphElement": ["autoText", "columnBreak", "endIndex", "equation", "footnoteReference", "horizontalRule", "inlineObjectElement", "pageBreak", "person", "richLink", "startIndex", "textRun"], "newTableOfContents": ["content", "suggestedDeletionIds", "suggestedInsertionIds"], "newTableStyle": ["tableColumnProperties"], "newWriteControl": ["requiredRevisionId", "targetRevisionId"], "newBackground": ["color"], "newTableCellBorder": ["color", "dashStyle", "width"], "newTableCellLocation": ["columnIndex", "rowIndex", "tableStartLocation"], "newWeightedFontFamily": ["fontFamily", "weight"], "newReplaceNamedRangeContentRequest": ["namedRangeId", "namedRangeName", "tabsCriteria", "text"], "newTable": ["columns", "rows", "suggestedDeletionIds", "suggestedInsertionIds", "tableRows", "tableStyle"], "newParagraph": ["bullet", "elements", "paragraphStyle", "positionedObjectIds", "suggestedBulletChanges", "suggestedParagraphStyleChanges", "suggestedPositionedObjectIds"], "newUnmergeTableCellsRequest": ["tableRange"], "newSectionBreak": ["sectionStyle", "suggestedDeletionIds", "suggestedInsertionIds"], "newDeletePositionedObjectRequest": ["objectId", "tabId"], "newCreateFooterRequest": ["sectionBreakLocation", "type"] }
|
|
15
|
+
|
|
16
|
+
Reflect.ownKeys(propLists).forEach(p => {
|
|
17
|
+
this[p] = () => advClassMaker(propLists[p])
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
toString() {
|
|
22
|
+
return 'AdvancedServiceIdentifier{name=docs, version=v1}'
|
|
23
|
+
}
|
|
24
|
+
getVersion() {
|
|
25
|
+
return 'v1'
|
|
26
|
+
}
|
|
27
|
+
get Documents() {
|
|
28
|
+
return newFakeAdvDocuments(this)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const newFakeAdvDocs = (...args) => Proxies.guard(new FakeAdvDocs(...args))
|
|
33
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced docs service
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Proxies } from '../../support/proxies.js'
|
|
6
|
+
import { signatureArgs, ssError } from '../../support/helpers.js'
|
|
7
|
+
import { docsCacher } from '../../support/docscacher.js';
|
|
8
|
+
import { Syncit } from '../../support/syncit.js'
|
|
9
|
+
import is from '@sindresorhus/is'
|
|
10
|
+
import { FakeAdvResource } from '../common/fakeadvresource.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* the advanced docs Apps Script service faked - Documents class
|
|
14
|
+
* @class FakeAdvDocuments
|
|
15
|
+
*/
|
|
16
|
+
class FakeAdvDocuments extends FakeAdvResource {
|
|
17
|
+
constructor(docs) {
|
|
18
|
+
super(docs, 'documents', Syncit.fxDocs);
|
|
19
|
+
this.__fakeObjectType = "Docs.Documents";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
create (resource, options) {
|
|
23
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Docs.Documents.create")
|
|
24
|
+
if (nargs < 1 || nargs > 2) matchThrow('Invalid number of arguments provided. Expected 1-2 only')
|
|
25
|
+
if (!is.object(resource) || (nargs > 1 && !is.object(options))) {
|
|
26
|
+
matchThrow("API call to docs.documents.create failed with error: Invalid JSON payload received.")
|
|
27
|
+
}
|
|
28
|
+
const { response, data } = this._call("create", {
|
|
29
|
+
requestBody: resource
|
|
30
|
+
}, options);
|
|
31
|
+
|
|
32
|
+
// maybe we need to throw an error
|
|
33
|
+
ssError(response, "create")
|
|
34
|
+
|
|
35
|
+
return data
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
batchUpdate(requests, documentId) {
|
|
39
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Docs.Documents.batchUpdate");
|
|
40
|
+
if (nargs !== 2) matchThrow('Invalid number of arguments provided. Expected 2 only');
|
|
41
|
+
if (!is.object(requests) || !is.string(documentId)) {
|
|
42
|
+
matchThrow("API call to docs.documents.batchUpdate failed with error: Invalid JSON payload received.");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Invalidate the cache for this document since we are updating it.
|
|
46
|
+
docsCacher.clear(documentId);
|
|
47
|
+
|
|
48
|
+
const { response, data } = this._call("batchUpdate", {
|
|
49
|
+
documentId: documentId,
|
|
50
|
+
requestBody: requests
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
ssError(response, "batchUpdate");
|
|
54
|
+
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* often the 2nd options args is for standard gapi params
|
|
60
|
+
* however in the case of documentid they are actuallly the 2 query parameters
|
|
61
|
+
* suggestionsViewMode, includeTabsContent
|
|
62
|
+
* https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/get
|
|
63
|
+
* @param {} documentId
|
|
64
|
+
* @param {*} options
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
get(documentId, options) {
|
|
68
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Docs.Documents.get");
|
|
69
|
+
if (nargs < 1 || nargs > 2) matchThrow('Invalid number of arguments provided. Expected 1-2 only');
|
|
70
|
+
if (!is.string(documentId) || (nargs > 1 && !is.object(options))) {
|
|
71
|
+
matchThrow("API call to docs.documents.get failed with error: Invalid JSON payload received.");
|
|
72
|
+
}
|
|
73
|
+
const optionsSet = new Set(["suggestionsViewMode", "includeTabsContent"]);
|
|
74
|
+
|
|
75
|
+
if (nargs === 2 && !Reflect.ownKeys(options || {}).every(f => optionsSet.has(f))) matchThrow();
|
|
76
|
+
|
|
77
|
+
const params = { documentId, ...(options || {}) };
|
|
78
|
+
const cachedData = docsCacher.getEntry(documentId, options || {});
|
|
79
|
+
if (cachedData) {
|
|
80
|
+
return cachedData;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const { response, data } = this._call("get", params);
|
|
84
|
+
ssError(response, 'get');
|
|
85
|
+
|
|
86
|
+
docsCacher.setEntry(documentId, options || {}, data);
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const newFakeAdvDocuments = (...args) => Proxies.guard(new FakeAdvDocuments(...args))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { google } from "googleapis";
|
|
2
|
+
import { Auth } from '../../support/auth.js'
|
|
3
|
+
|
|
4
|
+
export const getApiClient = (auth) => {
|
|
5
|
+
return google.drive({ version: 'v3', auth });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const getAuthedClient = () => {
|
|
9
|
+
const auth = Auth.getAuth()
|
|
10
|
+
return getApiClient(auth)
|
|
11
|
+
}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Proxies } from '../../support/proxies.js'
|
|
5
5
|
import { notYetImplemented } from '../../support/helpers.js'
|
|
6
|
-
import { getAuthedClient } from '
|
|
6
|
+
import { getAuthedClient } from './drapis.js'
|
|
7
7
|
import { newFakeAdvDriveAbout } from './fakeadvdriveabout.js'
|
|
8
8
|
import { newFakeAdvDriveFiles } from './fakeadvdrivefiles.js';
|
|
9
9
|
import { newFakeAdvDriveApps } from './fakeadvdriveapps.js'
|
|
10
|
-
import {
|
|
10
|
+
import { newFakeAdvDrivePermissions } from './fakeadvdrivepermissions.js'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* the advanced Drive Apps Script service faked
|
|
@@ -55,7 +55,7 @@ class FakeAdvDrive {
|
|
|
55
55
|
)
|
|
56
56
|
}
|
|
57
57
|
get Permissions() {
|
|
58
|
-
return
|
|
58
|
+
return newFakeAdvDrivePermissions(this)
|
|
59
59
|
}
|
|
60
60
|
get Replies() {
|
|
61
61
|
return notYetImplemented()
|
|
@@ -1,36 +1,56 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import { notYetImplemented, signatureArgs } from '../../support/helpers.js';
|
|
3
|
+
import { FakeAdvResource } from '../common/fakeadvresource.js';
|
|
4
|
+
import { Syncit } from '../../support/syncit.js';
|
|
1
5
|
|
|
2
|
-
|
|
3
|
-
import { checkResponse } from '../../support/filecache.js';
|
|
4
|
-
import { mergeParamStrings } from '../../support/utils.js';
|
|
5
|
-
import { notYetImplemented, minPermissionFields } from '../../support/helpers.js'
|
|
6
|
-
import { Proxies } from '../../support/proxies.js'
|
|
7
|
-
|
|
8
|
-
class FakeAdvDrivePermissions {
|
|
6
|
+
class FakeAdvDrivePermissions extends FakeAdvResource {
|
|
9
7
|
constructor(drive) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.__fakeObjectType ="Drive.Permissions"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
// The service name is 'permissions', and it uses the main Drive sync method.
|
|
9
|
+
super(drive, 'permissions', Syncit.fxDrive);
|
|
10
|
+
this.__fakeObjectType = "Drive.Permissions";
|
|
11
|
+
|
|
12
|
+
const props = ['get', 'update'];
|
|
13
|
+
props.forEach(f => {
|
|
14
|
+
if (!this[f]) {
|
|
15
|
+
this[f] = () => notYetImplemented(f);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
|
|
20
|
+
create(resource, fileId, optionalArgs) {
|
|
21
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Drive.Permissions.create");
|
|
22
|
+
if (nargs < 2 || nargs > 3) matchThrow();
|
|
23
|
+
|
|
24
|
+
const params = {
|
|
25
|
+
resource,
|
|
26
|
+
fileId,
|
|
27
|
+
...(optionalArgs || {})
|
|
28
|
+
};
|
|
29
|
+
const { data } = this._call('create', params);
|
|
30
|
+
return data;
|
|
22
31
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
|
|
33
|
+
delete(fileId, permissionId, optionalArgs) {
|
|
34
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Drive.Permissions.delete");
|
|
35
|
+
if (nargs < 2 || nargs > 3) matchThrow();
|
|
36
|
+
|
|
37
|
+
const params = {
|
|
38
|
+
fileId,
|
|
39
|
+
permissionId,
|
|
40
|
+
...(optionalArgs || {})
|
|
41
|
+
};
|
|
42
|
+
// Delete returns an empty body on success, so we don't need to return anything.
|
|
43
|
+
this._call('delete', params);
|
|
30
44
|
}
|
|
31
|
-
|
|
32
|
-
|
|
45
|
+
|
|
46
|
+
list(fileId, optionalArgs) {
|
|
47
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Drive.Permissions.list");
|
|
48
|
+
if (nargs < 1 || nargs > 2) matchThrow();
|
|
49
|
+
|
|
50
|
+
const params = { fileId, ...(optionalArgs || {}) };
|
|
51
|
+
const { data } = this._call('list', params);
|
|
52
|
+
return data;
|
|
33
53
|
}
|
|
34
54
|
}
|
|
35
55
|
|
|
36
|
-
export const
|
|
56
|
+
export const newFakeAdvDrivePermissions = (...args) => Proxies.guard(new FakeAdvDrivePermissions(...args));
|
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
/**
|
|
3
3
|
* the idea here is to create a global entry for the singleton
|
|
4
4
|
* before we actually have everything we need to create it.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { newFakeAdvSheets } from './fakeadvsheets.js'
|
|
9
9
|
import { Proxies } from '../../support/proxies.js'
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
let _app = null
|
|
13
13
|
|
|
14
14
|
/**
|