@mcpher/gas-fakes 1.0.4 → 1.0.6

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 (37) hide show
  1. package/README.md +90 -78
  2. package/package.json +3 -1
  3. package/src/index.js +1 -1
  4. package/src/services/advdrive/fakeadvdrive.js +30 -82
  5. package/src/services/advdrive/fakeadvdriveabout.js +15 -0
  6. package/src/services/advdrive/fakeadvdriveapps.js +47 -0
  7. package/src/services/advdrive/fakeadvdrivefiles.js +244 -0
  8. package/src/services/advdrive/fakeadvdrivepermissions.js +35 -0
  9. package/src/services/{drive → driveapp}/drapis.js +10 -0
  10. package/src/services/driveapp/fakedrive.js +9 -0
  11. package/src/services/driveapp/fakedriveapp.js +162 -0
  12. package/src/services/driveapp/fakedrivefile.js +164 -0
  13. package/src/services/driveapp/fakedrivefolder.js +104 -0
  14. package/src/services/driveapp/fakedriveiterators.js +205 -0
  15. package/src/services/driveapp/fakedrivemeta.js +375 -0
  16. package/src/services/driveapp/fakefolderapp.js +156 -0
  17. package/src/services/scriptapp/app.js +0 -1
  18. package/src/services/session/fakeuser.js +13 -1
  19. package/src/services/sheets/fakesheet.js +1 -1
  20. package/src/services/urlfetchapp/app.js +37 -7
  21. package/src/services/utilities/fakeblob.js +22 -2
  22. package/src/services/utilities/fakeutilities.js +2 -2
  23. package/src/support/auth.js +4 -1
  24. package/src/support/filecache.js +154 -0
  25. package/src/support/helpers.js +117 -0
  26. package/src/support/proxies.js +10 -1
  27. package/src/support/sxauth.js +116 -0
  28. package/src/support/sxdrive.js +188 -0
  29. package/src/support/sxfetch.js +31 -0
  30. package/src/support/sxstore.js +19 -0
  31. package/src/support/sxzip.js +91 -0
  32. package/src/support/syncit.js +190 -289
  33. package/src/support/utils.js +79 -1
  34. package/src/services/drive/fakedrive.js +0 -570
  35. package/src/services/drive/fakedrivehelpers.js +0 -142
  36. package/src/support/constants.js +0 -22
  37. /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,12 +28,13 @@ 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",
@@ -38,15 +43,16 @@ gasfakes.json holds various location and behavior parameters to inform about you
38
43
  "properties": "/tmp/gas-fakes/properties",
39
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,19 +164,27 @@ 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 and classes are implemented. However, only a subset of methods are currently available for some of them - 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.
170
+
171
+ v1.0.5
161
172
 
162
- v1.0.3
163
- - `DriveApp`
164
- - `ScriptApp`
165
- - `UrlFetchApp`
166
- - `Utilities`
167
- - `Sheets`
168
- - `CacheService`
169
- - `PropertiesService`
170
- - `Session`
171
- - `Blob`
172
- - `User`
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.
173
188
 
174
189
  #### Proxies and globalThis
175
190
 
@@ -178,39 +193,36 @@ Each service has a FakeClass but I needed the Auth cycle to be initiated and don
178
193
  Here's the code for `Utilities`
179
194
 
180
195
  ```js
181
-
182
196
  /**
183
197
  * adds to global space to mimic Apps Script behavior
184
198
  */
185
- import { Proxies } from '../../support/proxies.js'
186
- import { newFakeUtilities } from './fakeutilities.js';
187
-
199
+ import { Proxies } from "../../support/proxies.js";
200
+ import { newFakeUtilities } from "./fakeutilities.js";
188
201
 
189
202
  // This will eventually hold a proxy for Utilties
190
- let _app = null
203
+ let _app = null;
191
204
 
192
205
  /**
193
206
  * adds to global space to mimic Apps Script behavior
194
207
  */
195
- const name = "Utilities"
208
+ const name = "Utilities";
196
209
  if (typeof globalThis[name] === typeof undefined) {
197
210
  const getApp = () => {
198
211
  // if it hasnt been intialized yet then do that
199
212
  if (!_app) {
200
- console.log (`setting ${name} to global`)
201
- _app = newFakeUtilities()
213
+ console.log(`setting ${name} to global`);
214
+ _app = newFakeUtilities();
202
215
  }
203
216
  // this is the actual driveApp we'll return from the proxy
204
- return _app
205
- }
206
- Proxies.registerProxy (name, getApp)
217
+ return _app;
218
+ };
219
+ Proxies.registerProxy(name, getApp);
207
220
  }
208
221
  ```
