@mcpher/gas-fakes 1.0.2 → 1.0.5

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 (39) hide show
  1. package/README.md +101 -91
  2. package/package.json +6 -2
  3. package/src/index.js +3 -1
  4. package/src/services/advdrive/app.js +31 -0
  5. package/src/services/advdrive/fakeadvdrive.js +200 -0
  6. package/src/services/advdrive/fakeadvdriveabout.js +15 -0
  7. package/src/services/advdrive/fakeadvdriveapps.js +47 -0
  8. package/src/services/advdrive/fakeadvdrivefiles.js +227 -0
  9. package/src/services/advdrive/fakeadvdrivepermissions.js +35 -0
  10. package/src/services/{drive → driveapp}/drapis.js +10 -0
  11. package/src/services/driveapp/fakedrive.js +9 -0
  12. package/src/services/driveapp/fakedriveapp.js +163 -0
  13. package/src/services/driveapp/fakedrivefile.js +134 -0
  14. package/src/services/driveapp/fakedrivefolder.js +104 -0
  15. package/src/services/driveapp/fakedriveiterators.js +198 -0
  16. package/src/services/driveapp/fakedrivemeta.js +257 -0
  17. package/src/services/driveapp/fakefolderapp.js +156 -0
  18. package/src/services/scriptapp/app.js +1 -2
  19. package/src/services/session/app.js +33 -0
  20. package/src/services/session/fakesession.js +45 -0
  21. package/src/services/session/fakeuser.js +44 -0
  22. package/src/services/sheets/app.js +2 -1
  23. package/src/services/sheets/fakesheet.js +1 -1
  24. package/src/services/stores/app.js +2 -1
  25. package/src/services/stores/fakestores.js +2 -2
  26. package/src/services/urlfetchapp/app.js +39 -8
  27. package/src/services/utilities/app.js +5 -20
  28. package/src/services/utilities/fakeblob.js +22 -6
  29. package/src/services/utilities/fakeutilities.js +105 -0
  30. package/src/support/auth.js +21 -4
  31. package/src/support/filecache.js +106 -0
  32. package/src/support/helpers.js +75 -0
  33. package/src/support/proxies.js +10 -1
  34. package/src/support/syncit.js +258 -37
  35. package/src/support/utils.js +79 -1
  36. package/src/services/drive/fakedrive.js +0 -570
  37. package/src/services/drive/fakedrivehelpers.js +0 -142
  38. package/src/support/constants.js +0 -17
  39. /package/src/services/{drive → driveapp}/app.js +0 -0
package/README.md CHANGED
@@ -16,7 +16,11 @@ You can get the package from npm
16
16
  npm i @mcpher/gas-fakes
17
17
  ```
18
18
 
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.
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
+
21
+ 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
+
23
+ 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 if operating in their normal asynchronous mode.
20
24
 
21
25
  ### Cloud project
22
26
 
@@ -24,29 +28,31 @@ You don't have access to the GAS maintained cloud project, so you'll need to cre
24
28
 
25
29
  ### Testing
26
30
 
27
- I recommend you use the test project included in the repo to make sure all is set up correctly. It uses a Fake DriveApp service to excercise Auth etc. Just change the fixtures to values present in your own Drive, then `npm i && npm test`. Note that I use a [unit tester](https://ramblings.mcpher.com/apps-script-test-runner-library-ported-to-node/) that runs in both GAS and Node, so the exact same tests will run in both environments. There are some example tests in the repo. Each test has been proved on both Node and GAS.
31
+ I recommend you use the test project included in the repo to make sure all is set up correctly. It uses a Fake DriveApp service to excercise Auth etc. Just change the fixtures to values present in your own Drive, then `npm i && npm test`. Note that I use a [unit tester](https://ramblings.mcpher.com/apps-script-test-runner-library-ported-to-node/) that runs in both GAS and Node, so the exact same tests will run in both environments. There are some example tests in the repo. Each test has been proved on both Node and GAS. There's also a shell (togas.sh) which will use clasp to push the test code to Apps Script.
28
32
 
29
33
  ### Settings
30
34
 
31
35
  gasfakes.json holds various location and behavior parameters to inform about your Node environment. It's not required on GAS as you can't change anything over there. If you don't have one, it'll create one for you and use some sensible defaults. Here's an example of one with the defaults. It should be in the same folder as your main script.
32
- ````
36
+
37
+ ```
33
38
  {
34
39
  "manifest": "./appsscript.json",
35
40
  "clasp": "./.clasp.json",
36
41
  "documentId": null,
37
42
  "cache": "/tmp/gas-fakes/cache",
38
43
  "properties": "/tmp/gas-fakes/properties",
39
- "scriptId": "1ey2fr74m4n9fwaqi9dsx9ye"
44
+ "scriptId": "1bc79bd3-fe02-425f-9653-525e5ae0b678"
40
45
  }
