Google Apps Script ライブラリの変数・関数公開範囲

# 背景
Google Apps Scriptで作成したプロジェクトをライブラリ化した場合、何が公開されるのか、どうやって公開範囲を設定するのか。
調査と実験をした。

## 結論
* ライブラリ外に公開：
 * 関数
 * var で宣言した変数
 * properties explicitly set on the global object（要追加調査）
* ライブラリ外に非公開：
 * 末尾にアンダースコアを付けた関数
 * let で宣言した変数
 * const で宣言した定数

## 調査
[Libraries#Best practices - Google Apps Script][ref-LibraryScope]

> 2.If you want one or more methods of your script to not be visible (nor usable) to your library users, you can end the name of the method with an underscore. For example, myPrivateMethod_().

公開したくないメソッドは、メソッド名の最後にアンダースコア（_）をつける。

> 3.Only enumerable global properties are visible to library users. This includes function declarations, variables created outside a function with var, and properties explicitly set on the global object. For example, Object.defineProperty() with enumerable set to false creates a symbol you can use in your library, but this symbol isn't accessible by your users.

関数宣言、関数外にvarで宣言した変数、グローバルオブジェクトに意図的にセットしたプロパティ（properties explicitly set on the global object）
が、公開される。

properties explicitly set on the global object
は、JSをよく知らないのでなんのことかわからない。


## 実験
### 実験内容
#### ライブラリプロジェクト

```javascript:test.gs
var variable1 = 1;
let variable2 = 2;
const constant = 3;

var function1 = () => 4;
let function2 = () => 5;
const function3 = () => 6;
function function4() {
  return 7;
}
```

#### 使用者プロジェクト（ライブラリプロジェクトをLibというIDで使っている）

```javascript:test.gs
function myFunction() {
  console.log("variable1: " + Lib.variable1);   // -> variable1: 1
  console.log("variable2: " + Lib.variable2);   // -> variable2: undefined
  console.log("constant: "  + Lib.constant);    // -> constant: undefined
  console.log("function1: " + Lib.function1()); // function1: 4
  console.log("function2: " + Lib.function2()); // TypeError: Lib.function2 is not a function
  console.log("function3: " + Lib.function3()); // TypeError: Lib.function3 is not a function
  console.log("function4: " + Lib.function4()); // function4: 7
}
```

下記のようにすることで、エラーではなくなる（未定義となる）。

```javascript:lambdaCallTest.gs
  console.log("function2: " + Lib.function2);   // -> function2: undefined
  console.log("function3: " + Lib.function3);   // -> function3: undefined
```

つまり、未定義の参照（参照できていない）を関数として呼ぼうとしたのでエラーになった。
つまり、let, constで定義したものは、ライブラリ外から参照できない。

ちなみに、function2, function3は、content assistの候補には出てくる。
実行結果は上記の通りなので、Content assistのバグかな？（V8ランタイムのスコープに追従できていない）

##補足
ライブラリ内のファイル間は、letでもconstでも参照できる。

```javascript:test.gs
let variable2 = 2;
const constant = 3;

let function2 = () => 5;
const function3 = () => 6;
```
```javascript:test2.gs
function myFunction() {
  console.log("variable2: " + variable2);   // variable2: 2
  console.log("constant: " + constant);     // constant: 3
  console.log("function2: " + function2()); // function2: 5
  console.log("function3: " + function3()); // function3: 6
}
```

##蛇足
https://developers.google.com/apps-script/guides/v8-runtime?hl=en#features_of_the_v8_runtime
に書いてある、V8ランタイムで定義できるようになった関数でもやってみたが、let, constはライブラリ外からは参照不可（undefined）だった。

```javascript
function myFunction() {
  console.log("01: " + DeleteMail.normalFunction);
  console.log("02: " + DeleteMail.asyncFunction);
  console.log("03: " + DeleteMail.generatorFunction);
  console.log("04: " + DeleteMail.varFunction);
  console.log("05: " + DeleteMail.letFunction);
  console.log("06: " + DeleteMail.constFunction);
  console.log("07: " + DeleteMail.namedVarFunction);
  console.log("08: " + DeleteMail.namedLetFunction);
  console.log("09: " + DeleteMail.namedConstFunction);
  console.log("10: " + DeleteMail.varAsyncFunction);
  console.log("11: " + DeleteMail.letAsyncFunction);
  console.log("12: " + DeleteMail.constAsyncFunction);
  console.log("13: " + DeleteMail.namedVarAsyncFunction);
  console.log("14: " + DeleteMail.namedLetAsyncFunction);
  console.log("15: " + DeleteMail.namedConstAsyncFunction);
  console.log("16: " + DeleteMail.varGeneratorFunction);
  console.log("17: " + DeleteMail.letGeneratorFunction);
  console.log("18: " + DeleteMail.constGeneratorFunction);
  console.log("19: " + DeleteMail.namedVarGeneratorFunction);
  console.log("20: " + DeleteMail.namedLetGeneratorFunction);
  console.log("21: " + DeleteMail.namedConstGeneratorFunction);
  console.log("22: " + DeleteMail.varLambda);
  console.log("23: " + DeleteMail.letLambda);
  console.log("24: " + DeleteMail.constLambda);
  console.log("25: " + DeleteMail.varAsyncLambda);
  console.log("26: " + DeleteMail.letAsyncLambda);
  console.log("27: " + DeleteMail.constAsyncLambda);
}
```

# 参考
* [【Google Apps Script】ライブラリの作り方と使い方 - CG METHOD](https://www.cg-method.com/google-apps-script-library/)
* [V8 Runtime Overview - Google Apps Script](https://developers.google.com/apps-script/guides/v8-runtime?hl=en)
* [Libraries#Best practices - Google Apps Script][ref-LibraryScope]

[ref-LibraryScope]:https://developers.google.com/apps-script/guides/libraries#best_practices