209
222
 
210
223
  Here's how the proxies are registered
211
224
 
212
225
  ```js
213
-
214
226
  /**
215
227
  * diverts the property get to another object returned by the getApp function
216
228
  * @param {function} a function to get the proxy object to substitutes
@@ -218,20 +230,19 @@ Here's how the proxies are registered
218
230
  */
219
231
  const getAppHandler = (getApp) => {
220
232
  return {
221
-
222
233
  get(_, prop, receiver) {
223
- // this will let the caller know we're not really running in Apps Script
224
- 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);
225
236
  },
226
237
 
227
238
  ownKeys(_) {
228
- return Reflect.ownKeys(getApp())
229
- }
230
- }
231
- }
239
+ return Reflect.ownKeys(getApp());
240
+ },
241
+ };
242
+ };
232
243
 
233
244
  const registerProxy = (name, getApp) => {
234
- const value = new Proxy({}, getAppHandler(getApp))
245
+ const value = new Proxy({}, getAppHandler(getApp));
235
246
  // add it to the global space to mimic what apps script does
236
247
  Object.defineProperty(globalThis, name, {
237
248
  value,
@@ -239,7 +250,7 @@ const registerProxy = (name, getApp) => {
239
250
  configurable: false,
240
251
  writable: false,
241
252
  });
242
- }
253
+ };
243
254
  ```
244
255
 
245
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.
@@ -251,55 +262,55 @@ There's also a test available to see if you are running in GAS or on Node - `Scr
251
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.
252
263
 
253
264
  ```js
254
- import { Proxies } from './proxies.js'
265
+ import { Proxies } from "./proxies.js";
255
266
  /**
256
267
  * this is a class to add a hasnext to a generator
257
268
  * @class Peeker
258
- *
269
+ *
259
270
  */
260
271
  class Peeker {
261
272
  /**
262
- * @constructor
273
+ * @constructor
263
274
  * @param {function} generator the generator function to add a hasNext() to
264
275
  * @returns {Peeker}
265
276
  */
266
277
  constructor(generator) {
267
- this.generator = generator
278
+ this.generator = generator;
268
279
  // in order to be able to do a hasnext we have to actually get the value
269
280
  // this is the next value stored
270
- this.peeked = generator.next()
281
+ this.peeked = generator.next();
271
282
  }
272
283
 
273
284
  /**
274
285
  * we see if there's a next if the peeked at is all over
275
286
  * @returns {Boolean}
276
287
  */
277
- hasNext () {
278
- return !this.peeked.done
288
+ hasNext() {
289
+ return !this.peeked.done;
279
290
  }
280
291
 
281
292
  /**
282
293
  * get the next value - actually its already got and storef in peeked
283
294
  * @returns {object} {value, done}
284
295
  */
285
- next () {
296
+ next() {
286
297
  if (!this.hasNext()) {
287
298
  // TODO find out what driveapp does
288
- throw new Error ('iterator is exhausted - there is no more')
299
+ throw new Error("iterator is exhausted - there is no more");
289
300
  }
290
301
  // instead of returning the next, we return the prepeeked next
291
- const value = this.peeked.value
292
- this.peeked = this.generator.next()
293
- return value
302
+ const value = this.peeked.value;
303
+ this.peeked = this.generator.next();
304
+ return value;
294
305
  }
295
306
  }
296
307
 
297
- export const newPeeker = (...args) => Proxies.guard(new Peeker (...args))
308
+ export const newPeeker = (...args) => Proxies.guard(new Peeker(...args));
298
309
  ```
299
310
 
300
311
  And an example of usage, creating a parents iterator from a Drive API file.
301
312
 