41
- ````
42
- | property | type | default | description |
43
- | ----------- | --------------- | ------------------------------------ | --------------------------------------------------------------------------------------------- |
44
- | manifest | string | ./appsscript.json | the manifest path and name relative to your main module |
45
- | clasp | string | ./clasp.json | where to look for an optional clasp file |
46
- | documentId | string | null | a bound document id. This will allow testing of container bound script. The documentId will become your activeDocument (for the appropriate service) |
47
- | cache | string | /tmp/gas-fakes/cache | gas-fakes uses a local file to emulate apps script's CacheService. This is where it should put the files |
48
- | 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 |
49
- | 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 |
46
+ ```
47
+
48
+ | property | type | default | description |
49
+ | ---------- | ------ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
50
+ | manifest | string | ./appsscript.json | the manifest path and name relative to your main module |
51
+ | clasp | string | ./clasp.json | where to look for an optional clasp file |
52
+ | documentId | string | null | a bound document id. This will allow testing of container bound script. The documentId will become your activeDocument (for the appropriate service) |
53
+ | cache | string | /tmp/gas-fakes/cache | gas-fakes uses a local file to emulate apps script's CacheService. This is where it should put the files |
54
+ | 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 |
55
+ | 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 |
50
56
 
51
57
  More on all this later.
52
58
 
@@ -80,7 +86,7 @@ Beyond that, implementation is just a lot of busy work. If you are interested, h
80
86
 
81
87
  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.
82
88
 
83
- 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), so I'm using that.
89
+ 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), so I'm using that.
84
90
 
85
91
  Here's a simple example of how to get info on an access token made synchronous
86
92
 
@@ -91,17 +97,18 @@ Here's a simple example of how to get info on an access token made synchronous
91
97
  * @returns {object} access token info
92
98
  */
93
99
  const fxCheckToken = (accessToken) => {
94
-
95
100
  // now turn all that into a synchronous function - it runs as a subprocess, so we need to start from scratch
96
- const fx = makeSynchronous(async accessToken => {
97
- const { default: got } = await import('got')
98
- const tokenInfo = await got(`https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${accessToken}`).json()
99
- return tokenInfo
100
- })
101
-
102
- const result = fx(accessToken)
103
- return result
104
- }
101
+ const fx = makeSynchronous(async (accessToken) => {
102
+ const { default: got } = await import("got");
103
+ const tokenInfo = await got(
104
+ `https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${accessToken}`
105
+ ).json();
106
+ return tokenInfo;
107
+ });
108
+
109
+ const result = fx(accessToken);
110
+ return result;
111
+ };
105
112
  ```
106
113
 
107
114
  ### OAuth
@@ -157,66 +164,65 @@ I recommend you do this to make sure Auth it's all good before you start coding
157
164
 
158
165
  ### Global intialization
159
166
 
