@mcpher/gas-fakes 1.0.14 → 1.0.16

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 (84) hide show
  1. package/README.RU.md +20 -1
  2. package/README.md +2 -1
  3. package/gasmess/bruce/d.js +4 -0
  4. package/gasmess/bruce/d1.js +4 -0
  5. package/gasmess/bruce/dreport.js +81 -0
  6. package/gasmess/bruce/pbx.js +33 -45
  7. package/gasmess/tanaike/for_simple_test.js +7 -1
  8. package/gasmess/tanaike/sample4.js +59 -0
  9. package/ghissues/issue-positioned-image.sh +25 -0
  10. package/ghissues/post-issue.sh +53 -0
  11. package/ghissues/sandbox-issue.sh +31 -0
  12. package/ghissues/setup-under-construction.sh +107 -0
  13. package/package.json +16 -7
  14. package/src/services/advdocs/docapis.js +10 -6
  15. package/src/services/advdocs/fakeadvdocs.js +1 -3
  16. package/src/services/advdocs/fakeadvdocuments.js +22 -8
  17. package/src/services/advdrive/drapis.js +10 -7
  18. package/src/services/advdrive/fakeadvdrive.js +19 -2
  19. package/src/services/advdrive/fakeadvdrivefiles.js +8 -5
  20. package/src/services/advdrive/fakeadvdrivepermissions.js +4 -4
  21. package/src/services/advsheets/fakeadvsheets.js +15 -5
  22. package/src/services/advsheets/fakeadvsheetsdevelopermetadata.js +3 -2
  23. package/src/services/advsheets/fakeadvsheetsspreadsheets.js +5 -6
  24. package/src/services/advsheets/fakeadvsheetsvalues.js +3 -2
  25. package/src/services/advsheets/shapis.js +18 -8
  26. package/src/services/advslides/fakeadvslides.js +20 -2
  27. package/src/services/advslides/slapis.js +10 -6
  28. package/src/services/documentapp/appenderhelpers.js +247 -56
  29. package/src/services/documentapp/elementblasters.js +61 -13
  30. package/src/services/documentapp/elementhelpers.js +50 -3
  31. package/src/services/documentapp/elementoptions.js +331 -47
  32. package/src/services/documentapp/elements.js +7 -0
  33. package/src/services/documentapp/fakebody.js +59 -8
  34. package/src/services/documentapp/fakebookmark.js +96 -0
  35. package/src/services/documentapp/fakecontainerelement.js +46 -12
  36. package/src/services/documentapp/fakedocument.js +186 -5
  37. package/src/services/documentapp/fakedocumentapp.js +3 -2
  38. package/src/services/documentapp/fakedocumenttab.js +10 -2
  39. package/src/services/documentapp/fakeelement.js +22 -13
  40. package/src/services/documentapp/fakefootersection.js +44 -0
  41. package/src/services/documentapp/fakefootnote.js +189 -0
  42. package/src/services/documentapp/fakefootnotereference.js +48 -0
  43. package/src/services/documentapp/fakefootnotesection.js +127 -0
  44. package/src/services/documentapp/fakeheadersection.js +44 -0
  45. package/src/services/documentapp/fakehorizontalrule.js +2 -2
  46. package/src/services/documentapp/fakeinlineimage.js +138 -0
  47. package/src/services/documentapp/fakelistitem.js +188 -0
  48. package/src/services/documentapp/fakepagebreak.js +2 -2
  49. package/src/services/documentapp/fakeparagraph.js +52 -10
  50. package/src/services/documentapp/fakeposition.js +84 -0
  51. package/src/services/documentapp/fakepositionedimage.js +86 -0
  52. package/src/services/documentapp/fakesectionelement.js +209 -0
  53. package/src/services/documentapp/faketable.js +28 -2
  54. package/src/services/documentapp/faketablecell.js +2 -2
  55. package/src/services/documentapp/faketablerow.js +2 -2
  56. package/src/services/documentapp/faketext.js +2 -2
  57. package/src/services/documentapp/fakeui.js +27 -0
  58. package/src/services/documentapp/nrhelpers.js +55 -20
  59. package/src/services/documentapp/shadowdocument.js +216 -55
  60. package/src/services/driveapp/driveiterators.js +8 -2
  61. package/src/services/driveapp/fakefolderapp.js +1 -0
  62. package/src/services/scriptapp/app.js +6 -6
  63. package/src/services/scriptapp/behavior.js +93 -0
  64. package/src/services/spreadsheetapp/fakenamedrange.js +120 -0
  65. package/src/services/spreadsheetapp/fakesheet.js +40 -2
  66. package/src/services/spreadsheetapp/fakespreadsheet.js +86 -3
  67. package/src/services/urlfetchapp/app.js +5 -5
  68. package/src/support/auth.js +14 -20
  69. package/src/support/backoff.js +52 -0
  70. package/src/support/helpers.js +10 -2
  71. package/src/support/sxauth.js +9 -11
  72. package/src/support/sxdocs.js +7 -9
  73. package/src/support/sxdrive.js +10 -14
  74. package/src/support/sxfetch.js +19 -5
  75. package/src/support/sxsheets.js +8 -8
  76. package/src/support/sxslides.js +8 -8
  77. package/src/support/sxstore.js +1 -1
  78. package/src/support/sxzip.js +1 -1
  79. package/src/support/syncit.js +5 -5
  80. package/src/support/utils.js +32 -4
  81. package/src/support/workersync/worker.js +5 -3
  82. package/src/services/advdrive/fakeadvvalues.js +0 -0
  83. package/src/services/documentapp/shadow.js +0 -121
  84. /package/{shadowhelpers.js → fakepositionedimage.js} +0 -0