302
- ````
313
+ ```
303
314
  const getParentsIterator = ({
304
315
  file
305
316
  }) => {
@@ -319,22 +330,20 @@ const getParentsIterator = ({
319
330
  // create the iterator
320
331
  const parentsIt = filesink()
321
332
 
322
- // a regular iterator doesnt support the same methods
333
+ // a regular iterator doesnt support the same methods
323
334
  // as Apps Script so we'll fake that too
324
335
  return newPeeker(parentsIt)
325
336
 
326
337
  }
327
- ````
328
-
338
+ ```
329
339
 
330
340
  ### Cache and Property services
331
341
 
332
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.
333
343
 
334
-
335
344
  #### Script, user and document store varieties
336
345
 
337
- All 3 are supported for both properties and cache.
346
+ All 3 are supported for both properties and cache.
338
347
 
339
348
  ##### scriptId
340
349
 
@@ -343,19 +352,22 @@ The local version may have no knowledge of the Apps ScriptId. If you are using c
343
352
  ##### userId
344
353
 
345
354
  The userId is extracted from an accessToken and will match the id derived from Application Default Credentials. This means that you can logon as a different user to test user data isolation. All user level property and cache stores use the scriptId and userId to partition data.
355
+
346
356
  ##### documentId
347
357
 
348
- 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.
349
359
 
350
360
  ### Settings and temporary files
351
361
 
352
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.
353
363
 
354
-
355
364
  ## Noticed differences
356
365
 
357
- I'll make a note here on trivial implementation differences. The main will be slight differences in error message text, which I'll normalize over time. Please report any differences in behavior you find in the repo issues.
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
358
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.
359
371
 
360
372
  ## Help
361
373
 
package/package.json CHANGED
@@ -6,11 +6,13 @@
6
6
  "google-auth-library": "^9.15.0",
7
7
  "googleapis": "^144.0.0",
8
8
  "got": "^14.4.5",
9
+ "into-stream": "^8.0.1",
9
10
  "keyv": "^5.2.3",
10
11
  "keyv-file": "^5.1.1",
11
12
  "make-synchronous": "^1.0.0",
12
13
  "mime": "^4.0.6",
13
14
  "sleep-synchronously": "^2.0.0",
15
+ "to-readable-stream": "^4.0.0",
14
16
  "unzipper": "^0.12.3"
15
17
  },
16
18
  "type": "module",
@@ -19,7 +21,7 @@
19
21
  "pub": "npm publish --access public"
20
22
  },
21
23
  "name": "@mcpher/gas-fakes",
22
- "version": "1.0.4",
24
+ "version": "1.0.6",
23
25
  "main": "main.js",
24
26
  "description": "A proof of concept implementation of Apps Script Environment on Node",
25
27
  "repository": "github:brucemcpherson/gas-fakes",
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
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'
@@ -2,11 +2,21 @@
2
2
  * Advanced drive service
3
3
  */
4
4
  import { Proxies } from '../../support/proxies.js'
5
- import { notYetImplemented } from '../../support/constants.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
+ */
6
16
 