160
- This was a little problematic to sequence, but I wanted to make sure that any GAS services being imitated were available and initialized on the Node side, just as they are in GAS. At the time of writing these services are implemented. Only a subset of methods are currently available - the rest are work in progress.
167
+ This was a little problematic to sequence, but I wanted to make sure that any GAS services being imitated were available and initialized on the Node side, just as they are in GAS. At the time of writing these services and classes are partially implemented.
168
+
169
+ 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.
161
170
 
162
- v1.0.1
163
- - `DriveApp`
164
- - `ScriptApp`
165
- - `UrlFetchApp`
166
- - `Utilities`
167
- - `Sheets`
168
- - `CacheService`
169
- - `PropertiesService`
171
+ v1.0.5
172
+
173
+ - `DriveApp` - 50%
174
+ - `ScriptApp` - almost all
175
+ - `UrlFetchApp` - 80%
176
+ - `Utilities` - 60%
177
+ - `Sheets` - `minimal`
178
+ - `CacheService` - 80%
179
+ - `PropertiesService` - 80%
180
+ - `Session` - almost all
181
+ - `Blob` - all
182
+ - `User` - all
183
+ - `Drive (Advanced Service)` - 40%
184
+
185
+ ### Testing coverage
186
+
187
+ Tests for all methods are added as we go to the cumulative unit tests and run on both Apps Script and Node. The goal is to try to get the behavior as exactly equivalent as possible. See/updated the issues section for detected anomalies. There are currently 1182 active tests.
170
188
 
171
189
  #### Proxies and globalThis
172
190
 
173
191
  Each service has a FakeClass but I needed the Auth cycle to be initiated and done before making them public. Using a proxy was the simplest approach.
174
192
 
175
- Here's the code for `ScriptApp`
193
+ Here's the code for `Utilities`
176
194
 
177
195
  ```js
178
-
179
196
  /**
180
197
  * adds to global space to mimic Apps Script behavior
181
198
  */
182
- const name = "ScriptApp"
183
-
184
- if (typeof globalThis[name] === typeof undefined) {
199
+ import { Proxies } from "../../support/proxies.js";
200
+ import { newFakeUtilities } from "./fakeutilities.js";
185
201
 
186
- // initializing auth etc
187
- Syncit.fxInit()
202
+ // This will eventually hold a proxy for Utilties
203
+ let _app = null;
188
204
 
189
- console.log(`setting ${name} to global`)
205
+ /**
206
+ * adds to global space to mimic Apps Script behavior
207
+ */
208
+ const name = "Utilities";
209
+ if (typeof globalThis[name] === typeof undefined) {
190
210
  const getApp = () => {
191
-
192
- // if it hasn't been intialized yet then do that
211
+ // if it hasnt been intialized yet then do that
193
212
  if (!_app) {
194
-
195
- _app = {
196
- getOAuthToken,
197
- requireAllScopes,
198
- requireScopes,
199
- AuthMode: {
200
- FULL: 'FULL'
201
- }
202
- }
203
-
204
-
213
+ console.log(`setting ${name} to global`);
214
+ _app = newFakeUtilities();
205
215
  }
206
216
  // this is the actual driveApp we'll return from the proxy
207
- return _app
208
- }
209
-
210
-
211
- Proxies.registerProxy(name, getApp)
212
-
217
+ return _app;
218
+ };
219
+ Proxies.registerProxy(name, getApp);
213
220
  }
214
221
  ```
215
222
 
216
223
  Here's how the proxies are registered
217
224
 
