@mcpher/gas-fakes 2.3.10 → 2.3.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.
Files changed (50) hide show
  1. package/README.md +14 -14
  2. package/gas-fakes.js +1 -0
  3. package/gf_agent/scripts/builder.js +26 -1
  4. package/package.json +1 -1
  5. package/src/cli/lib-manager.js +14 -4
  6. package/src/cli/setup.js +17 -4
  7. package/src/services/chartsapp/fakechartsapp.js +6 -1
  8. package/src/services/documentapp/elementhelpers.js +27 -0
  9. package/src/services/documentapp/fakeelement.js +8 -0
  10. package/src/services/documentapp/fakeparagraph.js +14 -0
  11. package/src/services/documentapp/faketext.js +174 -4
  12. package/src/services/driveapp/driveiterators.js +53 -8
  13. package/src/services/driveapp/fakedriveapp.js +49 -15
  14. package/src/services/driveapp/fakedrivefile.js +105 -0
  15. package/src/services/driveapp/fakedrivefolder.js +8 -0
  16. package/src/services/driveapp/fakedrivemeta.js +68 -16
  17. package/src/services/driveapp/fakefolderapp.js +19 -6
  18. package/src/services/enums/chartsenums.js +53 -20
  19. package/src/services/enums/driveenums.js +1 -0
  20. package/src/services/slidesapp/fakeautofit.js +23 -15
  21. package/src/services/slidesapp/fakecolorscheme.js +160 -0
  22. package/src/services/slidesapp/fakelayout.js +11 -1
  23. package/src/services/slidesapp/fakemaster.js +10 -0
  24. package/src/services/slidesapp/fakepresentation.js +27 -0
  25. package/src/services/slidesapp/fakeslide.js +9 -0
  26. package/src/services/slidesapp/faketextrange.js +6 -11
  27. package/src/services/spreadsheetapp/chartenummapping.js +15 -0
  28. package/src/services/spreadsheetapp/fakebooleancondition.js +119 -0
  29. package/src/services/spreadsheetapp/fakecellimage.js +42 -0
  30. package/src/services/spreadsheetapp/fakecellimagebuilder.js +59 -0
  31. package/src/services/spreadsheetapp/fakeconditionalformatrule.js +55 -0
  32. package/src/services/spreadsheetapp/fakeconditionalformatrulebuilder.js +330 -0
  33. package/src/services/spreadsheetapp/fakedevelopermetadata.js +32 -4
  34. package/src/services/spreadsheetapp/fakedevelopermetadatalocation.js +27 -5
  35. package/src/services/spreadsheetapp/fakeembeddedchartbuilder.js +155 -21
  36. package/src/services/spreadsheetapp/fakegradientcondition.js +71 -0
  37. package/src/services/spreadsheetapp/fakesheet.js +63 -0
  38. package/src/services/spreadsheetapp/fakesheetrange.js +12 -1
  39. package/src/services/spreadsheetapp/fakespreadsheet.js +30 -11
  40. package/src/services/spreadsheetapp/fakespreadsheetapp.js +21 -3
  41. package/src/services/urlfetchapp/app.js +33 -1
  42. package/src/support/fileiterators.js +3 -1
  43. package/src/support/filesharers.js +7 -3
  44. package/src/support/peeker.js +8 -2
  45. package/src/support/sheetutils.js +1 -0
  46. package/src/support/sxdrive.js +26 -15
  47. package/src/support/syncit.js +4 -6
  48. package/src/support/workersync/synchronizer.js +24 -4
  49. package/src/support/workersync/worker.js +13 -2
  50. package/summarize_advanced.js +0 -69