7
17
  class FakeAdvDrive {
8
18
  constructor() {
9
-
19
+ this.client = Proxies.guard(getAuthedClient())
10
20
  }
11
21
  toString() {
12
22
  return `AdvancedServiceIdentifier{name=drive, version=v3}`
@@ -21,113 +31,51 @@ class FakeAdvDrive {
21
31
  return newFakeAdvDriveAbout(this)
22
32
  }
23
33
  get Accessproposals() {
24
- return notYetImplemented
34
+ return notYetImplemented()
25
35
  }
26
36
  get Apps() {
27
- return notYetImplemented
37
+ return newFakeAdvDriveApps(this)
28
38
  }
29
39
  get Changes() {
30
- return notYetImplemented
40
+ return notYetImplemented()
31
41
  }
32
42
  get Channels() {
33
- return notYetImplemented
43
+ return notYetImplemented()
34
44
  }
35
45
  get Comments() {
36
- return notYetImplemented
46
+ return notYetImplemented()
37
47
  }
38
48
  get Drives() {
39
- return notYetImplemented
49
+ return notYetImplemented()
40
50
  }
41
51
  get Operations() {
42
- return notYetImplemented
52
+ return blanketProxy(
53
+ "GoogleJsonResponseException: API call to drive.operations.list failed with error: Operation is not implemented, or supported, or enabled."
54
+ )
43
55
  }
44
56
  get Permissions() {
45
- return notYetImplemented
57
+ return newFakeDrivePermissions(this)
46
58
  }
47
59
  get Replies() {
48
- return notYetImplemented
60
+ return notYetImplemented()
49
61
  }
50
62
  get Revisions() {
51
- return notYetImplemented
63
+ return notYetImplemented()
52
64
  }
53
65
  get Teamdrives() {
54
- return notYetImplemented
66
+ return notYetImplemented()
55
67
  }
56
68
 
57
69
  }
58
70
 
59
- class FakeAdvDriveAbout {
60
- constructor(drive) {
61
- this.toString = drive.toString
62
- }
63
-
64
- // this is a schema and needs the fields parameter
65
- get() {
66
- return notYetImplemented
67
- }
68
- }
69
-
70
- class FakeAdvDriveFiles {
71
- constructor(drive) {
72
- this.toString = drive.toString
73
- }
74
-
75
- listLabels() {
76
- return notYetImplemented
77
- }
78
-
79
- emptyTrash() {
80
- return notYetImplemented
81
- }
82
71
 
83
- update() {
84
- return notYetImplemented
85
- }
86
-
87
- list() {
88
- return notYetImplemented
89
- }
90
- remove() {
91
- return notYetImplemented
92
- }
72
+ // will always fail no matter which method is selected
73
+ const blanketProxy = (message) => Proxies.blanketProxy(() => {
74
+ throw new Error(message)
75
+ })
93
76
 
94
- download() {
95
- return notYetImplemented
96
- }
97
-
98
- modifyLabels() {
99
- return notYetImplemented
100
- }
101
-
102
- watch() {
103
- return notYetImplemented
104
- }
105
-
106
- get() {
107
- return notYetImplemented
108
- }
109
-
110
- create() {
111
- return notYetImplemented
112
- }
113
-
114
- generateIds() {
115
- return notYetImplemented
116
- }
117
-
118
- copy() {
119
- return notYetImplemented
120
- }
121
-
122
- export() {
123
- return notYetImplemented
124
- }
125
-
126
- }
127
77
 
128
- const newFakeAdvDriveFiles = (...args) => Proxies.guard(new FakeAdvDriveFiles(...args))
129
- const newFakeAdvDriveAbout = (...args) => Proxies.guard(new FakeAdvDriveAbout(...args))
130
- export const newFakeAdvDrive = (...args) => Proxies.guard(new FakeAdvDrive)
78
+ export const newFakeAdvDrive = (...args) => Proxies.guard(new FakeAdvDrive(...args))
131
79
 
132
80
 
133
81
 
@@ -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))
@@ -0,0 +1,47 @@
1
+
2
+ import { Proxies } from '../../support/proxies.js'
3
+ import { isGood, throwResponse } from '../../support/helpers.js'
4
+ import { Syncit } from '../../support/syncit.js'
5
+
6
+ /**
7
+ * these apply to Drive.apps
8
+ * note that this can't work with ADC yet as it's blocked - waiting for feedback from google on the issue
9
+ */
10
+ class FakeAdvDriveApps {
11
+ constructor(drive) {
12
+ this.drive = drive
13
+ this.name = 'Drive.Apps'
14
+ this.apiProp = 'apps'
15
+ }
16
+
17
+ toString() {
18
+ return this.drive.toString()
19
+ }
20
+
21
+ get(appId, params = {}) {
22
+ // sincify that call
23
+ params = { ...params, appId }
24
+ const { response, data } = Syncit.fxDrive({ prop: this.apiProp, method: 'get', params })
25
+
26
+ // maybe we need to throw an error
27
+ if (!isGood(response)) {
28
+ throwResponse(response)
29
+ }
30
+
31
+ return data
32
+ }
33
+
34
+ list(params) {
35
+ // sincify that call
36
+ const { response, data } = Syncit.fxDrive({ prop: this.apiProp, method: 'list', params })
37
+
38
+ // maybe we need to throw an error
39
+ if (!isGood(response)) {
40
+ throwResponse(response)
41
+ }
42
+ return data
43
+ }
44
+
45
+ }
46
+
47
+ export const newFakeAdvDriveApps = (...args) => Proxies.guard(new FakeAdvDriveApps(...args))