218
225
  ```js
219
-
220
226
  /**
221
227
  * diverts the property get to another object returned by the getApp function
222
228
  * @param {function} a function to get the proxy object to substitutes
@@ -224,20 +230,19 @@ Here's how the proxies are registered
224
230
  */
225
231
  const getAppHandler = (getApp) => {
226
232
  return {
227
-
228
233
  get(_, prop, receiver) {
229
- // this will let the caller know we're not really running in Apps Script
230
- return (prop === 'isFake') ? true : Reflect.get(getApp(), prop, receiver);
234
+ // this will let the caller know we're not really running in Apps Script
235
+ return prop === "isFake" ? true : Reflect.get(getApp(), prop, receiver);
231
236
  },
232
237
 
233
238
  ownKeys(_) {
234
- return Reflect.ownKeys(getApp())
235
- }
236
- }
237
- }
239
+ return Reflect.ownKeys(getApp());
240
+ },
241
+ };
242
+ };
238
243
 
239
244
  const registerProxy = (name, getApp) => {
240
- const value = new Proxy({}, getAppHandler(getApp))
245
+ const value = new Proxy({}, getAppHandler(getApp));
241
246
  // add it to the global space to mimic what apps script does
242
247
  Object.defineProperty(globalThis, name, {
243
248
  value,
@@ -245,7 +250,7 @@ const registerProxy = (name, getApp) => {
245
250
  configurable: false,
246
251
  writable: false,
247
252
  });
248
- }
253
+ };
249
254
  ```
250
255
 
251
256
  In short, the service us registered as an empty object, but when any attempt is made to access it actually returns a different object which handles the request. In the `ScriptApp` example, `ScriptApp` is an empty object, but accessing `ScriptApp.getOAuthToken()` returns an Fake `ScriptApp` object which has been initialized.
@@ -257,55 +262,55 @@ There's also a test available to see if you are running in GAS or on Node - `Scr
257
262
  An iterator created by a generator does not have a `hasNext()` function, whereas GAS iterators do. To get round this, we can create a regular Node iterator, but introduce a wrapper so the constructor actually gets the first one, and `next()` uses the value we've already peeked at. Here's a wrapper to convert an iterator into a GAS style one.
258
263
 
259
264
  ```js
260
- import { Proxies } from './proxies.js'
265
+ import { Proxies } from "./proxies.js";
261
266
  /**
262
267
  * this is a class to add a hasnext to a generator
263
268
  * @class Peeker
264
- *
269
+ *
265
270
  */
266
271
  class Peeker {
267
272
  /**
268
- * @constructor
273
+ * @constructor
269
274
  * @param {function} generator the generator function to add a hasNext() to
270
275
  * @returns {Peeker}
271
276
  */
272
277
  constructor(generator) {
273
- this.generator = generator
278
+ this.generator = generator;
274
279
  // in order to be able to do a hasnext we have to actually get the value
275
280
  // this is the next value stored
276
- this.peeked = generator.next()
281
+ this.peeked = generator.next();
277
282
  }
278
283
 
279
284
  /**
280
285
  * we see if there's a next if the peeked at is all over
281
286
  * @returns {Boolean}
282
287
  */
283
- hasNext () {
284
- return !this.peeked.done
288
+ hasNext() {
289
+ return !this.peeked.done;
285
290
  }
286
291
 
287
292
  /**
288
293
  * get the next value - actually its already got and storef in peeked
289
294
  * @returns {object} {value, done}
290
295
  */
291
- next () {
296
+ next() {
292
297
  if (!this.hasNext()) {
293
298
  // TODO find out what driveapp does
294
- throw new Error ('iterator is exhausted - there is no more')
299
+ throw new Error("iterator is exhausted - there is no more");
295
300
  }
296
301
  // instead of returning the next, we return the prepeeked next
297
- const value = this.peeked.value
298
- this.peeked = this.generator.next()
299
- return value
302
+ const value = this.peeked.value;
303
+ this.peeked = this.generator.next();
304
+ return value;
300
305
  }
301
306
  }
302
307
 
303
- export const newPeeker = (...args) => Proxies.guard(new Peeker (...args))
308
+ export const newPeeker = (...args) => Proxies.guard(new Peeker(...args));
304
309
  ```
305
310
 
306
311
  And an example of usage, creating a parents iterator from a Drive API file.
307
312
 