@@ -0,0 +1,160 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeColor } from '../common/fakecolor.js';
3
+ import { newFakeColorBuilder } from '../common/fakecolorbuilder.js';
4
+ import { ThemeColorType } from '../enums/slidesenums.js';
5
+ import { signatureArgs } from '../../support/helpers.js';
6
+
7
+ export const newFakeColorScheme = (...args) => {
8
+ return Proxies.guard(new FakeColorScheme(...args));
9
+ };
10
+
11
+ /**
12
+ * @class FakeColorScheme
13
+ */
14
+ export class FakeColorScheme {
15
+ constructor(parent) {
16
+ this.__parent = parent;
17
+ }
18
+
19
+ get __masterPage() {
20
+ const parent = this.__parent;
21
+ const type = parent.toString();
22
+
23
+ if (type === 'Master') return parent;
24
+ if (type === 'Slide' || type === 'Layout') {
25
+ // Find the master for this slide/layout
26
+ if (type === 'Slide') {
27
+ const layout = parent.getLayout();
28
+ return layout ? layout.getMaster() : null;
29
+ } else {
30
+ return parent.getMaster();
31
+ }
32
+ }
33
+ if (type === 'Presentation') {
34
+ // Use the first master of the presentation
35
+ const masters = parent.getMasters();
36
+ if (masters.length > 0) {
37
+ return masters[0];
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+
43
+ get __resource() {
44
+ const master = this.__masterPage;
45
+ return master?.__resource?.pageProperties?.colorScheme || { colors: [] };
46
+ }
47
+
48
+ /**
49
+ * getConcreteColor(themeColorType) https://developers.google.com/apps-script/reference/slides/color-scheme#getconcretecolorthemecolortype
50
+ * @param {ThemeColorType} themeColorType
51
+ * @returns {FakeColor}
52
+ */
53
+ getConcreteColor(themeColorType) {
54
+ const { nargs, matchThrow } = signatureArgs(arguments, "ColorScheme.getConcreteColor");
55
+ if (nargs !== 1) matchThrow();
56
+
57
+ const colors = this.__resource.colors || [];
58
+ const typeStr = themeColorType.toString();
59
+ const pair = colors.find(c => c.type === typeStr);
60
+
61
+ if (pair && pair.color) {
62
+ return makeColorFromApiForSlides(pair.color);
63
+ }
64
+
65
+ return null;
66
+ }
67
+
68
+ /**
69
+ * getThemeColors() https://developers.google.com/apps-script/reference/slides/color-scheme#getthemecolors
70
+ * @returns {ThemeColorType[]}
71
+ */
72
+ getThemeColors() {
73
+ return Object.keys(ThemeColorType)
74
+ .filter(k => k !== 'UNSUPPORTED')
75
+ .map(k => ThemeColorType[k]);
76
+ }
77
+
78
+ /**
79
+ * setConcreteColor(themeColorType, color) https://developers.google.com/apps-script/reference/slides/color-scheme#setconcretecolorthemecolortype,color
80
+ * @param {ThemeColorType} themeColorType
81
+ * @param {FakeColor} color
82
+ * @returns {FakeColorScheme} self
83
+ */
84
+ setConcreteColor(themeColorType, color) {
85
+ const { nargs, matchThrow } = signatureArgs(arguments, "ColorScheme.setConcreteColor");
86
+ if (nargs !== 2) matchThrow();
87
+
88
+ const master = this.__masterPage;
89
+ if (!master) throw new Error('Could not find master page for color scheme');
90
+
91
+ const presentationId = master.__presentation.getId();
92
+ const typeStr = themeColorType.toString();
93
+
94
+ // The API requires ALL theme colors to be present when updating the color scheme.
95
+ // So we fetch the current colors, update the one we want, and send them all back.
96
+ const currentResource = this.__resource;
97
+ const colors = [...(currentResource.colors || [])];
98
+
99
+ // Convert the new Color to API format
100
+ const apiColor = {};
101
+ if (color.getColorType().toString() === 'RGB') {
102
+ const rgb = color.asRgbColor();
103
+ apiColor.red = rgb.getRed() / 255;
104
+ apiColor.green = rgb.getGreen() / 255;
105
+ apiColor.blue = rgb.getBlue() / 255;
106
+ } else if (color.getColorType().toString() === 'THEME') {
107
+ apiColor.themeColor = color.asThemeColor().getThemeColorType().toString();
108
+ }
109
+
110
+ // Find and update or add the color pair
111
+ const index = colors.findIndex(c => c.type === typeStr);
112
+ if (index !== -1) {
113
+ colors[index] = { type: typeStr, color: apiColor };
114
+ } else {
115
+ colors.push({ type: typeStr, color: apiColor });
116
+ }
117
+
118
+ // Ensure we have exactly the right set of colors if possible?
119
+ // The API error said "must have 12 theme colors pairs".
120
+ // Usually these are the standard 12 types.
121
+
122
+ const requests = [{
123
+ updatePageProperties: {
124
+ objectId: master.getObjectId(),
125
+ pageProperties: {
126
+ colorScheme: {
127
+ colors: colors
128
+ }
129
+ },
130
+ fields: 'colorScheme'
131
+ }
132
+ }];
133
+
134
+ Slides.Presentations.batchUpdate(requests, presentationId);
135
+ return this;
136
+ }
137
+
138
+ toString() {
139
+ return 'ColorScheme';
140
+ }
141
+ }
142
+
143
+ // Helper to avoid circular dependency or reusing the spreadsheet-specific one if it differs
144
+ const makeColorFromApiForSlides = (apiColor) => {
145
+ const builder = newFakeColorBuilder();
146
+ const rgb = apiColor.rgbColor || (apiColor.red !== undefined ? apiColor : null);
147
+
148
+ if (rgb) {
149
+ const hex = '#' + [rgb.red, rgb.green, rgb.blue].map(v => {
150
+ const val = Math.round((v || 0) * 255);
151
+ const hex = val.toString(16);
152
+ return hex.length === 1 ? '0' + hex : hex;
153
+ }).join('');
154
+ builder.setRgbColor(hex);
155
+ } else if (apiColor.themeColor) {
156
+ const tc = apiColor.themeColor;
157
+ builder.setThemeColor(ThemeColorType[tc]);
158
+ }
159
+ return builder.build();
160
+ };
@@ -1,5 +1,6 @@
1
1
  import { Proxies } from '../../support/proxies.js';
2
2
  import { newFakeMaster } from './fakemaster.js';
3
+ import { newFakeColorScheme } from './fakecolorscheme.js';
3
4
 
4
5
  export const newFakeLayout = (...args) => {
5
6
  return Proxies.guard(new FakeLayout(...args));
@@ -21,7 +22,7 @@ export class FakeLayout {
21
22
  }
22
23
 
23
24
  getMaster() {
24
- const masterId = this.__resource.masterObjectId;
25
+ const masterId = this.__resource.layoutProperties?.masterObjectId;
25
26
  if (!masterId) return null;
26
27
 
27
28
  const presentationResource = this.__presentation.__resource;
@@ -32,6 +33,15 @@ export class FakeLayout {
32
33
  getObjectId() {
33
34
  return this.__id;
34
35
  }
36
+
37
+ /**
38
+ * Gets the color scheme of the layout.
39
+ * @returns {FakeColorScheme} The color scheme.
40
+ */
41
+ getColorScheme() {
42
+ return newFakeColorScheme(this);
43
+ }
44
+
35
45
  toString() {
36
46
  return 'Layout';
37
47
  }
@@ -1,4 +1,5 @@
1
1
  import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeColorScheme } from './fakecolorscheme.js';
2
3
 
3
4
  export const newFakeMaster = (...args) => {
4
5
  return Proxies.guard(new FakeMaster(...args));
@@ -22,6 +23,15 @@ export class FakeMaster {
22
23
  getObjectId() {
23
24
  return this.__id;
24
25
  }
26
+
27
+ /**
28
+ * Gets the color scheme of the master.
29
+ * @returns {FakeColorScheme} The color scheme.
30
+ */
31
+ getColorScheme() {
32
+ return newFakeColorScheme(this);
33
+ }
34
+
25
35
  toString() {
26
36
  return 'Master';
27
37
  }
@@ -1,5 +1,7 @@
1
1
  import { Proxies } from '../../support/proxies.js';
2
2
  import { newFakeSlide } from './fakeslide.js';
3
+ import { newFakeMaster } from './fakemaster.js';
4
+ import { newFakeColorScheme } from './fakecolorscheme.js';
3
5
 
4
6
  export const newFakePresentation = (...args) => {
5
7
  return Proxies.guard(new FakePresentation(...args));
@@ -50,6 +52,31 @@ export class FakePresentation {
50
52
  return `https://docs.google.com/presentation/d/${this.getId()}/edit`;
51
53
  }
52
54
 
55
+ /**
56
+ * Gets the color scheme of the presentation.
57
+ * @returns {FakeColorScheme} The color scheme.
58
+ */
59
+ getColorScheme() {
60
+ return newFakeColorScheme(this);
61
+ }
62
+
63
+ /**
64
+ * Gets the masters in the presentation.
65
+ * @returns {FakeMaster[]} The masters.
66
+ */
67
+ getMasters() {
68
+ return (this.__resource.masters || []).map(m => newFakeMaster(m, this));
69
+ }
70
+
71
+ /**
72
+ * Gets a master by its ID.
73
+ * @param {string} id The master ID.
74
+ * @returns {FakeMaster | null} The master, or null if not found.
75
+ */
76
+ getMasterById(id) {
77
+ return this.getMasters().find(m => m.getObjectId() === id) || null;
78
+ }
79
+
53
80
  /**
54
81
  * Gets the slides in the presentation.
55
82
  * @returns {FakeSlide[]} The slides.
@@ -4,6 +4,7 @@ import { newFakeLayout } from './fakelayout.js';
4
4
  import { newFakeMaster } from './fakemaster.js';
5
5
  import { newFakePageElement } from './fakepageelement.js';
6
6
  import { newFakePageBackground } from './fakepagebackground.js';
7
+ import { newFakeColorScheme } from './fakecolorscheme.js';
7
8
  import { asSpecificPageElement } from './pageelementfactory.js';
8
9
 
9
10
  export const newFakeSlide = (...args) => {
@@ -86,6 +87,14 @@ export class FakeSlide {
86
87
  return background ? newFakePageBackground(this) : null;
87
88
  }
88
89
 
90
+ /**
91
+ * Gets the color scheme of the slide.
92
+ * @returns {FakeColorScheme} The color scheme.
93
+ */
94
+ getColorScheme() {
95
+ return newFakeColorScheme(this);
96
+ }
97
+
89
98
  /**
90
99
  * Gets the list of tables on the slide.
91
100
  * @returns {FakeTable[]} The tables.
@@ -17,10 +17,11 @@ export class FakeTextRange {
17
17
  }
18
18
 
19
19
  get __resource() {
20
- if (!this.__shape.__resource.shape.text) {
21
- this.__shape.__resource.shape.text = {};
20
+ const shapeResource = this.__shape.__resource;
21
+ if (shapeResource && shapeResource.shape && shapeResource.shape.text) {
22
+ return shapeResource.shape.text;
22
23
  }
23
- return this.__shape.__resource.shape.text;
24
+ return {};
24
25
  }
25
26
 
26
27
  getStartIndex() {
@@ -42,7 +43,7 @@ export class FakeTextRange {
42
43
  * @returns {string} The text.
43
44
  */
44
45
  asString() {
45
- const textElements = this.__resource.textElements || [];
46
+ const textElements = this.__resource?.textElements || [];
46
47
  let fullText = textElements.map(te => {
47
48
  if (te.textRun) return te.textRun.content;
48
49
  if (te.autoText) return te.autoText.content || '[AutoText]'; // Use placeholder
@@ -114,12 +115,6 @@ export class FakeTextRange {
114
115
 
115
116
  if (requests.length > 0) {
116
117
  Slides.Presentations.batchUpdate(requests, presentationId);
117
-
118
- // REST API documentation: "The field is automatically set to NONE if a request is made that might affect text fitting within its bounding text box."
119
- if (!this.__resource.autoFit) {
120
- this.__resource.autoFit = {};
121
- }
122
- this.__resource.autoFit.autofitType = AutofitType.NONE;
123
118
  }
124
119
 
125
120
  return this;
@@ -176,7 +171,7 @@ export class FakeTextRange {
176
171
  * @returns {FakeAutoText[]} The auto texts.
177
172
  */
178
173
  getAutoTexts() {
179
- const textElements = this.__resource.textElements || [];
174
+ const textElements = this.__resource?.textElements || [];
180
175
  const autoTexts = [];
181
176
  let charIndex = 0;
182
177
  let autoTextIndex = 0;
@@ -0,0 +1,15 @@
1
+ export const ChartEnumMapping = {
2
+ Position: {
3
+ BOTTOM: "BOTTOM_LEGEND",
4
+ TOP: "TOP_LEGEND",
5
+ LEFT: "LEFT_LEGEND",
6
+ RIGHT: "RIGHT_LEGEND",
7
+ NONE: "NO_LEGEND",
8
+ },
9
+ ChartHiddenDimensionStrategy: {
10
+ IGNORE_BOTH: "SKIP_HIDDEN_ROWS_AND_COLUMNS",
11
+ IGNORE_ROWS: "SKIP_HIDDEN_ROWS",
12
+ IGNORE_COLUMNS: "SKIP_HIDDEN_COLUMNS",
13
+ SHOW_BOTH: "SHOW_ALL",
14
+ }
15
+ };
@@ -0,0 +1,119 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { BooleanCriteria } from '../enums/sheetsenums.js';
3
+ import { newFakeColor } from '../common/fakecolor.js';
4
+ import { makeColorFromApi } from '../common/fakecolorbuilder.js';
5
+
6
+ export const newFakeBooleanCondition = (...args) => {
7
+ return Proxies.guard(new FakeBooleanCondition(...args));
8
+ };
9
+
10
+ export class FakeBooleanCondition {
11
+ constructor(apiCondition, format) {
12
+ this.__apiCondition = apiCondition;
13
+ this.__format = format || {};
14
+ }
15
+
16
+ getBackgroundObject() {
17
+ if (this.__format.backgroundColorStyle) {
18
+ return makeColorFromApi(this.__format.backgroundColorStyle);
19
+ }
20
+ if (this.__format.backgroundColor) {
21
+ return makeColorFromApi({ rgbColor: this.__format.backgroundColor });
22
+ }
23
+ return null;
24
+ }
25
+
26
+ getBold() {
27
+ return this.__format.textFormat?.bold ?? null;
28
+ }
29
+
30
+ getCriteriaType() {
31
+ // The API uses slightly different strings than the GAS enum for many rules
32
+ const map = {
33
+ 'BLANK': 'CELL_EMPTY',
34
+ 'NOT_BLANK': 'CELL_NOT_EMPTY',
35
+ 'DATE_AFTER': 'DATE_AFTER',
36
+ 'DATE_BEFORE': 'DATE_BEFORE',
37
+ 'DATE_EQ': 'DATE_EQUAL_TO',
38
+ 'DATE_NOT_EQ': 'DATE_NOT_EQUAL_TO',
39
+ 'DATE_AFTER_RELATIVE': 'DATE_AFTER_RELATIVE',
40
+ 'DATE_BEFORE_RELATIVE': 'DATE_BEFORE_RELATIVE',
41
+ 'DATE_EQUAL_TO_RELATIVE': 'DATE_EQUAL_TO_RELATIVE',
42
+ 'DATE_EQ_RELATIVE': 'DATE_EQUAL_TO_RELATIVE',
43
+ 'NUMBER_BETWEEN': 'NUMBER_BETWEEN',
44
+ 'NUMBER_NOT_BETWEEN': 'NUMBER_NOT_BETWEEN',
45
+ 'NUMBER_EQ': 'NUMBER_EQUAL_TO',
46
+ 'NUMBER_NOT_EQ': 'NUMBER_NOT_EQUAL_TO',
47
+ 'NUMBER_GREATER': 'NUMBER_GREATER_THAN',
48
+ 'NUMBER_GREATER_THAN_EQ': 'NUMBER_GREATER_THAN_OR_EQUAL_TO',
49
+ 'NUMBER_LESS': 'NUMBER_LESS_THAN',
50
+ 'NUMBER_LESS_THAN_EQ': 'NUMBER_LESS_THAN_OR_EQUAL_TO',
51
+ 'TEXT_CONTAINS': 'TEXT_CONTAINS',
52
+ 'TEXT_NOT_CONTAINS': 'TEXT_DOES_NOT_CONTAIN',
53
+ 'TEXT_EQ': 'TEXT_EQUAL_TO',
54
+ 'TEXT_NOT_EQ': 'TEXT_NOT_EQUAL_TO',
55
+ 'TEXT_STARTS_WITH': 'TEXT_STARTS_WITH',
56
+ 'TEXT_ENDS_WITH': 'TEXT_ENDS_WITH',
57
+ 'CUSTOM_FORMULA': 'CUSTOM_FORMULA'
58
+ };
59
+
60
+ // If the API value contains RELATIVE properties it should probably be resolved to the _RELATIVE equivalents
61
+ // However the API 'type' doesn't usually distinguish between DATE_EQ and DATE_EQUAL_TO_RELATIVE at the root level,
62
+ // they are often just DATE_EQ and the value object specifies if it's relative.
63
+ // Let's infer if it's relative.
64
+ let type = this.__apiCondition.type;
65
+ if (type && type.startsWith('DATE_')) {
66
+ const isRelative = this.__apiCondition.values && this.__apiCondition.values.some(v => v.relativeDate !== undefined);
67
+ if (isRelative && !type.endsWith('_RELATIVE')) {
68
+ type += '_RELATIVE';
69
+ }
70
+ }
71
+
72
+ const enumKey = map[type] || type;
73
+
74
+ // Return the Enum if available
75
+ if (BooleanCriteria[enumKey]) {
76
+ return BooleanCriteria[enumKey];
77
+ }
78
+
79
+ return enumKey || null;
80
+ }
81
+
82
+ getCriteriaValues() {
83
+ if (!this.__apiCondition.values) return [];
84
+
85
+ // API condition values are typically { userEnteredValue: 'string' } or { relativeDate: 'TODAY' }
86
+ return this.__apiCondition.values.map(v => {
87
+ if (v.userEnteredValue !== undefined) return v.userEnteredValue;
88
+ // In Apps Script, RelativeDate enum values are typically returned as strings matching the enum
89
+ if (v.relativeDate !== undefined) return SpreadsheetApp.RelativeDate[v.relativeDate] || v.relativeDate;
90
+ return null;
91
+ });
92
+ }
93
+
94
+ getFontColorObject() {
95
+ if (this.__format.textFormat?.foregroundColorStyle) {
96
+ return makeColorFromApi(this.__format.textFormat.foregroundColorStyle);
97
+ }
98
+ if (this.__format.textFormat?.foregroundColor) {
99
+ return makeColorFromApi({ rgbColor: this.__format.textFormat.foregroundColor });
100
+ }
101
+ return null;
102
+ }
103
+
104
+ getItalic() {
105
+ return this.__format.textFormat?.italic ?? null;
106
+ }
107
+
108
+ getStrikethrough() {
109
+ return this.__format.textFormat?.strikethrough ?? null;
110
+ }
111
+
112
+ getUnderline() {
113
+ return this.__format.textFormat?.underline ?? null;
114
+ }
115
+
116
+ toString() {
117
+ return 'BooleanCondition';
118
+ }
119
+ }
@@ -0,0 +1,42 @@
1
+ import { Proxies } from "../../support/proxies.js";
2
+ import { newFakeCellImageBuilder } from "./fakecellimagebuilder.js";
3
+
4
+ /**
5
+ * Fake CellImage
6
+ * @class FakeCellImage
7
+ */
8
+ export class FakeCellImage {
9
+ constructor(properties) {
10
+ this._properties = properties || {};
11
+ }
12
+
13
+ getAltTextDescription() {
14
+ return this._properties.altTextDescription || null;
15
+ }
16
+
17
+ getAltTextTitle() {
18
+ return this._properties.altTextTitle || null;
19
+ }
20
+
21
+ getContentUrl() {
22
+ const url = this._properties.sourceUrl || null;
23
+ if (url && !url.includes('googleusercontent.com')) {
24
+ throw new Error('Unexpected error while getting the method or property getContentUrl on object SpreadsheetApp.CellImage.');
25
+ }
26
+ return url;
27
+ }
28
+
29
+ toBuilder() {
30
+ const builder = newFakeCellImageBuilder();
31
+ if (this._properties.sourceUrl) builder.setSourceUrl(this._properties.sourceUrl);
32
+ if (this._properties.altTextTitle) builder.setAltTextTitle(this._properties.altTextTitle);
33
+ if (this._properties.altTextDescription) builder.setAltTextDescription(this._properties.altTextDescription);
34
+ return builder;
35
+ }
36
+
37
+ toString() {
38
+ return 'CellImage';
39
+ }
40
+ }
41
+
42
+ export const newFakeCellImage = (...args) => Proxies.guard(new FakeCellImage(...args));
@@ -0,0 +1,59 @@
1
+ import { Proxies } from "../../support/proxies.js";
2
+ import { newFakeCellImage } from "./fakecellimage.js";
3
+
4
+ /**
5
+ * Fake CellImageBuilder
6
+ * @class FakeCellImageBuilder
7
+ */
8
+ export class FakeCellImageBuilder {
9
+ constructor() {
10
+ this._properties = {};
11
+ }
12
+
13
+ build() {
14
+ return newFakeCellImage(this._properties);
15
+ }
16
+
17
+ getAltTextDescription() {
18
+ return this._properties.altTextDescription || null;
19
+ }
20
+
21
+ getAltTextTitle() {
22
+ return this._properties.altTextTitle || null;
23
+ }
24
+
25
+ getContentUrl() {
26
+ const url = this._properties.sourceUrl || null;
27
+ if (url && !url.includes('googleusercontent.com')) {
28
+ throw new Error('Unexpected error while getting the method or property getContentUrl on object SpreadsheetApp.CellImageBuilder.');
29
+ }
30
+ return url;
31
+ }
32
+
33
+ setAltTextDescription(description) {
34
+ this._properties.altTextDescription = description;
35
+ return this;
36
+ }
37
+
38
+ setAltTextTitle(title) {
39
+ this._properties.altTextTitle = title;
40
+ return this;
41
+ }
42
+
43
+ setSourceUrl(url) {
44
+ this._properties.sourceUrl = url;
45
+ return this;
46
+ }
47
+
48
+ toBuilder() {
49
+ const builder = newFakeCellImageBuilder();
50
+ builder._properties = { ...this._properties };
51
+ return builder;
52
+ }
53
+
54
+ toString() {
55
+ return 'CellImageBuilder';
56
+ }
57
+ }
58
+
59
+ export const newFakeCellImageBuilder = (...args) => Proxies.guard(new FakeCellImageBuilder(...args));
@@ -0,0 +1,55 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeBooleanCondition } from './fakebooleancondition.js';
3
+ import { newFakeGradientCondition } from './fakegradientcondition.js';
4
+ import { newFakeSheetRange } from './fakesheetrange.js';
5
+ import { newFakeConditionalFormatRuleBuilder } from './fakeconditionalformatrulebuilder.js';
6
+
7
+ export const newFakeConditionalFormatRule = (...args) => {
8
+ return Proxies.guard(new FakeConditionalFormatRule(...args));
9
+ };
10
+
11
+ export class FakeConditionalFormatRule {
12
+ constructor(apiRule, sheet) {
13
+ this.__apiRule = apiRule;
14
+ this.__sheet = sheet;
15
+ }
16
+
17
+ copy() {
18
+ // Builder takes spreadsheet. Sheet gives us spreadsheet via getParent()
19
+ return newFakeConditionalFormatRuleBuilder(this.__apiRule, this.__sheet.getParent());
20
+ }
21
+
22
+ getBooleanCondition() {
23
+ if (!this.__apiRule.booleanRule) return null;
24
+ return newFakeBooleanCondition(
25
+ this.__apiRule.booleanRule.condition,
26
+ this.__apiRule.booleanRule.format
27
+ );
28
+ }
29
+
30
+ getGradientCondition() {
31
+ if (!this.__apiRule.gradientRule) return null;
32
+ return newFakeGradientCondition(this.__apiRule.gradientRule);
33
+ }
34
+
35
+ getRanges() {
36
+ if (!this.__apiRule.ranges) return [];
37
+ return this.__apiRule.ranges.map(gridRange => {
38
+ const sheetId = gridRange.sheetId;
39
+ let sheet = this.__sheet; // Default to the sheet this rule was fetched from
40
+ if (sheetId !== undefined && sheet.getSheetId() !== sheetId) {
41
+ sheet = this.__sheet.getParent().getSheets().find(s => s.getSheetId() === sheetId);
42
+ }
43
+
44
+ if (!sheet) return null;
45
+ return newFakeSheetRange(
46
+ gridRange,
47
+ sheet
48
+ );
49
+ }).filter(Boolean);
50
+ }
51
+
52
+ toString() {
53
+ return 'ConditionalFormatRule';
54
+ }
55
+ }