apps-script-utils (Русский) 2.1.1 Help

Среда выполнения Apps Script

Библиотека одна, но её функции работают не в одних и тех же местах. От того, по какую сторону черты стоит функция, зависит, получится ли покрыть её модульным тестом и стоит ли она обращения к сервису.

Два рода функций

Независимые от среды функции — это обычный JavaScript. Они принимают значения, возвращают значения и никогда не лезут в глобальные объекты. К этому роду относится всё в lang, net, json, html, time и exception, а также те части appsscript, которые лишь преобразуют строки и простые объекты: разборщики нотации A1, конвертеры букв столбцов и сравнения GridRange.

Привязанные к сервисам функции сами обращаются к глобальному сервису. Они работают только внутри скрипта с выданными правами и в Node не работают вовсе. Сегодня это весь список:

Функция

К какому глобальному объекту обращается

isAdmin

Session.getActiveUser, AdminDirectory.Users

checkMultipleAccount

Session.getEffectiveUser

getSheetById

SpreadsheetApp.getActiveSpreadsheet, если таблица не передана

getSheetByIndex

SpreadsheetApp.getActiveSpreadsheet, если таблица не передана

highlightHtml

SpreadsheetApp.newTextStyle, SpreadsheetApp.newRichTextValue

convertRichTextToHtml

Utilities.formatString

Всё остальное в appsscript принимает объект сервиса аргументом: appendRows пишет в тот Sheet, который вы ему дали, а requireSheet разглядывает переданное значение, а не добывает его сам. Таким функциям живой объект сервиса нужен, чтобы принести пользу, но искать его они не идут — именно это и позволяет подменить их в тесте.

Пакетность на границе

Каждое обращение к сервису — это поход туда и обратно, и Apps Script засчитывает его в лимит времени выполнения. Помощники для записи существуют ровно поэтому: appendRows делает один вызов независимо от числа строк, а цикл с appendRow — по вызову на строку.

// Один вызов сервиса. appendRows(sheet, rows); // По вызову на строку; годится разве что для одной записи. for (const row of rows) { appendRow(sheet, row); }

То же рассуждение верно и для проверок. Проверяйте форму данных до того, как они дойдут до сервиса, а не после:

import { IllegalArgumentException, appendRows, isConsistent2DArray } from "apps-script-utils"; if (!isConsistent2DArray(rows)) { throw new IllegalArgumentException("every row must have the same number of columns"); } appendRows(sheet, rows);

Range.setValues() отвергает рваный массив, но сбой приходит от сервиса, не сообщая, какая строка виновата. Проверка заранее превращает это в ошибку, которой вы управляете.

Квоты

Apps Script следит за квотами на скрипт и на аккаунт: время выполнения, вызовы каждого сервиса, триггеры, запросы URL и прочее. Библиотека их не повышает и не считает — она лишь уменьшает число обращений. Два следствия, которые стоит держать в голове:

  • Функция, не зависящая от среды, не стоит ничего, кроме процессорного времени. Переносите проверки и преобразования на эту сторону черты везде, где можете.

  • Функция, привязанная к сервису, может упасть по причинам, не связанным с аргументами. Если isAdmin бросает AdminDirectoryException, это значит, что расширенный сервис Admin SDK не включён в проекте, а не что пользователь не администратор.

Действующие лимиты опубликованы в Quotas for Google Services.

Тестирование

Набор тестов работает на Vitest в Node, где глобальных объектов Apps Script нет вовсе. Поэтому деление и важно:

  • Независимые от среды функции покрыты модульными тестами напрямую. Их большинство в test/, импорт идёт через алиас @/.

  • Привязанные к сервисам — нет. Вызов в Node падает с ReferenceError на SpreadsheetApp или другом глобальном объекте, поэтому их проверяют вручную на настоящем проекте скрипта. Функции, которые просто принимают Sheet, стоят посередине: их можно прогнать с объектом-заглушкой той же формы, что и класс сервиса.

npm test # прогнать набор один раз npm run dev # режим наблюдения

Когда добавляете функцию, первый вопрос к её устройству такой: может ли она принимать объект сервиса параметром вместо того, чтобы добывать его? Если может — она становится тестируемой, а вызывающий код сохраняет контроль над числом обращений к сервису.

Как писать для обеих сторон

Библиотека рассчитана на среду V8. Две привычки держат код рабочим по обе стороны черты:

  • Принимайте объекты сервисов аргументами. appendRows(sheet, rows) работает всюду, откуда бы ни пришёл Sheet; функция, которая внутри зовёт SpreadsheetApp.getActiveSpreadsheet(), работает только в привязанном скрипте.

  • Отделяйте разбор от добычи. parseA1Notation — чистая работа со строками, она запускается в Node и потому покрыта тестами; getSheetById — тот же поиск, но выраженный через активную таблицу, и тестами не покрыт. Явная передача таблицы — getSheetById(id, spreadsheet) — возвращает его обратно за черту.

23 September 2026

Эта документация сгенерирована нейросетью (Claude) на основе исходного кода библиотеки.