308
- ````
313
+ ```
309
314
  const getParentsIterator = ({
310
315
  file
311
316
  }) => {
@@ -325,22 +330,20 @@ const getParentsIterator = ({
325
330
  // create the iterator
326
331
  const parentsIt = filesink()
327
332
 
328
- // a regular iterator doesnt support the same methods
333
+ // a regular iterator doesnt support the same methods
329
334
  // as Apps Script so we'll fake that too
330
335
  return newPeeker(parentsIt)
331
336
 
332
337
  }
333
- ````
334
-
338
+ ```
335
339
 
336
340
  ### Cache and Property services
337
341
 
338
342
  These are currently implemented using [keyv](https://github.com/jaredwray/keyv) with storage adaptor [keyv-file](https://github.com/zaaack/keyv-file).The `gasfakes.json` file is used to commiicate where these files should be. I've gone for local file storage rather than something like redis to avoid adding local service requirements, but keyv takes a wide range of storage adaptors if you want to do something fancier. A small modificaion to kv.js is all you need.
339
343
 
340
-
341
344
  #### Script, user and document store varieties
342
345
 
343
- All 3 are supported for both properties and cache.
346
+ All 3 are supported for both properties and cache.
344
347
 
345
348
  ##### scriptId
346
349
 
@@ -352,12 +355,19 @@ The userId is extracted from an accessToken and will match the id derived from A
352
355
 
353
356
  ##### documentId
354
357
 
355
- The documentId is only meaningful if you are working on a container bound scrip. We use the the documentId property of gasfakes.json to identify a container file. All document level property and cache stores use the scriptId and documentId to partition data.
358
+ The documentId is only meaningful if you are working on a container bound scrip. We use the the documentId property of gasfakes.json to identify a container file. All document level property and cache stores use the scriptId and documentId to partition data.
356
359
 
357
360
  ### Settings and temporary files
358
361
 
359
- As you will have noticed, there are various local support files for props/caching etc. Be careful that these do not get committed to a public repo if you are adding sensitive values to your stores.
362
+ As you will have noticed, there are various local support files for props/caching etc. Be careful that these do not get committed to a public repo if you are adding sensitive values to your stores. Note that the real user Id is not used when creating files, but rather an encrypted version of it. This avoids real user ids being revealed in your file system.
363
+
364
+ ## Noticed differences
365
+
366
+ I'll make a note in thre repos issues on implementation differences. In the main will be slight differences in error message text, which I'll normalize over time, or where Apps Script has a fundamental obstacle. Please report any differences in behavior you find in the repo issues.
367
+
368
+ ### Tradeoffs
360
369
 
370
+ 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. Again - any things you come across please use the issues in the repo to report.
361
371
 
362
372
  ## Help
363
373
 
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "dependencies": {
3
3
  "@sindresorhus/is": "^7.0.1",
4
+ "archiver": "^7.0.1",
4
5
  "get-stream": "^9.0.1",
5
6
  "google-auth-library": "^9.15.0",
6
7
  "googleapis": "^144.0.0",
7
8
  "got": "^14.4.5",
9
+ "into-stream": "^8.0.1",
8
10
  "keyv": "^5.2.3",
9
11
  "keyv-file": "^5.1.1",
10
12
  "make-synchronous": "^1.0.0",
11
13
  "mime": "^4.0.6",
12
- "sleep-synchronously": "^2.0.0"
14
+ "sleep-synchronously": "^2.0.0",
15
+ "to-readable-stream": "^4.0.0",
16
+ "unzipper": "^0.12.3"
13
17
  },
14
18
  "type": "module",
15
19
  "scripts": {
@@ -17,7 +21,7 @@
17
21
  "pub": "npm publish --access public"
18
22
  },
19
23
  "name": "@mcpher/gas-fakes",
20
- "version": "1.0.2",
24
+ "version": "1.0.5",
21
25
  "main": "main.js",
22
26
  "description": "A proof of concept implementation of Apps Script Environment on Node",
23
27
  "repository": "github:brucemcpherson/gas-fakes",
package/src/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import './services/scriptapp/app.js'
2
- import './services/drive/app.js'
2
+ import './services/driveapp/app.js'
3
3
  import './services/urlfetchapp/app.js'
4
4
  import './services/utilities/app.js'
5
5
  import './services/sheets/app.js'
6
6
  import './services/stores/app.js'
7
+ import './services/session/app.js'
8
+ import './services/advdrive/app.js'
@@ -0,0 +1,31 @@
1
+ // fake Apps Script DriveApp
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 { newFakeAdvDrive} from './fakeadvdrive.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 = "Drive"
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 = newFakeAdvDrive()
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
+ }
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Advanced drive service
3
+ */
4
+ import { Proxies } from '../../support/proxies.js'
5
+ import { notYetImplemented } from '../../support/helpers.js'
6
+ import { getAuthedClient } from '../driveapp/drapis.js'
7
+ import { newFakeAdvDriveAbout } from './fakeadvdriveabout.js'
8
+ import { newFakeAdvDriveFiles } from './fakeadvdrivefiles.js';
9
+ import { newFakeAdvDriveApps } from './fakeadvdriveapps.js'
10
+ import { newFakeDrivePermissions } from './fakeadvdrivepermissions.js'
11
+
12
+ /**
13
+ * the advanced Drive Apps Script service faked
14
+ * @class FakeAdvDrive
15
+ */
16
+
17
+ class FakeAdvDrive {
18
+ constructor() {
19
+ this.client = Proxies.guard(getAuthedClient())
20
+ }
21
+ toString() {
22
+ return `AdvancedServiceIdentifier{name=drive, version=v3}`
23
+ }
24
+ getVersion() {
25
+ return 'v3'
26
+ }
27
+ get Files() {
28
+ return newFakeAdvDriveFiles(this)
29
+ }
30
+ get About() {
31
+ return newFakeAdvDriveAbout(this)
32
+ }
33
+ get Accessproposals() {
34
+ return notYetImplemented()
35
+ }
36
+ get Apps() {
37
+ return newFakeAdvDriveApps(this)
38
+ }
39
+ get Changes() {
40
+ return notYetImplemented()
41
+ }
42
+ get Channels() {
43
+ return notYetImplemented()
44
+ }
45
+ get Comments() {
46
+ return notYetImplemented()
47
+ }
48
+ get Drives() {
49
+ return notYetImplemented()
50
+ }
51
+ get Operations() {
52
+ return blanketProxy(
53
+ "GoogleJsonResponseException: API call to drive.operations.list failed with error: Operation is not implemented, or supported, or enabled."
54
+ )
55
+ }
56
+ get Permissions() {
57
+ return newFakeDrivePermissions(this)
58
+ }
59
+ get Replies() {
60
+ return notYetImplemented()
61
+ }
62
+ get Revisions() {
63
+ return notYetImplemented()
64
+ }
65
+ get Teamdrives() {
66
+ return notYetImplemented()
67
+ }
68
+
69
+ }
70
+
71
+
72
+ // will always fail no matter which method is selected
73
+ const blanketProxy = (message) => Proxies.blanketProxy(() => {
74
+ throw new Error(message)
75
+ })
76
+
77
+
78
+ export const newFakeAdvDrive = (...args) => Proxies.guard(new FakeAdvDrive(...args))
79
+
80
+
81
+
82
+ /* methods to implement
83
+ toString: [Function],
84
+ getVersion: [Function],
85
+ newTeamDriveRestrictions: [Function],
86
+ newTeamDrive: [Function],
87
+ newLabelFieldModification: [Function],
88
+ newFileImageMediaMetadataLocation: [Function],
89
+ newRevision: [Function],
90
+ newComment: [Function],
91
+ newFile: [Function],
92
+ newContentRestriction: [Function],
93
+ newDrive: [Function],
94
+ newDriveCapabilities: [Function],
95
+ newFileVideoMediaMetadata: [Function],
96
+ newDriveBackgroundImageFile: [Function],
97
+ newResolveAccessProposalRequest: [Function],
98
+ newFileLabelInfo: [Function],
99
+ newTeamDriveBackgroundImageFile: [Function],
100
+ newFileContentHints: [Function],
101
+ newPermission: [Function],
102
+ newFileLinkShareMetadata: [Function],
103
+ newFileImageMediaMetadata: [Function],
104
+ newFileCapabilities: [Function],
105
+ newCommentQuotedFileContent: [Function],
106
+ newReply: [Function],
107
+ newFileContentHintsThumbnail: [Function],
108
+ newModifyLabelsRequest: [Function],
109
+ newUser: [Function],
110
+ newLabel: [Function],
111
+ newDownloadRestriction: [Function],
112
+ newLabelModification: [Function],
113
+ newPermissionPermissionDetails: [Function],
114
+ newDriveRestrictions: [Function],
115
+ newPermissionTeamDrivePermissionDetails: [Function],
116
+ newFileShortcutDetails: [Function],
117
+ newChannel: [Function],
118
+ newTeamDriveCapabilities: [Function],
119
+ About: { toString: [Function], get: [Function] },
120
+
121
+
122
+
123
+
124
+ Accessproposals:
125
+ { toString: [Function],
126
+ resolve: [Function],
127
+ get: [Function],
128
+ list: [Function] },
129
+ Apps: { toString: [Function], get: [Function], list: [Function] },
130
+ Changes:
131
+ { toString: [Function],
132
+ getStartPageToken: [Function],
133
+ watch: [Function],
134
+ list: [Function] },
135
+ Channels: { toString: [Function], stop: [Function] },
136
+ Comments:
137
+ { toString: [Function],
138
+ get: [Function],
139
+ create: [Function],
140
+ update: [Function],
141
+ list: [Function],
142
+ remove: [Function] },
143
+ Drives:
144
+ { toString: [Function],
145
+ hide: [Function],
146
+ get: [Function],
147
+ create: [Function],
148
+ update: [Function],
149
+ list: [Function],
150
+ remove: [Function],
151
+ unhide: [Function] },
152
+ Files:
153
+ { toString: [Function],
154
+ listLabels: [Function],
155
+ emptyTrash: [Function],
156
+ update: [Function],
157
+ list: [Function],
158
+ remove: [Function],
159
+ download: [Function],
160
+ modifyLabels: [Function],
161
+ watch: [Function],
162
+ get: [Function],
163
+ create: [Function],
164
+ generateIds: [Function],
165
+ copy: [Function],
166
+ export: [Function] },
167
+ Operations:
168
+ { toString: [Function],
169
+ cancel: [Function],
170
+ get: [Function],
171
+ list: [Function],
172
+ remove: [Function] },
173
+ Permissions:
174
+ { toString: [Function],
175
+ get: [Function],
176
+ create: [Function],
177
+ update: [Function],
178
+ list: [Function],
179
+ remove: [Function] },
180
+ Replies:
181
+ { toString: [Function],
182
+ get: [Function],
183
+ create: [Function],
184
+ update: [Function],
185
+ list: [Function],
186
+ remove: [Function] },
187
+ Revisions:
188
+ { toString: [Function],
189
+ get: [Function],
190
+ update: [Function],
191
+ list: [Function],
192
+ remove: [Function] },
193
+ Teamdrives:
194
+ { toString: [Function],
195
+ get: [Function],
196
+ create: [Function],
197
+ update: [Function],
198
+ list: [Function],
199
+ remove: [Function] } }
200
+ */
@@ -0,0 +1,15 @@
1
+ import { Proxies } from '../../support/proxies.js'
2
+ import { notYetImplemented } from '../../support/helpers.js'
3
+
4
+ class FakeAdvDriveAbout {
5
+ constructor(drive) {
6
+ this.toString = drive.toString
7
+ }
8
+
9
+ // this is a schema and needs the fields parameter
10
+ get() {
11
+ return notYetImplemented()
12
+ }
13
+ }
14
+
15
+ export const newFakeAdvDriveAbout = (...args) => Proxies.guard(new FakeAdvDriveAbout(...args))