package/README.RU.md CHANGED
@@ -312,4 +312,23 @@ const getParentsIterator = ({
312
312
 
313
313
  ## Помощь
314
314
 
315
- Как я уже упоминал ранее, чтобы развивать это дальше, мне понадобится много помощи для расширения поддерживаемых методов и сервисов - поэтому, если вы считаете, что это будет полезно для вас, и хотите сотрудничать, пожалуйста, свяжитесь со мной по [bruce@mcpher.com](mailto:bruce@mcpher.com) и мы поговорим.
315
+ Как я уже упоминал ранее, чтобы развивать это дальше, мне понадобится много помощи для расширения поддерживаемых методов и сервисов - поэтому, если вы считаете, что это будет полезно для вас, и хотите сотрудничать, пожалуйста, свяжитесь со мной по [bruce@mcpher.com](mailto:bruce@mcpher.com) и мы поговорим.
316
+
317
+
318
+ ## Translations and writeups
319
+
320
+ - [initial idea and thoughts](https://ramblings.mcpher.com/a-proof-of-concept-implementation-of-apps-script-environment-on-node/)
321
+ - [Inside the volatile world of a Google Document](https://ramblings.mcpher.com/inside-the-volatile-world-of-a-google-document/
322
+ - [Apps Script Services on Node – using apps script libraries](https://ramblings.mcpher.com/apps-script-services-on-node-using-apps-script-libraries/)
323
+ - [Apps Script environment on Node – more services](https://ramblings.mcpher.com/apps-script-environment-on-node-more-services/)
324
+ - [Turning async into synch on Node using workers](https://ramblings.mcpher.com/turning-async-into-synch-on-node-using-workers/)
325
+ - [All about Apps Script Enums and how to fake them](https://ramblings.mcpher.com/all-about-apps-script-enums-and-how-to-fake-them/)
326
+ - [Russian version](README.RU.md) ([credit Alex Ivanov](https://github.com/oshliaer)) - needs updating
327
+ - [colaborators](collaborators.md) - additional information for collaborators
328
+ - [oddities](oddities.md) - a collection of oddities uncovered during this project
329
+ - [gemini](gemini.md) - some reflections and experiences on using gemini to help code large projects
330
+ - [named colors](named-colors.md) - colors supported by Apps Script
331
+ - [setup env](setup-env.md) - ([credit Eric Shapiro] - additional info on contents of .env file
332
+ - [this file](README.md)
333
+ - [named colors](named-colors.md)
334
+ - [sandbox](sandbox.md)
package/README.md CHANGED
@@ -143,4 +143,5 @@ As I mentioned earlier, to take this further, I'm going to need a lot of help to
143
143
  - [named colors](named-colors.md) - colors supported by Apps Script
144
144
  - [setup env](setup-env.md) - ([credit Eric Shapiro] - additional info on contents of .env file
145
145
  - [this file](README.md)
146
- - [named colors](named-colors.md)
146
+ - [named colors](named-colors.md)
147
+ - [sandbox](sandbox.md)
@@ -0,0 +1,4 @@
1
+ import '../../main.js';
2
+ const res1 = Sheets.Spreadsheets.create({ properties: { title: "sample" } });
3
+ const res2 = Sheets.Spreadsheets.get(res1.spreadsheetId);
4
+ console.log(res2);
@@ -0,0 +1,4 @@
1
+ import '../../main.js';
2
+ const d = DriveApp.createFile('my-test-file.txt', 'Hello from gas-fakes!');
3
+ const e = DriveApp.getFileById(d.getId());
4
+ console.log(e.getName());
@@ -0,0 +1,81 @@
1
+ import is from '@sindresorhus/is';
2
+ export const whichType = (element) => {
3
+ const ts = ["paragraph", "pageBreak", "textRun", "table", "tableRows", "tableCells", "content"]
4
+ const [t] = ts.filter(f => Reflect.has(element, f))
5
+ return t
6
+ }
7
+
8
+ export const report = (doc, what) => {
9
+ let newdoc = doc
10
+ let body = doc.body
11
+ let tabs = doc.tabs
12
+ // handle case where tabs is handling legacy doc.
13
+ if (!body) {
14
+ if (!tabs) {
15
+ console.log('missing tabs')
16
+ console.log(JSON.stringify(doc))
17
+ } else {
18
+ console.log('getting body from tabs')
19
+ newdoc = tabs[0].documentTab
20
+ body = newdoc.body
21
+ }
22
+ }
23
+
24
+ // drop the section break
25
+ const children = body.content.slice(1)
26
+ what += ` -children:${children.length}`
27
+ console.log(what)
28
+ let text = ' '
29
+ console.log(stringCircular(children))
30
+ const childProps = ["elements", "tableRows", "tableCells", "content", "listItem"]
31
+ const typer = (child, text, spaces = " ") => {
32
+ const type = whichType(child)
33
+ if (type) {
34
+ text += `\n${spaces}-${type} ${child.startIndex}:${child.endIndex}`
35
+ if (type === 'textRun') {
36
+ text += ` ${JSON.stringify(child[type].content)}`
37
+ }
38
+ const key = Reflect.ownKeys(child[type]).find(f => childProps.includes(f))
39
+ let arr = key && child[type][key]
40
+ if (!arr && is.array(child[type])) arr = child[type]
41
+
42
+ if (is.array(arr)) {
43
+ //text += spaces
44
+ arr.forEach(f => text = typer(f, text, spaces + " "))
45
+ //text += ''
46
+ }
47
+ }
48
+ return text
49
+ }
50
+ return children.map(f => typer(f, text)).join("\n")
51
+ }
52
+
53
+
54
+ export const scl = (doc) => {
55
+ if (!DocumentApp.isFake) {
56
+ const id = doc.getId()
57
+ doc.saveAndClose()
58
+ doc = DocumentApp.openById(id)
59
+ }
60
+ return doc
61
+ }
62
+
63
+ // The custom replacer function
64
+ const getCircularReplacer = () => {
65
+ const seen = new WeakSet(); // Use WeakSet to avoid memory leaks
66
+ return (_, value) => {
67
+ // If the value is an object and not null
68
+ if (typeof value === "object" && value !== null) {
69
+ // If we have already seen this object, it's a circular reference
70
+ if (seen.has(value)) {
71
+ return "[Circular]"; // Replace it with a placeholder
72
+ }
73
+ // If it's a new object, add it to our cache
74
+ seen.add(value);
75
+ }
76
+ // Return the value to be serialized
77
+ return value;
78
+ };
79
+ };
80
+
81
+ export const stringCircular = (ob) => JSON.stringify(ob, getCircularReplacer());
@@ -1,54 +1,26 @@
1
1
  import '../../main.js';
2
2
  import { moveToTempFolder, deleteTempFile } from '../tempfolder.js';
3
- import is from '@sindresorhus/is';
3
+ import { report, scl } from './dreport.js';
4
+
4
5
  const suffix = "-bruce"
5
6
 
6
- const whichType = (element) => {
7
- const ts = ["paragraph", "pageBreak", "textRun","table","tableRows","tableCells","content"]
8
- const [t] = ts.filter(f => Reflect.has(element, f))
9
- //if (!t) console.log('skipping element', element)
10
- return t
11
- }
7
+ const tabsa = () => {
12
8
 
13
- const report = (doc, what) => {
14
- const body = doc.body
15
- // drop the section break
16
- const children = body.content.slice(1)
17
- what += ` -children:${children.length}`
18
- console.log(what)
19
- let text = ' '
20
-
21
- const childProps = ["elements", "tableRows", "tableCells","content"]
22
- const typer = (child, text, spaces = " ") => {
23
- const type = whichType(child)
24
- if (type) {
25
- text += `\n${spaces}-${type} ${child.startIndex}:${child.endIndex}`
26
- if (type === 'textRun') {
27
- text += ` ${JSON.stringify(child[type].content)}`
28
- }
29
- const key = Reflect.ownKeys(child[type]).find (f=>childProps.includes(f))
30
- let arr = key && child[type][key]
31
- if (!arr && is.array (child[type])) arr = child[type]
32
-
33
- if (is.array(arr)) {
34
- //text += spaces
35
- arr.forEach(f => text = typer(f, text, spaces + " "))
36
- //text += ''
37
- }
38
- }
39
- return text
40
- }
41
- return children.map(f => typer(f, text)).join("\n")
42
- }
43
- const scl = (doc) => {
44
- if (!DocumentApp.isFake) {
45
- const id = doc.getId()
46
- doc.saveAndClose()
47
- doc = DocumentApp.openById(id)
48
- }
49
- return doc
9
+ let doc = DocumentApp.create("abc")
10
+ const id = doc.getId()
11
+ moveToTempFolder(id, suffix)
12
+
13
+ let body = doc.getBody()
14
+ console.log (body)
15
+ doc = scl(doc)
16
+ console.log(report(Docs.Documents.get(id, {includeTabsContent: true}), `\n1.empty document`))
17
+
18
+
19
+ deleteTempFile(id)
50
20
  }
51
21
 
22
+ //tabsa()
23
+
52
24
  // this is testing the new simplified method
53
25
  const pbnew = () => {
54
26
  let doc = DocumentApp.create("abc")
@@ -56,6 +28,16 @@ const pbnew = () => {
56
28
  moveToTempFolder(id, suffix)
57
29
  let body
58
30
 
31
+ body = doc.getBody()
32
+ body.appendListItem('l0a append')
33
+ doc = scl(doc)
34
+ console.log(report(Docs.Documents.get(id), `\nl0a.appended list item l0a`))
35
+
36
+ body = doc.getBody()
37
+ body.appendListItem('l01b append')
38
+ doc = scl(doc)
39
+ console.log(report(Docs.Documents.get(id), `\nl0a.appended list item l0b`))
40
+
59
41
  body = doc.getBody()
60
42
  body.appendTable([['']])
61
43
  doc = scl(doc)
@@ -66,6 +48,12 @@ const pbnew = () => {
66
48
  doc = scl(doc)
67
49
  console.log(report(Docs.Documents.get(id), `\n1.appended para`))
68
50
 
51
+ body = doc.getBody()
52
+ body.appendListItem('l1 append')
53
+ doc = scl(doc)
54
+ console.log(report(Docs.Documents.get(id), `\nl1.appended list item l1`))
55
+
56
+
69
57
  body = doc.getBody()
70
58
  body.insertParagraph(0, 'para 0')
71
59
  doc = scl(doc)
@@ -131,8 +119,8 @@ const pbnew = () => {
131
119
 
132
120
  deleteTempFile(id)
133
121
  }
134
- pbnew()
135
122
 
123
+ pbnew()
136
124
 
137
125
 
138
126
 
@@ -2,5 +2,11 @@ import "../../main.js";
2
2
  import { FakeSpreadsheetApp } from "../../src/services/spreadsheetapp/fakespreadsheetapp.js";
3
3
  import { moveToTempFolder, deleteTempFile } from "./tempfolder.js";
4
4
 
5
- const spreadsheet = SpreadsheetApp.openById("");
5
+ const spreadsheet = SpreadsheetApp.openById("###");
6
6
  const sheet = spreadsheet.getSheets()[0];
7
+ sheet.setName("sample");
8
+
9
+ const r = spreadsheet.getRangeByName("test111");
10
+ if (r) {
11
+ console.log(r.getA1Notation());
12
+ }
@@ -0,0 +1,59 @@
1
+ import "../../main.js";
2
+ import { FakeSpreadsheetApp } from "../../src/services/spreadsheetapp/fakespreadsheetapp.js";
3
+ import { moveToTempFolder, deleteTempFile } from "./tempfolder.js";
4
+
5
+ const spreadsheet = SpreadsheetApp.create("sample");
6
+ const sheet = spreadsheet.getSheets()[0];
7
+ const spreadsheetId = spreadsheet.getId();
8
+ moveToTempFolder(spreadsheetId);
9
+
10
+ // Create named ranges
11
+ const name1 = "sampleNamedRange1";
12
+ const range1 = sheet.getRange("A1:B2");
13
+ const name2 = "sampleNamedRange2";
14
+ const range2 = sheet.getRange("C1:E2");
15
+ spreadsheet.setNamedRange(name1, range1);
16
+ spreadsheet.setNamedRange(name2, range2);
17
+
18
+ // Get created named ranges from Spreadsheet
19
+ const res1 = spreadsheet
20
+ .getNamedRanges()
21
+ .map(
22
+ (rr) =>
23
+ `${rr.getName()}: '${rr.getRange().getSheet().getSheetName()}'!${rr
24
+ .getRange()
25
+ .getA1Notation()}`
26
+ );
27
+ console.log(res1);
28
+
29
+ // Get created named ranges from Sheet
30
+ const res2 = sheet
31
+ .getNamedRanges()
32
+ .map(
33
+ (rr) =>
34
+ `${rr.getName()}: '${rr.getRange().getSheet().getSheetName()}'!${rr
35
+ .getRange()
36
+ .getA1Notation()}`
37
+ );
38
+ console.log(res2);
39
+
40
+ // Update named ranges.
41
+ spreadsheet.getNamedRanges().forEach((r, i) => {
42
+ r.setName(`${r.getName()}_${i + 10}`);
43
+ const range = r.getRange().offset(0, 2);
44
+ r.setRange(range);
45
+ });
46
+ const res3 = spreadsheet
47
+ .getNamedRanges()
48
+ .map(
49
+ (rr) =>
50
+ `${rr.getName()}: '${rr.getRange().getSheet().getSheetName()}'!${rr
51
+ .getRange()
52
+ .getA1Notation()}`
53
+ );
54
+ console.log(res3);
55
+
56
+ // Remove named ranges
57
+ spreadsheet.getNamedRanges().forEach((r) => r.remove());
58
+
59
+ deleteTempFile(spreadsheetId);
@@ -0,0 +1,25 @@
1
+ #!/bin/bash
2
+
3
+ # A script to create a GitHub issue for the PositionedImage API limitation.
4
+
5
+ # Issue details
6
+ TITLE="Cannot emulate Paragraph.addPositionedImage() due to missing public API"
7
+ BODY=$(cat <<'EOF'
8
+ The `DocumentApp.Paragraph.addPositionedImage()` method exists in the live Google Apps Script environment, allowing for the creation of positioned images anchored to a paragraph.
9
+
10
+ However, as of May 2024, there is no corresponding public endpoint in the Google Docs API v1 to programmatically create a `PositionedObject`. The `createPositionedObject` request does not exist in the public API.
11
+
12
+ This has been a requested feature, but it appears that the Apps Script service uses a private, non-public API to achieve this functionality.
13
+
14
+ Because `gas-fakes` relies exclusively on the public Google Workspace APIs, it is not possible to emulate this method. Tests that use `addPositionedImage` are skipped when run in the fake environment.
15
+
16
+ This issue is to track this limitation and can be closed if Google exposes a public API for this feature.
17
+
18
+ See this related issue tracker for the API feature request: https://issuetracker.google.com/issues/183845501 (Note: This is a guess at a relevant issue, a real one might need to be found or created).
19
+ EOF
20
+ )
21
+ LABELS="emulation-accuracy,document-app"
22
+
23
+ # Create the issue using the GitHub CLI
24
+ gh issue create --title "$TITLE" --body "$BODY" --label "$LABELS"
25
+
@@ -0,0 +1,53 @@
1
+ #!/bin/bash
2
+
3
+ # A shell script to post a markdown file from ./ghissues as a GitHub issue.
4
+ # It automatically extracts the title, labels, and body from the file.
5
+ #
6
+ # Usage: ./ghissues/post-issue.sh <filename>
7
+ # Example: ./ghissues/post-issue.sh document-clear-behavior.md
8
+
9
+ set -e
10
+
11
+ # The directory where issue files are stored, relative to the script's location.
12
+ SCRIPT_DIR=$(dirname "$0")
13
+
14
+ # Check for filename argument
15
+ if [ -z "$1" ]; then
16
+ echo "Usage: $0 <filename_in_ghissues_dir>"
17
+ echo "Example: $0 document-clear-behavior.md"
18
+ exit 1
19
+ fi
20
+
21
+ ISSUE_FILE="$SCRIPT_DIR/$1"
22
+
23
+ # Check if file exists
24
+ if [ ! -f "$ISSUE_FILE" ]; then
25
+ echo "Error: Issue file not found at $ISSUE_FILE"
26
+ exit 1
27
+ fi
28
+
29
+ echo "Reading issue from $ISSUE_FILE..."
30
+
31
+ # Extract the title (first line, remove markdown heading)
32
+ TITLE=$(head -n 1 "$ISSUE_FILE" | sed 's/^# //')
33
+
34
+ # Extract labels from the second line (e.g., **Labels**: `label1`, `label2`)
35
+ LABELS_LINE=$(sed -n '2p' "$ISSUE_FILE")
36
+ LABELS_STRING=$(echo "$LABELS_LINE" | grep -o '`.*`' | sed 's/`//g' || echo "")
37
+
38
+ LABEL_ARGS=()
39
+ if [ -n "$LABELS_STRING" ]; then
40
+ IFS=',' read -ra ADDR <<< "$LABELS_STRING"
41
+ for label in "${ADDR[@]}"; do
42
+ trimmed_label=$(echo "$label" | xargs) # trim whitespace
43
+ if [ -n "$trimmed_label" ]; then
44
+ LABEL_ARGS+=("--label" "$trimmed_label")
45
+ fi
46
+ done
47
+ fi
48
+
49
+ # Use the rest of the file (from line 3) as the body
50
+ gh issue create --title "$TITLE" --body-file <(tail -n +3 "$ISSUE_FILE") "${LABEL_ARGS[@]}"
51
+
52
+ echo "Issue '$TITLE' created successfully."
53
+
@@ -0,0 +1,31 @@
1
+ #!/bin/bash
2
+
3
+ # A shell script to create a GitHub issue for the sandbox feature.
4
+
5
+ # Issue title
6
+ TITLE="Improve Sandbox Mode to fully emulate drive.file scope"
7
+
8
+ # Issue body in markdown
9
+ BODY=$(cat <<'EOF'
10
+ ## Summary
11
+
12
+ The current implementation of `gas-fakes` requires the full `https://www.googleapis.com/auth/drive` scope for initialization, primarily to access metadata about the root Drive folder. This is a stumbling block for users who want to run tests in a more restrictive environment using only the `drive.file` scope.
13
+
14
+ The `ScriptApp.__behavior.sandBoxMode` was introduced as a clever workaround to *emulate* the `drive.file` scope during test execution, but it doesn't solve the initial authorization requirement.
15
+
16
+ For more details on the current sandbox implementation, see sandbox.md.
17
+
18
+ ## TODO
19
+
20
+ We need to investigate ways to remove the dependency on root folder access during the `FakeDriveApp` initialization. This would allow `gas-fakes` to operate with only the `drive.file` scope, making the sandbox feature a true end-to-end emulation.
21
+
22
+ Possible areas to explore:
23
+ - Can we mock or bypass the root folder check during initialization if a specific `drive.file` mode is detected?
24
+ - Can we lazy-initialize parts of `FakeDriveApp` that require root access, and only fail if those specific methods (like `getRootFolder()`) are called without sufficient permissions?
25
+
26
+ This would be a significant improvement for security-conscious development and testing workflows.
27
+ EOF
28
+ )
29
+
30
+ # Create the issue using GitHub CLI
31
+ gh issue create --title "$TITLE" --body "$BODY" --label "enhancement" --label "help wanted"
@@ -0,0 +1,107 @@
1
+ #!/bin/bash
2
+
3
+ echo "Welcome to the gas-fakes configuration tool!"
4
+ echo "This script will help you set up your .env and gasfakes.json files."
5
+
6
+ # --- Check for existing .env file ---
7
+ if [ -f ".env" ]; then
8
+ echo ""
9
+ echo "An existing .env file was found. We will update the values."
10
+ UPDATE_MODE=true
11
+ else
12
+ echo ""
13
+ echo "No .env file found. We will create a new one."
14
+ UPDATE_MODE=false
15
+ fi
16
+
17
+ # --- Get .env file details ---
18
+ echo ""
19
+ echo "First, let's configure your .env file for Application Default Credentials (ADC)."
20
+ echo "These are necessary for gas-fakes to access Google Workspace APIs on your behalf."
21
+
22
+ read -p "Enter your Google Cloud Project ID: " gcp_project_id
23
+ read -p "Enter the ID of a Google Drive file you have access to: " drive_test_file_id
24
+ read -p "Enter the default scopes (e.g., \"https://www.googleapis.com/auth/userinfo.email,openid,https://www.googleapis.com/auth/cloud-platform\"): " default_scopes
25
+ read -p "Enter any EXTRA_SCOPES (e.g., ,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets): " extra_scopes
26
+
27
+ # --- Update or create .env file ---
28
+ if [ "$UPDATE_MODE" = true ]; then
29
+ # Use sed to replace the values in the existing file
30
+ sed -i "s|^GCP_PROJECT_ID=.*|GCP_PROJECT_ID=$gcp_project_id|" .env
31
+ sed -i "s|^DRIVE_TEST_FILE_ID=.*|DRIVE_TEST_FILE_ID=$drive_test_file_id|" .env
32
+ sed -i "s|^DEFAULT_SCOPES=.*|DEFAULT_SCOPES=\"$default_scopes\"|" .env
33
+ sed -i "s|^EXTRA_SCOPES=.*|EXTRA_SCOPES=\"$extra_scopes\"|" .env
34
+ echo ""
35
+ echo "Successfully updated the .env file."
36
+ else
37
+ # Write a new .env file
38
+ cat <<EOF > .env
39
+ # Required for gas-fakes to use Application Default Credentials
40
+ GCP_PROJECT_ID="$gcp_project_id"
41
+ DRIVE_TEST_FILE_ID="$drive_test_file_id"
42
+
43
+ # This should generally be left as default for ADC
44
+ AC=default
45
+
46
+ # These are the scopes set by default - customize as needed
47
+ DEFAULT_SCOPES="$default_scopes"
48
+
49
+ # Add additional scopes here
50
+ EXTRA_SCOPES="$extra_scopes"
51
+ EOF
52
+ echo ""
53
+ echo "Successfully created the .env file."
54
+ fi
55
+
56
+ # --- Get gasfakes.json details ---
57
+ echo ""
58
+ echo "Next, let's configure your gasfakes.json file."
59
+ echo "This file informs gas-fakes about your local environment."
60
+
61
+ # Using default values as suggested by the repository
62
+ DEFAULT_MANIFEST="./appsscript.json"
63
+ DEFAULT_CLASP="./.clasp.json"
64
+ DEFAULT_CACHE="/tmp/gas-fakes/cache"
65
+ DEFAULT_PROPERTIES="/tmp/gas-fakes/properties"
66
+ DEFAULT_SCRIPT_ID=$(uuidgen) # A fake script ID if clasp file is not used
67
+
68
+ read -p "Enter the path to your manifest file (default: $DEFAULT_MANIFEST): " manifest_path
69
+ manifest_path=${manifest_path:-$DEFAULT_MANIFEST}
70
+
71
+ read -p "Enter the path to your clasp file (default: $DEFAULT_CLASP): " clasp_path
72
+ clasp_path=${clasp_path:-$DEFAULT_CLASP}
73
+
74
+ read -p "Enter a bound document ID if applicable (leave blank for none): " document_id
75
+ if [ -z "$document_id" ]; then
76
+ document_id="null"
77
+ else
78
+ document_id="\"$document_id\""
79
+ fi
80
+
81
+ read -p "Enter the local cache directory (default: $DEFAULT_CACHE): " cache_path
82
+ cache_path=${cache_path:-$DEFAULT_CACHE}
83
+
84
+ read -p "Enter the local properties directory (default: $DEFAULT_PROPERTIES): " properties_path
85
+ properties_path=${properties_path:-$DEFAULT_PROPERTIES}
86
+
87
+ read -p "Enter the script ID (default: a new random ID will be created): " script_id
88
+ script_id=${script_id:-$DEFAULT_SCRIPT_ID}
89
+
90
+ # --- Write gasfakes.json file ---
91
+ cat <<EOF > gasfakes.json
92
+ {
93
+ "manifest": "$manifest_path",
94
+ "clasp": "$clasp_path",
95
+ "documentId": $document_id,
96
+ "cache": "$cache_path",
97
+ "properties": "$properties_path",
98
+ "scriptId": "$script_id"
99
+ }
100
+ EOF
101
+
102
+ echo ""
103
+ echo "Successfully created the gasfakes.json file."
104
+
105
+ echo ""
106
+ echo "Setup complete! You can now run your gas-fakes project locally."
107
+ echo "Be sure to follow the remaining setup instructions in the gas-fakes repository."
package/package.json CHANGED
@@ -4,16 +4,18 @@
4
4
  },
5
5
  "dependencies": {
6
6
  "@mcpher/fake-gasenum": "^1.0.2",
7
+ "@mcpher/gas-fakes": "^1.0.14",
7
8
  "@mcpher/unit": "^1.1.11",
8
9
  "@sindresorhus/is": "^7.0.1",
9
10
  "archiver": "^7.0.1",
10
11
  "get-stream": "^9.0.1",
11
- "googleapis": "^150.0.1",
12
- "got": "^14.4.5",
12
+ "googleapis": "^157.0.0",
13
+ "got": "^14.4.7",
13
14
  "into-stream": "^8.0.1",
14
- "keyv": "^5.2.3",
15
- "keyv-file": "^5.1.1",
16
- "mime": "^4.0.6",
15
+ "is": "^3.3.2",
16
+ "keyv": "^5.5.0",
17
+ "keyv-file": "^5.1.3",
18
+ "mime": "^4.0.7",
17
19
  "sleep-synchronously": "^2.0.0",
18
20
  "subsume": "^4.0.0",
19
21
  "to-readable-stream": "^4.0.0",
@@ -45,13 +47,20 @@
45
47
  "testslides": "cp mainlocal.js main.js && node --env-file=.env ./test/testslides.js execute",
46
48
  "testdocsnext": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsnext.js execute",
47
49
  "testsheetstext": "cp mainlocal.js main.js && node --env-file=.env ./test/testsheetstext.js execute",
50
+ "testsheetsrange": "cp mainlocal.js main.js && node --env-file=.env ./test/testsheetsrange.js execute",
51
+ "testdocslistitems": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocslistitems.js execute",
52
+ "testdocsall": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsall.js",
53
+ "testdocsheaders": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsheaders.js execute",
54
+ "testdocsfooters": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsfooters.js execute",
55
+ "testdocsfootnotes": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsfootnotes.js execute",
56
+ "testdocsimages": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsimages.js execute",
48
57
  "pub": "cp mainlocal.js main.js && npm publish --access public"
49
58
  },
50
59
  "name": "@mcpher/gas-fakes",
51
- "version": "1.0.14",
60
+ "version": "1.0.16",
52
61
  "license": "MIT",
53
62
  "main": "main.js",
54
63
  "description": "A proof of concept implementation of Apps Script Environment on Node",
55
64
  "repository": "github:brucemcpherson/gas-fakes",
56
65
  "homepage": "https://ramblings.mcpher.com/a-proof-of-concept-implementation-of-apps-script-environment-on-node/"
57
- }
66
+ }
@@ -1,11 +1,15 @@
1
1
  import { google } from "googleapis";
2
2
  import { Auth } from '../../support/auth.js'
3
+ import { syncLog} from '../../support/workersync/synclogger.js'
3
4
 
4
- export const getApiClient = (auth) => {
5
- return google.docs({ version: 'v1', auth });
6
- }
5
+ let __client = null;
7
6
 
8
- export const getAuthedClient = () => {
7
+ export const getDocsApiClient = () => {
9
8
  const auth = Auth.getAuth()
10
- return getApiClient(auth)
11
- }
9
+ if (!__client) {
10
+ syncLog('Creating new Docs API client');
11
+ __client = google.docs({ version: 'v1', auth });
12
+ }
13
+ return __client;
14
+ }
15
+
@@ -2,14 +2,12 @@
2
2
  * Advanced sheets service
3
3
  */
4
4
  import { Proxies } from '../../support/proxies.js'
5
- import { advClassMaker, notYetImplemented } from '../../support/helpers.js'
6
- import { getAuthedClient } from './docapis.js'
5
+ import { advClassMaker } from '../../support/helpers.js'
7
6
  import { newFakeAdvDocuments } from './fakeadvdocuments.js'
8
7
  import { docsCacher } from '../../support/docscacher.js';
9
8
 
10
9
  class FakeAdvDocs {
11
10
  constructor() {
12
- this.client = Proxies.guard(getAuthedClient())
13
11
  this.__fakeObjectType = "Docs"
14
12
 
15
13
  const propLists = {